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>
124 lines
4.8 KiB
Dart
124 lines
4.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import '../core/network/interceptors/auth_interceptor.dart';
|
|
import '../features/auth/presentation/screens/login_screen.dart';
|
|
import '../features/auth/presentation/screens/signup_screen.dart';
|
|
import '../features/body_doubling/presentation/screens/rooms_screen.dart';
|
|
import '../features/settings/presentation/screens/settings_screen.dart';
|
|
import '../features/streaks/presentation/screens/streaks_screen.dart';
|
|
import '../features/tasks/presentation/screens/create_task_screen.dart';
|
|
import '../features/tasks/presentation/screens/focus_mode_screen.dart';
|
|
import '../features/tasks/presentation/screens/onboarding_screen.dart';
|
|
import '../features/tasks/presentation/screens/task_dashboard_screen.dart';
|
|
import '../features/tasks/presentation/screens/task_detail_screen.dart';
|
|
import '../features/time_perception/presentation/screens/time_dashboard_screen.dart';
|
|
|
|
/// Application router using GoRouter.
|
|
///
|
|
/// Auth redirect: unauthenticated users are sent to /login except
|
|
/// when they are already on /login, /signup, or /onboarding.
|
|
class AppRouter {
|
|
AppRouter._();
|
|
|
|
static final _rootNavigatorKey = GlobalKey<NavigatorState>();
|
|
|
|
static final GoRouter router = GoRouter(
|
|
navigatorKey: _rootNavigatorKey,
|
|
initialLocation: '/',
|
|
redirect: _authRedirect,
|
|
routes: [
|
|
// ── Home / Task Dashboard ────────────────────────────────────
|
|
GoRoute(
|
|
path: '/',
|
|
name: 'home',
|
|
builder: (context, state) => const TaskDashboardScreen(),
|
|
),
|
|
|
|
// ── Focus mode — "just do the next thing" ───────────────────
|
|
GoRoute(
|
|
path: '/focus',
|
|
name: 'focus',
|
|
builder: (context, state) => const FocusModeScreen(),
|
|
),
|
|
|
|
// ── Auth ─────────────────────────────────────────────────────
|
|
GoRoute(
|
|
path: '/login',
|
|
name: 'login',
|
|
builder: (context, state) => const LoginScreen(),
|
|
),
|
|
GoRoute(
|
|
path: '/signup',
|
|
name: 'signup',
|
|
builder: (context, state) => const SignupScreen(),
|
|
),
|
|
|
|
// ── Task detail ──────────────────────────────────────────────
|
|
GoRoute(
|
|
path: '/task/:id',
|
|
name: 'taskDetail',
|
|
builder: (context, state) => TaskDetailScreen(
|
|
taskId: state.pathParameters['id']!,
|
|
),
|
|
),
|
|
|
|
// ── Create task ──────────────────────────────────────────────
|
|
GoRoute(
|
|
path: '/task-create',
|
|
name: 'createTask',
|
|
builder: (context, state) => const CreateTaskScreen(),
|
|
),
|
|
|
|
// ── Streaks ──────────────────────────────────────────────────
|
|
GoRoute(
|
|
path: '/streaks',
|
|
name: 'streaks',
|
|
builder: (context, state) => const StreaksScreen(),
|
|
),
|
|
|
|
// ── Time perception ──────────────────────────────────────────
|
|
GoRoute(
|
|
path: '/time',
|
|
name: 'time',
|
|
builder: (context, state) => const TimeDashboardScreen(),
|
|
),
|
|
|
|
// ── Body doubling rooms ──────────────────────────────────────
|
|
GoRoute(
|
|
path: '/rooms',
|
|
name: 'rooms',
|
|
builder: (context, state) => const RoomsScreen(),
|
|
),
|
|
|
|
// ── Settings ─────────────────────────────────────────────────
|
|
GoRoute(
|
|
path: '/settings',
|
|
name: 'settings',
|
|
builder: (context, state) => const SettingsScreen(),
|
|
),
|
|
|
|
// ── Onboarding ───────────────────────────────────────────────
|
|
GoRoute(
|
|
path: '/onboarding',
|
|
name: 'onboarding',
|
|
builder: (context, state) => const OnboardingScreen(),
|
|
),
|
|
],
|
|
);
|
|
|
|
/// Redirect unauthenticated users to /login.
|
|
static Future<String?> _authRedirect(
|
|
BuildContext context,
|
|
GoRouterState state,
|
|
) async {
|
|
final publicPaths = {'/login', '/signup', '/onboarding'};
|
|
if (publicPaths.contains(state.matchedLocation)) return null;
|
|
|
|
final loggedIn = await AuthInterceptor.hasToken();
|
|
if (!loggedIn) return '/login';
|
|
|
|
return null; // no redirect needed
|
|
}
|
|
}
|