first commit
This commit is contained in:
424
app/lib/main.dart
Normal file
424
app/lib/main.dart
Normal file
@@ -0,0 +1,424 @@
|
||||
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<MainNavigationPage> createState() => _MainNavigationPageState();
|
||||
}
|
||||
|
||||
class _MainNavigationPageState extends State<MainNavigationPage> {
|
||||
int _currentIndex = 0;
|
||||
|
||||
final List<Widget> _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<Either<Failure, List<Tour>>> 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<Either<Failure, Tour>> 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<Either<Failure, void>> updateTourState(int tourId, int state) async {
|
||||
return const Right(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, void>> completeTour(int tourId) async {
|
||||
return const Right(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, void>> syncData() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
return const Right(null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, bool>> checkForUpdates() async => const Right(false);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<LogisticObject>>> getObjectsByTour(int tourId) async => const Right([]);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<LogisticObject>>> getObjectsByState(String state) async => const Right([]);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, LogisticObject?>> getObjectByBarcode(String barcode) async => const Right(null);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, void>> updateObjectState(
|
||||
int objectId,
|
||||
String newState, {
|
||||
int? locationId,
|
||||
int? refType,
|
||||
int? refId,
|
||||
String? containerCode,
|
||||
}) async => const Right(null);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, void>> createObject({
|
||||
required int type,
|
||||
required String code,
|
||||
bool isManual = true,
|
||||
}) async => const Right(null);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<Location>>> getLocations() async => const Right([]);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, Location>> getLocationById(int locationId) async {
|
||||
return const Left(NotFoundFailure(message: 'Location not found'));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<ObjectMetadata>>> getObjectMetadata() async => const Right([]);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, TourStatistics>> 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<Either<Failure, ObjectStatistics>> getObjectStatistics() async {
|
||||
return const Right(ObjectStatistics(
|
||||
byState: {},
|
||||
byType: {},
|
||||
byLocation: {},
|
||||
recentObjects: [],
|
||||
totalCount: 0,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, CounterOverview>> getCounterOverview(
|
||||
int tourId,
|
||||
String tourType, {
|
||||
String? pageId,
|
||||
}) async {
|
||||
return Right(CounterOverview(
|
||||
tourId: tourId,
|
||||
pageId: pageId,
|
||||
groups: [],
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<PickupCount>>> getPickupCounts(
|
||||
int tourId,
|
||||
String pageId,
|
||||
) async => const Right([]);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<SwapCount>>> getSwapCounts(
|
||||
int tourId,
|
||||
String pageId,
|
||||
) async => const Right([]);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<ContainerInfo>>> getOpenContainers() async => const Right([]);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, void>> addObjectToContainer(
|
||||
String containerId,
|
||||
String containerType,
|
||||
int objectId,
|
||||
) async => const Right(null);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, void>> closeContainer(
|
||||
String containerId,
|
||||
String containerType,
|
||||
) async => const Right(null);
|
||||
|
||||
@override
|
||||
Future<Either<Failure, List<RecentScan>>> 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: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user