feat: Complete Flutter app structure for LifeFlow
ADDED: - analysis_options.yaml (Flutter linting rules) - .gitignore (Flutter-specific) - All missing screen files: - routines/routines_screen.dart - calendar/calendar_screen.dart - stats/stats_screen.dart - settings/settings_screen.dart - RoutineCard widget with category colors - Models barrel export (models.dart) - Fixed AppTheme (removed duplicate class) APP STRUCTURE: ├── lib/ │ ├── main.dart (entry point with navigation) │ ├── models/ (Routine, Activity, Gamification) │ ├── repositories/ (RoutineRepository with Riverpod) │ ├── screens/ (Dashboard, Routines, Calendar, Stats, Settings) │ └── theme/ (AppTheme, AppColors) │ FEATURES READY: - Bottom navigation (5 tabs) - Dashboard with progress ring - Routine cards with category icons - Settings screen with options - Light/Dark theme support - Riverpod state management setup NOTE: This is a skeleton app that compiles but needs: - Hive initialization - Actual data persistence - Notification setup - More screen implementations To build APK, run: flutter build apk --release
This commit is contained in:
parent
545e092d3b
commit
a21873ebc3
|
|
@ -0,0 +1,44 @@
|
|||
# Flutter/Dart
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
/android/key.properties
|
||||
/ios/Flutter/.last_build_id
|
||||
/ios/Pods/
|
||||
/macos/Flutter/ephemeral/
|
||||
/windows/flutter/ephemeral/
|
||||
/linux/flutter/ephemeral/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Secrets
|
||||
*.jks
|
||||
*.keystore
|
||||
key.properties
|
||||
local.properties
|
||||
|
||||
# Temporary files
|
||||
*.log
|
||||
*.tmp
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# Test coverage
|
||||
coverage/
|
||||
.test_coverage.dart
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
rules:
|
||||
avoid_print: false
|
||||
prefer_single_quotes: true
|
||||
prefer_const_constructors: true
|
||||
prefer_const_literals_to_create_immutables: true
|
||||
avoid_unnecessary_containers: true
|
||||
use_key_in_widget_constructors: true
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export 'routine.dart';
|
||||
export 'activity.dart';
|
||||
export 'gamification.dart';
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class CalendarScreen extends StatelessWidget {
|
||||
const CalendarScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Calendar'),
|
||||
),
|
||||
body: const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.calendar_today, size: 64, color: Colors.grey),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'Calendar view coming soon',
|
||||
style: TextStyle(fontSize: 18, color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class RoutinesScreen extends StatelessWidget {
|
||||
const RoutinesScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('My Routines'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.filter_list),
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.checklist, size: 64, color: Colors.grey),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'Your routines will appear here',
|
||||
style: TextStyle(fontSize: 18, color: Colors.grey),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
'Tap + to add your first routine',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {},
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import '../../models/routine.dart';
|
||||
|
||||
class RoutineCard extends StatelessWidget {
|
||||
final Routine routine;
|
||||
final VoidCallback? onTap;
|
||||
final VoidCallback? onComplete;
|
||||
|
||||
const RoutineCard({
|
||||
super.key,
|
||||
required this.routine,
|
||||
this.onTap,
|
||||
this.onComplete,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
// Icon
|
||||
Container(
|
||||
width: 56,
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
color: _getCategoryColor().withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
routine.category.icon,
|
||||
style: const TextStyle(fontSize: 28),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
// Info
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
routine.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${routine.schedule.time} · ${routine.category.displayName}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
if (routine.description != null && routine.description!.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: Text(
|
||||
routine.description!,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[500],
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Complete button
|
||||
if (onComplete != null)
|
||||
IconButton(
|
||||
onPressed: onComplete,
|
||||
icon: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: _getCategoryColor().withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.check,
|
||||
color: _getCategoryColor(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Color _getCategoryColor() {
|
||||
return routine.category.color;
|
||||
}
|
||||
}
|
||||
|
||||
// Extension for category colors
|
||||
extension CategoryColor on RoutineCategory {
|
||||
Color get color {
|
||||
switch (this) {
|
||||
case RoutineCategory.medication:
|
||||
return const Color(0xFFE74C3C);
|
||||
case RoutineCategory.vitamin:
|
||||
return const Color(0xFFF39C12);
|
||||
case RoutineCategory.appointment:
|
||||
return const Color(0xFF9B59B6);
|
||||
case RoutineCategory.sleep:
|
||||
return const Color(0xFF8E44AD);
|
||||
case RoutineCategory.food:
|
||||
return const Color(0xFFE67E22);
|
||||
case RoutineCategory.hydration:
|
||||
return const Color(0xFF3498DB);
|
||||
case RoutineCategory.exercise:
|
||||
return const Color(0xFF27AE60);
|
||||
case RoutineCategory.hygiene:
|
||||
return const Color(0xFF1ABC9C);
|
||||
case RoutineCategory.selfCare:
|
||||
return const Color(0xFF16A085);
|
||||
case RoutineCategory.custom:
|
||||
return const Color(0xFF4A90E2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class SettingsScreen extends StatelessWidget {
|
||||
const SettingsScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Settings'),
|
||||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.person),
|
||||
title: const Text('Account'),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.notifications),
|
||||
title: const Text('Notifications'),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.palette),
|
||||
title: const Text('Appearance'),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.backup),
|
||||
title: const Text('Backup & Sync'),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.privacy_tip),
|
||||
title: const Text('Privacy'),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.help),
|
||||
title: const Text('Help & Support'),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info),
|
||||
title: const Text('About'),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class StatsScreen extends StatelessWidget {
|
||||
const StatsScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Statistics'),
|
||||
),
|
||||
body: const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.insights, size: 64, color: Colors.grey),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'Your stats will appear here',
|
||||
style: TextStyle(fontSize: 18, color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppTheme {
|
||||
class AppColors {
|
||||
// Primary Colors
|
||||
static const Color primary = Color(0xFF4A90E2);
|
||||
static const Color primaryLight = Color(0xFF7BB3F0);
|
||||
|
|
@ -27,45 +27,6 @@ class AppTheme {
|
|||
static const Color warning = Color(0xFFF39C12);
|
||||
static const Color error = Color(0xFFE74C3C);
|
||||
static const Color info = Color(0xFF3498DB);
|
||||
|
||||
static Color getCategoryColor(RoutineCategory category) {
|
||||
switch (category) {
|
||||
case RoutineCategory.medication:
|
||||
return medication;
|
||||
case RoutineCategory.vitamin:
|
||||
return vitamin;
|
||||
case RoutineCategory.appointment:
|
||||
return appointment;
|
||||
case RoutineCategory.sleep:
|
||||
return sleep;
|
||||
case RoutineCategory.food:
|
||||
return food;
|
||||
case RoutineCategory.hydration:
|
||||
return hydration;
|
||||
case RoutineCategory.exercise:
|
||||
return exercise;
|
||||
case RoutineCategory.hygiene:
|
||||
return hygiene;
|
||||
case RoutineCategory.selfCare:
|
||||
return selfCare;
|
||||
case RoutineCategory.custom:
|
||||
return primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary enum for compilation
|
||||
enum RoutineCategory {
|
||||
medication,
|
||||
vitamin,
|
||||
appointment,
|
||||
sleep,
|
||||
food,
|
||||
hydration,
|
||||
exercise,
|
||||
hygiene,
|
||||
selfCare,
|
||||
custom,
|
||||
}
|
||||
|
||||
class AppTheme {
|
||||
|
|
|
|||
Loading…
Reference in New Issue