Files
trainhub-flutter/lib/presentation/home/home_page.dart
Kazimierz Ciołek 9dcc4b87de
Some checks failed
Build Linux App / build (push) Failing after 1m18s
Next refactors
2026-02-24 02:19:28 +01:00

128 lines
4.3 KiB
Dart

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:trainhub_flutter/core/constants/ui_constants.dart';
import 'package:trainhub_flutter/core/theme/app_colors.dart';
import 'package:trainhub_flutter/presentation/common/widgets/app_empty_state.dart';
import 'package:trainhub_flutter/presentation/home/home_controller.dart';
import 'package:trainhub_flutter/presentation/home/home_state.dart';
import 'package:trainhub_flutter/presentation/home/widgets/next_workout_banner.dart';
import 'package:trainhub_flutter/presentation/home/widgets/quick_actions_row.dart';
import 'package:trainhub_flutter/presentation/home/widgets/recent_activity_section.dart';
import 'package:trainhub_flutter/presentation/home/widgets/stat_cards_row.dart';
import 'package:trainhub_flutter/presentation/home/widgets/welcome_header.dart';
@RoutePage()
class HomePage extends ConsumerWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final asyncState = ref.watch(homeControllerProvider);
return asyncState.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => _ErrorView(
error: e,
onRetry: () => ref.read(homeControllerProvider.notifier).refresh(),
),
data: (data) {
if (data.activeProgramName == null) {
return AppEmptyState(
icon: Icons.calendar_today_outlined,
title: 'No active program',
subtitle:
'Head to Calendar to create or select a training program to get started.',
actionLabel: 'Go to Calendar',
onAction: () => AutoTabsRouter.of(context).setActiveIndex(3),
);
}
return _HomeContent(data: data);
},
);
}
}
class _ErrorView extends StatelessWidget {
const _ErrorView({required this.error, required this.onRetry});
final Object error;
final VoidCallback onRetry;
@override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.all(UIConstants.pagePadding),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.error_outline,
size: 48,
color: AppColors.destructive,
),
const SizedBox(height: UIConstants.spacing16),
Text(
'Something went wrong',
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
),
),
const SizedBox(height: UIConstants.spacing8),
Text(
'$error',
style: GoogleFonts.inter(
fontSize: 13,
color: AppColors.textMuted,
),
textAlign: TextAlign.center,
),
const SizedBox(height: UIConstants.spacing24),
FilledButton.icon(
onPressed: onRetry,
icon: const Icon(Icons.refresh, size: 18),
label: const Text('Retry'),
),
],
),
),
);
}
}
class _HomeContent extends StatelessWidget {
const _HomeContent({required this.data});
final HomeState data;
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(UIConstants.pagePadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
WelcomeHeader(programName: data.activeProgramName!),
const SizedBox(height: UIConstants.spacing24),
StatCardsRow(
completed: data.completedWorkouts,
total: data.totalWorkouts,
),
const SizedBox(height: UIConstants.spacing24),
if (data.nextWorkoutName != null) ...[
NextWorkoutBanner(workoutName: data.nextWorkoutName!),
const SizedBox(height: UIConstants.spacing24),
],
const QuickActionsRow(),
const SizedBox(height: UIConstants.spacing32),
RecentActivitySection(activity: data.recentActivity),
],
),
);
}
}