Initial scaffold: FocusFlow ADHD Task Manager Flutter app
BLoC/Cubit state management, ADHD-friendly theme (calming teal, no red), GetIt DI, GoRouter navigation. Screens: task dashboard, focus mode, task create/detail, streaks, time perception, settings, onboarding, auth. Custom widgets: TaskCard, RewardPopup, StreakRing, GentleNudgeCard. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
84
lib/features/tasks/presentation/bloc/next_task_cubit.dart
Normal file
84
lib/features/tasks/presentation/bloc/next_task_cubit.dart
Normal file
@@ -0,0 +1,84 @@
|
||||
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';
|
||||
|
||||
// ── States ─────────────────────────────────────────────────────────
|
||||
|
||||
sealed class NextTaskState extends Equatable {
|
||||
const NextTaskState();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class NextTaskLoading extends NextTaskState {}
|
||||
|
||||
class NextTaskLoaded extends NextTaskState {
|
||||
final Task task;
|
||||
const NextTaskLoaded(this.task);
|
||||
@override
|
||||
List<Object?> get props => [task];
|
||||
}
|
||||
|
||||
class NextTaskEmpty extends NextTaskState {}
|
||||
|
||||
class NextTaskError extends NextTaskState {
|
||||
final String message;
|
||||
const NextTaskError(this.message);
|
||||
@override
|
||||
List<Object?> get props => [message];
|
||||
}
|
||||
|
||||
// ── Cubit ──────────────────────────────────────────────────────────
|
||||
|
||||
/// Simple cubit for focus mode: "just do the next thing."
|
||||
///
|
||||
/// Loads the single highest-priority task from the API.
|
||||
class NextTaskCubit extends Cubit<NextTaskState> {
|
||||
final ApiClient _api = getIt<ApiClient>();
|
||||
|
||||
NextTaskCubit() : super(NextTaskLoading());
|
||||
|
||||
/// Fetch the next recommended task.
|
||||
Future<void> loadNext() async {
|
||||
emit(NextTaskLoading());
|
||||
try {
|
||||
final response = await _api.fetchNextTask();
|
||||
final data = response.data;
|
||||
if (data != null && data['status'] == 'success' && data['data'] != null) {
|
||||
final task = Task.fromJson(data['data'] as Map<String, dynamic>);
|
||||
emit(NextTaskLoaded(task));
|
||||
} else {
|
||||
emit(NextTaskEmpty());
|
||||
}
|
||||
} catch (_) {
|
||||
emit(const NextTaskError('Could not load your next task.'));
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark the current task as done, then load the next one.
|
||||
Future<void> complete() async {
|
||||
final current = state;
|
||||
if (current is! NextTaskLoaded) return;
|
||||
try {
|
||||
await _api.completeTask(current.task.id);
|
||||
} catch (_) {
|
||||
// Best-effort — still load next.
|
||||
}
|
||||
await loadNext();
|
||||
}
|
||||
|
||||
/// Skip the current task, then load the next one.
|
||||
Future<void> skip() async {
|
||||
final current = state;
|
||||
if (current is! NextTaskLoaded) return;
|
||||
try {
|
||||
await _api.skipTask(current.task.id);
|
||||
} catch (_) {
|
||||
// Best-effort.
|
||||
}
|
||||
await loadNext();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user