import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import '../../../../app/di/injection.dart'; import '../../../../app/router/app_routes.dart'; import '../../../../core/l10n/l10n.dart'; import '../../../../core/theme/design_tokens.dart'; import '../../../../shared/widgets/app_button.dart'; import '../../../../shared/widgets/app_loading_indicator.dart'; import '../../../../shared/widgets/app_pressable.dart'; import '../../../../shared/widgets/app_toggle_switch.dart'; import '../../../../shared/widgets/toast/toast.dart'; import '../../../../shared/widgets/toast/toast_type.dart'; import '../../data/models/automation_job_model.dart'; import '../../data/apis/automation_jobs_api.dart'; import '../../presentation/cubits/automation_jobs_cubit.dart'; import '../widgets/settings_page_scaffold.dart'; class FeaturesScreen extends StatefulWidget { const FeaturesScreen({super.key}); @override State createState() => _FeaturesScreenState(); } class _FeaturesScreenState extends State { late final AutomationJobsCubit _cubit; @override void initState() { super.initState(); _cubit = AutomationJobsCubit(sl()); _cubit.loadJobs(); } @override void dispose() { _cubit.close(); super.dispose(); } @override Widget build(BuildContext context) { return BlocProvider.value( value: _cubit, child: SettingsPageScaffold( title: context.l10n.settingsFeaturesTitle, onBack: () => context.pop(), body: BlocBuilder( builder: (context, state) { if (state.isLoading) { return const Center( child: AppLoadingIndicator(variant: AppLoadingVariant.surface), ); } if (state.error != null) { return Center(child: Text(state.error!)); } return _buildJobList(state); }, ), ), ); } Widget _buildJobList(AutomationJobsState state) { final dailyJobs = state.dailyJobs; final weeklyJobs = state.weeklyJobs; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionTitle(context.l10n.settingsSectionDaily), const SizedBox(height: AppSpacing.sm), if (dailyJobs.isEmpty) _buildEmptyHint(context.l10n.settingsNoDailyPlans) else ...dailyJobs.map(_buildJobCard), const SizedBox(height: AppSpacing.lg), _buildSectionTitle(context.l10n.settingsSectionWeekly), const SizedBox(height: AppSpacing.sm), if (weeklyJobs.isEmpty) _buildEmptyHint(context.l10n.settingsNoWeeklyPlans) else ...weeklyJobs.map(_buildJobCard), if (state.canCreateMore) ...[ const SizedBox(height: AppSpacing.lg), _buildCreateButton(), ], ], ); } Widget _buildEmptyHint(String text) { final colorScheme = Theme.of(context).colorScheme; return Container( width: double.infinity, margin: const EdgeInsets.only(bottom: AppSpacing.sm), padding: const EdgeInsets.all(AppSpacing.lg), decoration: BoxDecoration( color: colorScheme.surface, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: colorScheme.outlineVariant), ), child: Text( text, style: TextStyle( color: colorScheme.onSurfaceVariant, fontSize: 13, fontWeight: FontWeight.w500, ), ), ); } Widget _buildSectionTitle(String title) { final colorScheme = Theme.of(context).colorScheme; return Text( title, style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: colorScheme.onSurfaceVariant, ), ); } Widget _buildJobCard(AutomationJobModel job) { final colorScheme = Theme.of(context).colorScheme; return AppPressable( onTap: () async { await context.push(AppRoutes.settingsJobDetail(job.id)); if (!mounted) { return; } _cubit.loadJobs(); }, borderRadius: BorderRadius.circular(AppRadius.lg), child: Container( margin: const EdgeInsets.only(bottom: AppSpacing.sm), padding: const EdgeInsets.all(AppSpacing.lg), decoration: BoxDecoration( color: colorScheme.surface, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: colorScheme.outlineVariant), ), child: Row( children: [ Container( width: AppSpacing.xxl + AppSpacing.lg, height: AppSpacing.xxl + AppSpacing.lg, decoration: BoxDecoration( color: colorScheme.surfaceContainerLow, borderRadius: BorderRadius.circular(AppRadius.md), ), child: Icon( Icons.auto_awesome, size: AppSpacing.lg, color: colorScheme.primary, ), ), const SizedBox(width: AppSpacing.md), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( job.title, style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, color: colorScheme.onSurface, ), ), const SizedBox(height: AppSpacing.xs), Text( _buildSubtitle(job), style: TextStyle( fontSize: 12, color: colorScheme.onSurfaceVariant, ), ), ], ), ), const SizedBox(width: AppSpacing.sm), AppToggleSwitch( value: job.isActive, onChanged: (next) { if (job.isSystem) { Toast.show( context, context.l10n.settingsSystemJobReadonly, type: ToastType.info, ); return; } _cubit.updateJobStatus(id: job.id, enabled: next); }, ), ], ), ), ); } String _buildSubtitle(AutomationJobModel job) { final statusText = job.isActive ? context.l10n.settingsJobStatusEnabled : context.l10n.settingsJobStatusDisabled; final sourceText = job.isSystem ? context.l10n.settingsJobSourceSystem : context.l10n.settingsJobSourceCustom; return '$sourceText • $statusText'; } Widget _buildCreateButton() { return AppButton( text: context.l10n.settingsCreateJob, onPressed: () async { await context.push(AppRoutes.settingsJobNew); if (!mounted) { return; } _cubit.loadJobs(); }, ); } }