import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:focusflow_shared/focusflow_shared.dart'; import '../../../../core/network/api_client.dart'; import '../../../../main.dart'; // ── Events ───────────────────────────────────────────────────────── sealed class StreakEvent extends Equatable { const StreakEvent(); @override List get props => []; } class StreaksLoaded extends StreakEvent { const StreaksLoaded(); } class StreakCompleted extends StreakEvent { final String id; const StreakCompleted(this.id); @override List get props => [id]; } class StreakForgiven extends StreakEvent { final String id; const StreakForgiven(this.id); @override List get props => [id]; } class StreakFrozen extends StreakEvent { final String id; final DateTime until; const StreakFrozen(this.id, this.until); @override List get props => [id, until]; } // ── States ───────────────────────────────────────────────────────── sealed class StreakState extends Equatable { const StreakState(); @override List get props => []; } class StreakInitial extends StreakState {} class StreakLoading extends StreakState {} class StreakLoaded extends StreakState { final List streaks; const StreakLoaded(this.streaks); @override List get props => [streaks]; } class StreakError extends StreakState { final String message; const StreakError(this.message); @override List get props => [message]; } // ── BLoC ─────────────────────────────────────────────────────────── class StreakBloc extends Bloc { final ApiClient _api = getIt(); StreakBloc() : super(StreakInitial()) { on(_onLoaded); on(_onCompleted); on(_onForgiven); on(_onFrozen); } Future _onLoaded(StreaksLoaded event, Emitter emit) async { emit(StreakLoading()); try { final response = await _api.fetchStreaks(); final data = response.data; if (data != null && data['status'] == 'success') { final items = (data['data'] as List) .map((e) => Streak.fromJson(e as Map)) .toList(); emit(StreakLoaded(items)); } else { emit(const StreakError('Could not load streaks.')); } } catch (_) { emit(const StreakError('Something went wrong loading streaks.')); } } Future _onCompleted(StreakCompleted event, Emitter emit) async { try { await _api.completeStreak(event.id); add(const StreaksLoaded()); } catch (_) { emit(const StreakError('Could not complete streak entry.')); } } Future _onForgiven(StreakForgiven event, Emitter emit) async { try { await _api.forgiveStreak(event.id); add(const StreaksLoaded()); } catch (_) { emit(const StreakError('Could not forgive streak.')); } } Future _onFrozen(StreakFrozen event, Emitter emit) async { // TODO: API call to freeze streak until `event.until`. add(const StreaksLoaded()); } }