Implemented settings, new scan, enhanced UI/UX
This commit is contained in:
279
lib/feature/scan/presentation/scan_page.dart
Normal file
279
lib/feature/scan/presentation/scan_page.dart
Normal file
@ -0,0 +1,279 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
|
||||
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_state.dart';
|
||||
import 'package:hl_lieferservice/feature/scan/presentation/scan_screen.dart';
|
||||
import 'package:hl_lieferservice/model/tour.dart';
|
||||
import 'package:hl_lieferservice/widget/home/bloc/navigation_bloc.dart';
|
||||
import 'package:hl_lieferservice/widget/home/bloc/navigation_event.dart';
|
||||
|
||||
enum TourHomeSteps { planning, delivery, off }
|
||||
|
||||
class ScanPage extends StatefulWidget {
|
||||
const ScanPage({super.key});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _ScanPageState();
|
||||
}
|
||||
|
||||
class _ScanPageState extends State<ScanPage> {
|
||||
int _currentStepIndex = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_tryFinish(context
|
||||
.read<TourBloc>()
|
||||
.state);
|
||||
}
|
||||
|
||||
void _onStartScan() {
|
||||
Navigator.of(
|
||||
context,
|
||||
).push(MaterialPageRoute(builder: (context) => ArticleScanningScreen()));
|
||||
}
|
||||
|
||||
Widget _tourSteps(Tour tour) {
|
||||
var allArticlesScanned = tour.deliveries.every(
|
||||
(delivery) => delivery.allArticlesScanned(),
|
||||
);
|
||||
|
||||
return Stepper(
|
||||
currentStep: _currentStepIndex,
|
||||
controlsBuilder: (context, details) {
|
||||
if (details.stepIndex == TourHomeSteps.planning.index) {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 15),
|
||||
child: FilledButton.icon(
|
||||
label: const Text("Scannen"),
|
||||
onPressed: _onStartScan,
|
||||
icon: const Icon(Icons.qr_code),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 15),
|
||||
child: FilledButton.icon(
|
||||
label: const Text("Auslieferung starten"),
|
||||
onPressed:
|
||||
allArticlesScanned
|
||||
? () =>
|
||||
context.read<NavigationBloc>().add(
|
||||
NavigateToIndex(index: 1))
|
||||
: null,
|
||||
icon: const Icon(Icons.local_shipping),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
onStepContinue:
|
||||
_currentStepIndex >= 1
|
||||
? null
|
||||
: () =>
|
||||
setState(() {
|
||||
if (_currentStepIndex < 2) {
|
||||
_currentStepIndex += 1;
|
||||
}
|
||||
}),
|
||||
onStepCancel:
|
||||
_currentStepIndex == 0
|
||||
? null
|
||||
: () =>
|
||||
setState(() {
|
||||
if (_currentStepIndex > 0) {
|
||||
_currentStepIndex -= 1;
|
||||
}
|
||||
}),
|
||||
onStepTapped:
|
||||
(value) =>
|
||||
setState(() {
|
||||
if (_currentStepIndex == 1 && allArticlesScanned) {
|
||||
return;
|
||||
}
|
||||
|
||||
_currentStepIndex = value;
|
||||
}),
|
||||
steps: [
|
||||
Step(
|
||||
title: Row(
|
||||
children: [
|
||||
Text(
|
||||
"Fahrzeuge beladen",
|
||||
style: TextStyle(
|
||||
color: allArticlesScanned ? Colors.grey : null,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
child:
|
||||
!allArticlesScanned
|
||||
? const Icon(
|
||||
Icons.access_time_filled,
|
||||
color: Colors.orangeAccent,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.check_circle,
|
||||
color: Colors.lightGreen,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
content: const Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 10),
|
||||
child: Icon(Icons.barcode_reader, color: Colors.black),
|
||||
),
|
||||
Text(
|
||||
"Scannen Sie die Ware, die Sie für die Auslieferungen benötigen.",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Step(
|
||||
title: const Text("Ausliefern"),
|
||||
content: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child:
|
||||
!allArticlesScanned
|
||||
? const Text(
|
||||
"Scannen Sie erst die benötigte Ware, um die Auslieferungen zu beginnen.",
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _info(Tour tour) {
|
||||
int amountArticles = tour.deliveries.fold(
|
||||
0,
|
||||
(acc, delivery) =>
|
||||
acc +
|
||||
delivery.articles
|
||||
.where((article) => article.scannable)
|
||||
.fold(
|
||||
0,
|
||||
(amountArticles, article) => amountArticles + article.amount,
|
||||
),
|
||||
);
|
||||
|
||||
int amountCars = tour.driver.cars.length;
|
||||
int amountDeliveries = tour.deliveries.length;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: Card(
|
||||
color: Theme
|
||||
.of(context)
|
||||
.colorScheme
|
||||
.onSecondary,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.archive),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
child: Text("Anzahl Artikel"),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(amountArticles.toString()),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 15),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.local_shipping_outlined),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
child: Text("Anzahl Fahrzeuge"),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(amountCars.toString()),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 15),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.person),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
child: Text("Anzahl Lieferungen"),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(amountDeliveries.toString()),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _tryFinish(TourState state) {
|
||||
if (state is TourLoaded) {
|
||||
if (state.tour.deliveries.every(
|
||||
(delivery) => delivery.allArticlesScanned(),
|
||||
)) {
|
||||
setState(() {
|
||||
_currentStepIndex = 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocConsumer<TourBloc, TourState>(
|
||||
listener: (context, state) {
|
||||
_tryFinish(state);
|
||||
},
|
||||
builder: (context, state) {
|
||||
if (state is TourLoaded) {
|
||||
return Column(children: [_info(state.tour), _tourSteps(state.tour)]);
|
||||
}
|
||||
|
||||
return Center(child: CircularProgressIndicator());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user