Initial commit: Fixes for linting and compilation
This commit is contained in:
406
lib/screens/home/home_screen.dart
Normal file
406
lib/screens/home/home_screen.dart
Normal file
@@ -0,0 +1,406 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import '../../theme/app_theme.dart';
|
||||
import '../../models/user_profile.dart';
|
||||
import '../../models/cycle_entry.dart';
|
||||
import '../../models/scripture.dart';
|
||||
import '../calendar/calendar_screen.dart';
|
||||
import '../log/log_screen.dart';
|
||||
import '../devotional/devotional_screen.dart';
|
||||
import '../../widgets/tip_card.dart';
|
||||
import '../../widgets/cycle_ring.dart';
|
||||
import '../../widgets/scripture_card.dart';
|
||||
import '../../widgets/quick_log_buttons.dart';
|
||||
import '../../providers/user_provider.dart';
|
||||
import '../../services/cycle_service.dart';
|
||||
|
||||
class HomeScreen extends ConsumerStatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<HomeScreen> createState() => _HomeScreenState();
|
||||
}
|
||||
|
||||
class _HomeScreenState extends ConsumerState<HomeScreen> {
|
||||
int _selectedIndex = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: IndexedStack(
|
||||
index: _selectedIndex,
|
||||
children: [
|
||||
const _DashboardTab(),
|
||||
const CalendarScreen(),
|
||||
const LogScreen(),
|
||||
const DevotionalScreen(),
|
||||
_SettingsTab(onReset: () => setState(() => _selectedIndex = 0)),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.charcoal.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: BottomNavigationBar(
|
||||
currentIndex: _selectedIndex,
|
||||
onTap: (index) => setState(() => _selectedIndex = index),
|
||||
items: const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.home_outlined),
|
||||
activeIcon: Icon(Icons.home),
|
||||
label: 'Home',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.calendar_today_outlined),
|
||||
activeIcon: Icon(Icons.calendar_today),
|
||||
label: 'Calendar',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.add_circle_outline),
|
||||
activeIcon: Icon(Icons.add_circle),
|
||||
label: 'Log',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.menu_book_outlined),
|
||||
activeIcon: Icon(Icons.menu_book),
|
||||
label: 'Devotional',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.settings_outlined),
|
||||
activeIcon: Icon(Icons.settings),
|
||||
label: 'Settings',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DashboardTab extends ConsumerWidget {
|
||||
const _DashboardTab();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final user = ref.watch(userProfileProvider);
|
||||
final cycleInfo = ref.watch(currentCycleInfoProvider);
|
||||
|
||||
final name = user?.name ?? 'Friend';
|
||||
final phase = cycleInfo['phase'] as CyclePhase;
|
||||
final dayOfCycle = cycleInfo['dayOfCycle'] as int;
|
||||
final cycleLength = user?.averageCycleLength ?? 28;
|
||||
|
||||
// Get scripture for current phase
|
||||
final scripture = ScriptureDatabase.getScriptureForPhase(phase.name);
|
||||
|
||||
return SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Greeting
|
||||
_buildGreeting(name),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Cycle Ring
|
||||
Center(
|
||||
child: CycleRing(
|
||||
dayOfCycle: dayOfCycle,
|
||||
totalDays: cycleLength,
|
||||
phase: phase,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Scripture Card
|
||||
ScriptureCard(
|
||||
verse: scripture.verse,
|
||||
reference: scripture.reference,
|
||||
phase: phase,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Quick Log Buttons
|
||||
Text(
|
||||
'Quick Log',
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.charcoal,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const QuickLogButtons(),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Today's Tip - Only show if not just tracking or husband (though husband has own screen)
|
||||
if (user?.role == UserRole.wife)
|
||||
TipCard(phase: phase, isMarried: user?.isMarried ?? false),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildGreeting(String name) {
|
||||
final hour = DateTime.now().hour;
|
||||
String greeting;
|
||||
if (hour < 12) {
|
||||
greeting = 'Good morning';
|
||||
} else if (hour < 17) {
|
||||
greeting = 'Good afternoon';
|
||||
} else {
|
||||
greeting = 'Good evening';
|
||||
}
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'$greeting,',
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 16,
|
||||
color: AppColors.warmGray,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
name,
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.charcoal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.blushPink,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.notifications_outlined,
|
||||
color: AppColors.rose,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Placeholder _calculateCycleInfo removed as it's now in CycleService
|
||||
}
|
||||
|
||||
class _SettingsTab extends ConsumerWidget {
|
||||
final VoidCallback? onReset;
|
||||
const _SettingsTab({this.onReset});
|
||||
|
||||
Widget _buildSettingsTile(BuildContext context, IconData icon, String title, {VoidCallback? onTap}) {
|
||||
return ListTile(
|
||||
leading: Icon(icon, color: AppColors.charcoal),
|
||||
title: Text(
|
||||
title,
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 16,
|
||||
color: AppColors.charcoal,
|
||||
),
|
||||
),
|
||||
trailing: Icon(Icons.chevron_right, color: AppColors.lightGray),
|
||||
onTap: onTap ?? () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Settings coming soon!')),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _resetApp(BuildContext context, WidgetRef ref) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Reset App?'),
|
||||
content: const Text('This will clear all data and return you to onboarding. Are you sure?'),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.pop(context, false), child: const Text('Cancel')),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: const Text('Reset', style: TextStyle(color: Colors.red)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (confirmed == true) {
|
||||
await ref.read(userProfileProvider.notifier).clearProfile();
|
||||
await ref.read(cycleEntriesProvider.notifier).clearEntries();
|
||||
|
||||
if (context.mounted) {
|
||||
onReset?.call();
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final user = ref.watch(userProfileProvider);
|
||||
|
||||
return SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Settings',
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.charcoal,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Profile Card
|
||||
Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.charcoal.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [AppColors.blushPink, AppColors.rose.withOpacity(0.7)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
user?.name.isNotEmpty == true ? user!.name[0].toUpperCase() : '?',
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
user?.name ?? 'Guest',
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.charcoal,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
user?.role == UserRole.husband
|
||||
? 'HUSBAND'
|
||||
: (user?.relationshipStatus.name.toUpperCase() ?? 'SINGLE'),
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 12,
|
||||
letterSpacing: 1,
|
||||
color: AppColors.warmGray,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Icon(Icons.chevron_right, color: AppColors.warmGray),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Settings Groups
|
||||
_buildSettingsGroup('Preferences', [
|
||||
_buildSettingsTile(context, Icons.notifications_outlined, 'Notifications'),
|
||||
_buildSettingsTile(context, Icons.palette_outlined, 'Appearance'),
|
||||
_buildSettingsTile(context, Icons.lock_outline, 'Privacy'),
|
||||
]),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
_buildSettingsGroup('Cycle', [
|
||||
_buildSettingsTile(context, Icons.calendar_today_outlined, 'Cycle Settings'),
|
||||
_buildSettingsTile(context, Icons.trending_up_outlined, 'Cycle History'),
|
||||
_buildSettingsTile(context, Icons.download_outlined, 'Export Data'),
|
||||
]),
|
||||
const SizedBox(height: 16),
|
||||
_buildSettingsGroup('Account', [
|
||||
_buildSettingsTile(
|
||||
context,
|
||||
Icons.logout,
|
||||
'Reset App / Logout',
|
||||
onTap: () => _resetApp(context, ref)
|
||||
),
|
||||
]),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSettingsGroup(String title, List<Widget> tiles) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.warmGray,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
children: tiles,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user