runable
This commit is contained in:
353
lib/app.dart
Normal file
353
lib/app.dart
Normal file
@@ -0,0 +1,353 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:worker/core/theme/app_theme.dart';
|
||||
import 'package:worker/generated/l10n/app_localizations.dart';
|
||||
|
||||
/// Root application widget for Worker Mobile App
|
||||
///
|
||||
/// This is the main app widget that:
|
||||
/// - Sets up Material 3 theme configuration
|
||||
/// - Configures localization for Vietnamese and English
|
||||
/// - Provides router configuration (to be implemented)
|
||||
/// - Integrates with Riverpod for state management
|
||||
/// - Handles app-level error states
|
||||
class WorkerApp extends ConsumerWidget {
|
||||
const WorkerApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return MaterialApp(
|
||||
// ==================== App Configuration ====================
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Worker App',
|
||||
|
||||
// ==================== Theme Configuration ====================
|
||||
// Material 3 theme with brand colors (Primary Blue: #005B9A)
|
||||
theme: AppTheme.lightTheme(),
|
||||
darkTheme: AppTheme.darkTheme(),
|
||||
themeMode: ThemeMode.light, // TODO: Make this configurable from settings
|
||||
|
||||
// ==================== Localization Configuration ====================
|
||||
// Support for Vietnamese (primary) and English (secondary)
|
||||
localizationsDelegates: const [
|
||||
// App-specific localizations
|
||||
AppLocalizations.delegate,
|
||||
|
||||
// Material Design localizations
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
|
||||
// Supported locales
|
||||
supportedLocales: const [
|
||||
Locale('vi', 'VN'), // Vietnamese (primary)
|
||||
Locale('en', 'US'), // English (secondary)
|
||||
],
|
||||
|
||||
// Default locale (Vietnamese)
|
||||
locale: const Locale('vi', 'VN'), // TODO: Make this configurable from settings
|
||||
|
||||
// Locale resolution strategy
|
||||
localeResolutionCallback: (locale, supportedLocales) {
|
||||
// Check if the device locale is supported
|
||||
for (final supportedLocale in supportedLocales) {
|
||||
if (supportedLocale.languageCode == locale?.languageCode) {
|
||||
return supportedLocale;
|
||||
}
|
||||
}
|
||||
|
||||
// If device locale is not supported, default to Vietnamese
|
||||
return const Locale('vi', 'VN');
|
||||
},
|
||||
|
||||
// ==================== Navigation Configuration ====================
|
||||
// TODO: Replace with actual router configuration when navigation is implemented
|
||||
// Options:
|
||||
// 1. Use go_router for declarative routing
|
||||
// 2. Use Navigator 2.0 for imperative routing
|
||||
// 3. Use auto_route for type-safe routing
|
||||
//
|
||||
// For now, we use a placeholder home screen
|
||||
home: const _PlaceholderHomePage(),
|
||||
|
||||
// Alternative: Use onGenerateRoute for custom routing
|
||||
// onGenerateRoute: (settings) {
|
||||
// return AppRouter.onGenerateRoute(settings);
|
||||
// },
|
||||
|
||||
// ==================== Material App Configuration ====================
|
||||
// Builder for additional context-dependent widgets
|
||||
builder: (context, child) {
|
||||
return _AppBuilder(
|
||||
child: child ?? const SizedBox.shrink(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// App builder widget
|
||||
///
|
||||
/// Wraps the entire app with additional widgets:
|
||||
/// - Error boundary
|
||||
/// - Connectivity listener
|
||||
/// - Global overlays (loading, snackbars)
|
||||
class _AppBuilder extends ConsumerWidget {
|
||||
const _AppBuilder({
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// TODO: Add connectivity listener
|
||||
// final connectivity = ref.watch(connectivityProvider);
|
||||
|
||||
// TODO: Add global loading state
|
||||
// final isLoading = ref.watch(globalLoadingProvider);
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
// Main app content
|
||||
child,
|
||||
|
||||
// TODO: Add global loading overlay
|
||||
// if (isLoading)
|
||||
// const _GlobalLoadingOverlay(),
|
||||
|
||||
// TODO: Add connectivity banner
|
||||
// if (connectivity == ConnectivityStatus.offline)
|
||||
// const _OfflineBanner(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Placeholder home page
|
||||
///
|
||||
/// This is a temporary home screen that will be replaced with the actual
|
||||
/// home page implementation from features/home/presentation/pages/home_page.dart
|
||||
///
|
||||
/// The actual home page will include:
|
||||
/// - Membership card display (Diamond/Platinum/Gold tiers)
|
||||
/// - Quick action grid
|
||||
/// - Bottom navigation bar
|
||||
/// - Floating action button for chat
|
||||
class _PlaceholderHomePage extends ConsumerWidget {
|
||||
const _PlaceholderHomePage();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Worker App'),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// App logo placeholder
|
||||
Container(
|
||||
width: 120,
|
||||
height: 120,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.primary,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.business_center,
|
||||
size: 64,
|
||||
color: theme.colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// Welcome text
|
||||
Text(
|
||||
'Chào mừng đến với Worker App',
|
||||
style: theme.textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Description
|
||||
Text(
|
||||
'Ứng dụng dành cho thầu thợ, kiến trúc sư, đại lý và môi giới',
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
color: theme.colorScheme.onSurface.withValues(alpha: 0.7),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 48),
|
||||
|
||||
// Status indicators
|
||||
const _StatusIndicator(
|
||||
icon: Icons.check_circle,
|
||||
color: Colors.green,
|
||||
label: 'Hive Database: Initialized',
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const _StatusIndicator(
|
||||
icon: Icons.check_circle,
|
||||
color: Colors.green,
|
||||
label: 'Riverpod: Active',
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const _StatusIndicator(
|
||||
icon: Icons.check_circle,
|
||||
color: Colors.green,
|
||||
label: 'Material 3 Theme: Loaded',
|
||||
),
|
||||
const SizedBox(height: 48),
|
||||
|
||||
// Next steps card
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
'Next Steps',
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const _NextStepItem(
|
||||
number: '1',
|
||||
text: 'Implement authentication flow',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const _NextStepItem(
|
||||
number: '2',
|
||||
text: 'Create home page with membership cards',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const _NextStepItem(
|
||||
number: '3',
|
||||
text: 'Set up navigation and routing',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const _NextStepItem(
|
||||
number: '4',
|
||||
text: 'Implement feature modules',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Floating action button (will be used for chat)
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Chat feature coming soon!'),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Icon(Icons.chat_bubble_outline),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Status indicator widget
|
||||
class _StatusIndicator extends StatelessWidget {
|
||||
const _StatusIndicator({
|
||||
required this.icon,
|
||||
required this.color,
|
||||
required this.label,
|
||||
});
|
||||
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
final String label;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, color: color, size: 20),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
label,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Next step item widget
|
||||
class _NextStepItem extends StatelessWidget {
|
||||
const _NextStepItem({
|
||||
required this.number,
|
||||
required this.text,
|
||||
});
|
||||
|
||||
final String number;
|
||||
final String text;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.primary.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
number,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: theme.colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user