354 lines
11 KiB
Dart
354 lines
11 KiB
Dart
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,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|