import 'package:dartz/dartz.dart' hide State; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'core/theme/app_theme.dart'; import 'domain/entities/tour.dart'; import 'domain/entities/logistic_object.dart'; import 'domain/entities/location.dart'; import 'domain/entities/counter.dart'; import 'domain/repositories/tour_repository.dart'; import 'core/errors/failures.dart'; import 'presentation/blocs/tour/tour_bloc.dart'; import 'presentation/blocs/scan/scan_bloc.dart'; import 'presentation/pages/tours/tours_page.dart'; import 'presentation/pages/tours/dashboard_page.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); // Set preferred orientations SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); // Set system UI overlay style SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.light, systemNavigationBarColor: Colors.white, systemNavigationBarIconBrightness: Brightness.dark, ), ); runApp(const HHAApp()); } class HHAApp extends StatelessWidget { const HHAApp({super.key}); @override Widget build(BuildContext context) { final repository = MockTourRepository(); return MultiBlocProvider( providers: [ BlocProvider( create: (context) => TourBloc( repository: repository, )..add(const LoadTours()), ), BlocProvider( create: (context) => ScanBloc( repository: repository, ), ), ], child: MaterialApp( title: 'HHA Logistics', debugShowCheckedModeBanner: false, theme: AppTheme.lightTheme, home: const MainNavigationPage(), ), ); } } class MainNavigationPage extends StatefulWidget { const MainNavigationPage({super.key}); @override State createState() => _MainNavigationPageState(); } class _MainNavigationPageState extends State { int _currentIndex = 0; final List _pages = const [ DashboardPage(), ToursPage(), InventoryPage(), SettingsPage(), ]; @override Widget build(BuildContext context) { return Scaffold( body: IndexedStack( index: _currentIndex, children: _pages, ), bottomNavigationBar: NavigationBar( selectedIndex: _currentIndex, onDestinationSelected: (index) { setState(() { _currentIndex = index; }); }, destinations: const [ NavigationDestination( icon: Icon(Icons.dashboard_outlined), selectedIcon: Icon(Icons.dashboard), label: 'Dashboard', ), NavigationDestination( icon: Icon(Icons.map_outlined), selectedIcon: Icon(Icons.map), label: 'Touren', ), NavigationDestination( icon: Icon(Icons.inventory_2_outlined), selectedIcon: Icon(Icons.inventory_2), label: 'Bestand', ), NavigationDestination( icon: Icon(Icons.settings_outlined), selectedIcon: Icon(Icons.settings), label: 'Einstellungen', ), ], ), ); } } // Mock Repository for demonstration class MockTourRepository implements TourRepository { @override Future>> getTours() async { await Future.delayed(const Duration(seconds: 1)); return const Right([ Tour( id: 1, jobId: 1, tourId: 1, version: 1, state: 0, type: 'stock_start', sort: 1, locationId: 1, locationCode: 'LAGER001', locationName: 'Hauptlager Wandsbek', modified: 0, ), Tour( id: 2, jobId: 1, tourId: 2, version: 1, state: 0, type: 'veh_start', sort: 2, locationId: 2, locationCode: 'DST001', locationName: 'Dienststelle Hammerbrook', modified: 0, ), Tour( id: 3, jobId: 1, tourId: 3, version: 1, state: 0, type: 'st', sort: 3, locationId: 3, locationCode: 'HALT001', locationName: 'Hauptbahnhof Nord', remark: '4 Fahrscheinautomaten', modified: 0, ), Tour( id: 4, jobId: 1, tourId: 4, version: 1, state: 1, type: 'st', sort: 4, locationId: 4, locationCode: 'HALT002', locationName: 'Jungfernstieg', remark: '2 Fahrscheinautomaten', modified: 0, ), Tour( id: 5, jobId: 1, tourId: 5, version: 1, state: 0, type: 'gi', sort: 5, locationId: 5, locationCode: 'BANK001', locationName: 'Geldinstitut Mitte', modified: 0, ), ]); } @override Future> getTourById(int tourId) async { final tours = await getTours(); return tours.fold( (failure) => Left(failure), (tourList) { final tour = tourList.firstWhere( (t) => t.tourId == tourId, orElse: () => throw Exception('Tour not found'), ); return Right(tour); }, ); } @override Future> updateTourState(int tourId, int state) async { return const Right(null); } @override Future> completeTour(int tourId) async { return const Right(null); } @override Future> syncData() async { await Future.delayed(const Duration(seconds: 1)); return const Right(null); } @override Future> checkForUpdates() async => const Right(false); @override Future>> getObjectsByTour(int tourId) async => const Right([]); @override Future>> getObjectsByState(String state) async => const Right([]); @override Future> getObjectByBarcode(String barcode) async => const Right(null); @override Future> updateObjectState( int objectId, String newState, { int? locationId, int? refType, int? refId, String? containerCode, }) async => const Right(null); @override Future> createObject({ required int type, required String code, bool isManual = true, }) async => const Right(null); @override Future>> getLocations() async => const Right([]); @override Future> getLocationById(int locationId) async { return const Left(NotFoundFailure(message: 'Location not found')); } @override Future>> getObjectMetadata() async => const Right([]); @override Future> getTourStatistics(int tourId) async { return const Right(TourStatistics( totalObjects: 10, completedObjects: 5, pendingObjects: 5, objectsByState: {'delivery': 3, 'station': 2}, objectsByType: {'meka': 3, 'beka': 2}, completionPercentage: 50.0, )); } @override Future> getObjectStatistics() async { return const Right(ObjectStatistics( byState: {}, byType: {}, byLocation: {}, recentObjects: [], totalCount: 0, )); } @override Future> getCounterOverview( int tourId, String tourType, { String? pageId, }) async { return Right(CounterOverview( tourId: tourId, pageId: pageId, groups: [], )); } @override Future>> getPickupCounts( int tourId, String pageId, ) async => const Right([]); @override Future>> getSwapCounts( int tourId, String pageId, ) async => const Right([]); @override Future>> getOpenContainers() async => const Right([]); @override Future> addObjectToContainer( String containerId, String containerType, int objectId, ) async => const Right(null); @override Future> closeContainer( String containerId, String containerType, ) async => const Right(null); @override Future>> getRecentScans( int tourId, { int limit = 10, }) async => const Right([]); } // Placeholder pages class InventoryPage extends StatelessWidget { const InventoryPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Bestand'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.inventory_2, size: 80, color: Colors.grey.shade400, ), const SizedBox(height: 16), Text( 'Bestandsübersicht', style: Theme.of(context).textTheme.headlineSmall, ), const SizedBox(height: 8), Text( 'Hier wird der aktuelle Bestand angezeigt', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Colors.grey.shade600, ), ), ], ), ), ); } } class SettingsPage extends StatelessWidget { const SettingsPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Einstellungen'), ), body: ListView( children: [ ListTile( leading: const Icon(Icons.sync), title: const Text('Daten synchronisieren'), subtitle: const Text('Letzte Synchronisation: Gerade eben'), trailing: const Icon(Icons.chevron_right), onTap: () { // Trigger sync }, ), const Divider(), ListTile( leading: const Icon(Icons.visibility), title: const Text('Erledigte Stationen anzeigen'), trailing: Switch( value: true, onChanged: (value) {}, ), ), const Divider(), ListTile( leading: const Icon(Icons.info), title: const Text('Über'), subtitle: const Text('Version 2.0.0'), trailing: const Icon(Icons.chevron_right), onTap: () {}, ), ], ), ); } }