Added custom tour ordering
This commit is contained in:
@ -60,7 +60,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
|
||||
debugPrint("🔵 Opening browser to: http://localhost:3000/login");
|
||||
|
||||
final loginUrl = Uri.parse('http://192.168.1.9:3000/login');
|
||||
final loginUrl = Uri.parse('http://100.72.100.33:3000/login');
|
||||
final launched = await launchUrl(
|
||||
loginUrl,
|
||||
mode: LaunchMode.externalApplication,
|
||||
|
||||
@ -56,7 +56,7 @@ class _CarManagementPageState extends State<CarManagementPage> {
|
||||
return Scaffold(
|
||||
body: BlocConsumer<CarsBloc, CarsState>(
|
||||
listener: (context, state) {
|
||||
if (state is CarsLoaded) {
|
||||
if (state is CarsLoaded && context.read<TourBloc>().state is TourLoaded) {
|
||||
var tour = (context.read<TourBloc>().state as TourLoaded).tour.copyWith();
|
||||
tour.driver.cars = state.cars;
|
||||
context.read<TourBloc>().add(UpdateTour(tour: tour));
|
||||
|
||||
@ -4,6 +4,8 @@ import 'package:hl_lieferservice/dto/discount_add_response.dart';
|
||||
import 'package:hl_lieferservice/dto/discount_update_response.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/detail/bloc/delivery_event.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/detail/bloc/delivery_state.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/detail/bloc/note_bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/detail/bloc/note_event.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/detail/repository/delivery_repository.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/detail/repository/note_repository.dart';
|
||||
import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart';
|
||||
@ -15,6 +17,7 @@ import '../../../../model/delivery.dart' as model;
|
||||
|
||||
class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
OperationBloc opBloc;
|
||||
NoteBloc noteBloc;
|
||||
DeliveryRepository repository;
|
||||
NoteRepository noteRepository;
|
||||
|
||||
@ -22,6 +25,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
required this.opBloc,
|
||||
required this.repository,
|
||||
required this.noteRepository,
|
||||
required this.noteBloc
|
||||
}) : super(DeliveryInitial()) {
|
||||
on<UnscanArticleEvent>(_unscan);
|
||||
on<ResetScanAmountEvent>(_resetAmount);
|
||||
@ -34,10 +38,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
on<FinishDeliveryEvent>(_finishDelivery);
|
||||
}
|
||||
|
||||
void _finishDelivery(
|
||||
FinishDeliveryEvent event,
|
||||
Emitter<DeliveryState> emit,
|
||||
) async {
|
||||
void _finishDelivery(FinishDeliveryEvent event,
|
||||
Emitter<DeliveryState> emit,) async {
|
||||
final currentState = state;
|
||||
opBloc.add(LoadOperation());
|
||||
|
||||
@ -70,10 +72,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _updatePayment(
|
||||
UpdateSelectedPaymentMethodEvent event,
|
||||
Emitter<DeliveryState> emit,
|
||||
) {
|
||||
void _updatePayment(UpdateSelectedPaymentMethodEvent event,
|
||||
Emitter<DeliveryState> emit,) {
|
||||
final currentState = state;
|
||||
|
||||
if (currentState is DeliveryLoaded) {
|
||||
@ -85,25 +85,23 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _updateDeliveryOptions(
|
||||
UpdateDeliveryOptionEvent event,
|
||||
Emitter<DeliveryState> emit,
|
||||
) {
|
||||
void _updateDeliveryOptions(UpdateDeliveryOptionEvent event,
|
||||
Emitter<DeliveryState> emit,) {
|
||||
final currentState = state;
|
||||
|
||||
if (currentState is DeliveryLoaded) {
|
||||
List<model.DeliveryOption> options =
|
||||
currentState.delivery.options.map((option) {
|
||||
if (option.key == event.key) {
|
||||
if (option.numerical) {
|
||||
return option.copyWith(value: event.value);
|
||||
} else {
|
||||
return option.copyWith(value: event.value == true ? "1" : "0");
|
||||
}
|
||||
}
|
||||
currentState.delivery.options.map((option) {
|
||||
if (option.key == event.key) {
|
||||
if (option.numerical) {
|
||||
return option.copyWith(value: event.value);
|
||||
} else {
|
||||
return option.copyWith(value: event.value == true ? "1" : "0");
|
||||
}
|
||||
}
|
||||
|
||||
return option;
|
||||
}).toList();
|
||||
return option;
|
||||
}).toList();
|
||||
|
||||
emit(
|
||||
DeliveryLoaded(
|
||||
@ -113,10 +111,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _updateDiscount(
|
||||
UpdateDiscountEvent event,
|
||||
Emitter<DeliveryState> emit,
|
||||
) async {
|
||||
void _updateDiscount(UpdateDiscountEvent event,
|
||||
Emitter<DeliveryState> emit,) async {
|
||||
opBloc.add(LoadOperation());
|
||||
|
||||
try {
|
||||
@ -139,22 +135,22 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
String discountArticleNumber = delivery.discount!.article.articleNumber;
|
||||
delivery.discount = model.Discount(
|
||||
article:
|
||||
response.values?.article != null
|
||||
? Article.fromDTO(response.values!.article)
|
||||
: delivery.discount!.article,
|
||||
response.values?.article != null
|
||||
? Article.fromDTO(response.values!.article)
|
||||
: delivery.discount!.article,
|
||||
note:
|
||||
response.values?.note != null
|
||||
? response.values!.note.noteDescription
|
||||
: delivery.discount!.note,
|
||||
response.values?.note != null
|
||||
? response.values!.note.noteDescription
|
||||
: delivery.discount!.note,
|
||||
noteId:
|
||||
response.values?.note != null
|
||||
? response.values!.note.rowId
|
||||
: delivery.discount!.noteId,
|
||||
response.values?.note != null
|
||||
? response.values!.note.rowId
|
||||
: delivery.discount!.noteId,
|
||||
);
|
||||
|
||||
delivery.articles = [
|
||||
...delivery.articles.where(
|
||||
(article) => article.articleNumber != discountArticleNumber,
|
||||
(article) => article.articleNumber != discountArticleNumber,
|
||||
),
|
||||
delivery.discount!.article,
|
||||
];
|
||||
@ -165,7 +161,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
}
|
||||
} catch (e, st) {
|
||||
debugPrint(
|
||||
"Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event.deliveryId}:",
|
||||
"Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event
|
||||
.deliveryId}:",
|
||||
);
|
||||
debugPrint("$e");
|
||||
debugPrint("$st");
|
||||
@ -176,10 +173,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _removeDiscount(
|
||||
RemoveDiscountEvent event,
|
||||
Emitter<DeliveryState> emit,
|
||||
) async {
|
||||
void _removeDiscount(RemoveDiscountEvent event,
|
||||
Emitter<DeliveryState> emit,) async {
|
||||
opBloc.add(LoadOperation());
|
||||
|
||||
try {
|
||||
@ -196,9 +191,9 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
delivery.articles
|
||||
.where(
|
||||
(article) =>
|
||||
article.internalId !=
|
||||
delivery.discount?.article.internalId,
|
||||
)
|
||||
article.internalId !=
|
||||
delivery.discount?.article.internalId,
|
||||
)
|
||||
.toList();
|
||||
|
||||
delivery.discount = null;
|
||||
@ -245,6 +240,10 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
noteId: response.values.note.rowId,
|
||||
);
|
||||
|
||||
noteBloc.add(AddNoteOffline(note: response.values.note.noteDescription,
|
||||
deliveryId: delivery.id,
|
||||
noteId: response.values.note.rowId));
|
||||
|
||||
delivery.articles = [...delivery.articles, delivery.discount!.article];
|
||||
|
||||
emit(currentState.copyWith(delivery));
|
||||
@ -253,7 +252,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
}
|
||||
} catch (e, st) {
|
||||
debugPrint(
|
||||
"Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event.deliveryId}:",
|
||||
"Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event
|
||||
.deliveryId}:",
|
||||
);
|
||||
debugPrint("$e");
|
||||
debugPrint("$st");
|
||||
@ -284,7 +284,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
|
||||
if (currentState is DeliveryLoaded) {
|
||||
Article article = currentState.delivery.articles.firstWhere(
|
||||
(article) => article.internalId == int.parse(event.articleId),
|
||||
(article) => article.internalId == int.parse(event.articleId),
|
||||
);
|
||||
|
||||
article.removeNoteId = noteId;
|
||||
@ -293,7 +293,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
|
||||
List<Article> articles = [
|
||||
...currentState.delivery.articles.where(
|
||||
(article) => article.internalId != int.parse(event.articleId),
|
||||
(article) => article.internalId != int.parse(event.articleId),
|
||||
),
|
||||
article,
|
||||
];
|
||||
@ -313,10 +313,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _resetAmount(
|
||||
ResetScanAmountEvent event,
|
||||
Emitter<DeliveryState> emit,
|
||||
) async {
|
||||
void _resetAmount(ResetScanAmountEvent event,
|
||||
Emitter<DeliveryState> emit,) async {
|
||||
opBloc.add(LoadOperation());
|
||||
|
||||
try {
|
||||
@ -325,7 +323,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
|
||||
if (currentState is DeliveryLoaded) {
|
||||
Article article = currentState.delivery.articles.firstWhere(
|
||||
(article) => article.internalId == int.parse(event.articleId),
|
||||
(article) => article.internalId == int.parse(event.articleId),
|
||||
);
|
||||
|
||||
article.removeNoteId = null;
|
||||
@ -334,7 +332,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
|
||||
|
||||
List<Article> articles = [
|
||||
...currentState.delivery.articles.where(
|
||||
(article) => article.internalId != int.parse(event.articleId),
|
||||
(article) => article.internalId != int.parse(event.articleId),
|
||||
),
|
||||
article,
|
||||
];
|
||||
|
||||
@ -15,7 +15,7 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
|
||||
final OperationBloc opBloc;
|
||||
|
||||
NoteBloc({required this.repository, required this.opBloc})
|
||||
: super(NoteInitial()) {
|
||||
: super(NoteInitial()) {
|
||||
on<LoadNote>(_load);
|
||||
on<AddNote>(_add);
|
||||
on<EditNote>(_edit);
|
||||
@ -23,16 +23,44 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
|
||||
on<AddImageNote>(_upload);
|
||||
on<RemoveImageNote>(_removeImage);
|
||||
on<ResetNotes>(_reset);
|
||||
on<AddNoteOffline>(_addOffline);
|
||||
}
|
||||
|
||||
Future<void> _reset(ResetNotes event, Emitter<NoteState> emit) async {
|
||||
emit.call(NoteInitial());
|
||||
}
|
||||
|
||||
Future<void> _removeImage(
|
||||
RemoveImageNote event,
|
||||
Emitter<NoteState> emit,
|
||||
) async {
|
||||
Future<void> _addOffline(AddNoteOffline event,
|
||||
Emitter<NoteState> emit,) async {
|
||||
if (state is NoteInitial) {
|
||||
emit(
|
||||
NoteLoadedBase(
|
||||
notes: [Note(content: event.note, id: int.parse(event.noteId))],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is NoteLoadedBase) {
|
||||
emit(
|
||||
NoteLoadedBase(
|
||||
notes: [
|
||||
...(state as NoteLoadedBase).notes,
|
||||
Note(content: event.note, id: int.parse(event.noteId)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is NoteLoaded) {
|
||||
final current = state as NoteLoaded;
|
||||
emit(NoteLoaded(notes: [...current.notes, Note(content: event.note, id: int.parse(event.noteId))],
|
||||
templates: [...current.templates],
|
||||
images: [...current.images]));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _removeImage(RemoveImageNote event,
|
||||
Emitter<NoteState> emit,) async {
|
||||
opBloc.add(LoadOperation());
|
||||
|
||||
try {
|
||||
@ -43,9 +71,9 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
|
||||
emit.call(
|
||||
currentState.copyWith(
|
||||
images:
|
||||
currentState.images
|
||||
.where((image) => image.$1.objectId != event.objectId)
|
||||
.toList(),
|
||||
currentState.images
|
||||
.where((image) => image.$1.objectId != event.objectId)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -89,7 +117,7 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
|
||||
|
||||
try {
|
||||
List<String> urls =
|
||||
event.delivery.images.map((image) => image.url).toList();
|
||||
event.delivery.images.map((image) => image.url).toList();
|
||||
List<Note> notes = await repository.loadNotes(event.delivery.id);
|
||||
List<NoteTemplate> templates = await repository.loadTemplates();
|
||||
List<Uint8List> images = await repository.loadImages(urls);
|
||||
@ -100,7 +128,7 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
|
||||
templates: templates,
|
||||
images: List.generate(
|
||||
images.length,
|
||||
(index) => (event.delivery.images[index], images[index]),
|
||||
(index) => (event.delivery.images[index], images[index]),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -148,7 +176,7 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
|
||||
if (currentState is NoteLoaded) {
|
||||
List<Note> refreshedNotes = [
|
||||
...currentState.notes.where(
|
||||
(note) => note.id != int.parse(event.noteId),
|
||||
(note) => note.id != int.parse(event.noteId),
|
||||
),
|
||||
Note(content: event.content, id: int.parse(event.noteId)),
|
||||
];
|
||||
@ -173,9 +201,9 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
|
||||
|
||||
if (currentState is NoteLoaded) {
|
||||
List<Note> refreshedNotes =
|
||||
currentState.notes
|
||||
.where((note) => note.id != int.parse(event.noteId))
|
||||
.toList();
|
||||
currentState.notes
|
||||
.where((note) => note.id != int.parse(event.noteId))
|
||||
.toList();
|
||||
|
||||
emit.call(currentState.copyWith(notes: refreshedNotes));
|
||||
}
|
||||
|
||||
@ -18,6 +18,14 @@ class AddNote extends NoteEvent {
|
||||
final String deliveryId;
|
||||
}
|
||||
|
||||
class AddNoteOffline extends NoteEvent {
|
||||
AddNoteOffline({required this.note, required this.deliveryId, required this.noteId});
|
||||
|
||||
final String note;
|
||||
final String noteId;
|
||||
final String deliveryId;
|
||||
}
|
||||
|
||||
class RemoveNote extends NoteEvent {
|
||||
RemoveNote({required this.noteId});
|
||||
|
||||
|
||||
@ -10,14 +10,21 @@ class NoteLoading extends NoteState {}
|
||||
|
||||
class NoteLoadingFailed extends NoteState {}
|
||||
|
||||
class NoteLoaded extends NoteState {
|
||||
NoteLoaded({
|
||||
class NoteLoadedBase extends NoteState {
|
||||
NoteLoadedBase({
|
||||
required this.notes,
|
||||
required this.templates,
|
||||
required this.images,
|
||||
});
|
||||
|
||||
List<Note> notes;
|
||||
}
|
||||
|
||||
class NoteLoaded extends NoteLoadedBase {
|
||||
NoteLoaded({
|
||||
required this.templates,
|
||||
required this.images,
|
||||
required super.notes,
|
||||
});
|
||||
|
||||
List<NoteTemplate> templates;
|
||||
List<(ImageNote, Uint8List)> images;
|
||||
|
||||
|
||||
@ -48,11 +48,29 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
bool _customerAccepted = false;
|
||||
bool _noteAccepted = false;
|
||||
bool _notesEmpty = true;
|
||||
bool _isCustomerSignatureEmpty = true;
|
||||
bool _isDriverSignatureEmpty = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_customerController.addListener(() {
|
||||
if (_isCustomerSignatureEmpty != _customerController.isEmpty) {
|
||||
setState(() {
|
||||
_isCustomerSignatureEmpty = _customerController.isEmpty;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_driverController.addListener(() {
|
||||
if (_isDriverSignatureEmpty != _driverController.isEmpty) {
|
||||
setState(() {
|
||||
_isDriverSignatureEmpty = _driverController.isEmpty;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// only load notes if they are not already loaded
|
||||
final noteState = context.read<NoteBloc>().state;
|
||||
if (noteState is NoteInitial) {
|
||||
@ -63,6 +81,7 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
@override
|
||||
void dispose() {
|
||||
_customerController.dispose();
|
||||
_driverController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -92,12 +111,18 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
_notesEmpty = current.notes.isEmpty;
|
||||
});
|
||||
}
|
||||
|
||||
if (current is NoteLoadedBase) {
|
||||
setState(() {
|
||||
_notesEmpty = current.notes.isEmpty;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
builder: (context, state) {
|
||||
final current = state;
|
||||
|
||||
if (current is NoteLoaded) {
|
||||
if (current is NoteLoadedBase) {
|
||||
if (current.notes.isEmpty) {
|
||||
return const SizedBox(
|
||||
width: double.infinity,
|
||||
@ -107,12 +132,12 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.event_note_outlined),
|
||||
title: Text(current.notes[index].content),
|
||||
contentPadding: EdgeInsets.all(20),
|
||||
contentPadding: const EdgeInsets.all(20),
|
||||
tileColor: Theme.of(context).colorScheme.onSecondary,
|
||||
);
|
||||
},
|
||||
@ -121,7 +146,7 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
return const SizedBox(
|
||||
width: double.infinity,
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
@ -156,10 +181,17 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
});
|
||||
},
|
||||
),
|
||||
const Flexible(
|
||||
child: Text(
|
||||
"Ich nehme die oben genannten Anmerkungen zur Lieferung zur Kenntnis.",
|
||||
overflow: TextOverflow.fade,
|
||||
Flexible(
|
||||
child: InkWell(
|
||||
onTap: _notesEmpty ? null : () {
|
||||
setState(() {
|
||||
_noteAccepted = !_noteAccepted;
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
"Ich nehme die oben genannten Anmerkungen zur Lieferung zur Kenntnis.",
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -177,10 +209,17 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
});
|
||||
},
|
||||
),
|
||||
const Flexible(
|
||||
child: Text(
|
||||
"Ich bestätige, dass ich die Ware im ordnungsgemäßen Zustand erhalten habe und, dass die Aufstell- und Einbauarbeiten korrekt durchgeführt wurden.",
|
||||
overflow: TextOverflow.fade,
|
||||
Flexible(
|
||||
child: InkWell(
|
||||
child: Text(
|
||||
"Ich bestätige, dass ich die Ware im ordnungsgemäßen Zustand erhalten habe und, dass die Aufstell- und Einbauarbeiten korrekt durchgeführt wurden.",
|
||||
overflow: TextOverflow.fade,
|
||||
),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_customerAccepted = !_customerAccepted;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -195,6 +234,16 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
Widget build(BuildContext context) {
|
||||
String formattedDate = DateFormat("dd.MM.yyyy").format(DateTime.now());
|
||||
|
||||
bool isButtonEnabled;
|
||||
if (!_isDriverSigning) {
|
||||
isButtonEnabled =
|
||||
_customerAccepted &&
|
||||
(_noteAccepted || _notesEmpty) &&
|
||||
!_isCustomerSignatureEmpty;
|
||||
} else {
|
||||
isButtonEnabled = !_isDriverSignatureEmpty;
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title:
|
||||
@ -247,9 +296,8 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
child: Center(
|
||||
child: FilledButton(
|
||||
onPressed:
|
||||
!(_customerAccepted && (_noteAccepted || _notesEmpty))
|
||||
? null
|
||||
: () async {
|
||||
isButtonEnabled
|
||||
? () async {
|
||||
if (!_isDriverSigning) {
|
||||
setState(() {
|
||||
_isDriverSigning = true;
|
||||
@ -260,7 +308,8 @@ class _SignatureViewState extends State<SignatureView> {
|
||||
(await _driverController.toPngBytes())!,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
: null,
|
||||
child:
|
||||
!_isDriverSigning
|
||||
? const Text("Weiter")
|
||||
|
||||
@ -4,6 +4,7 @@ import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_event.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_info.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_list.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_overview_custom_sort.dart';
|
||||
import 'package:hl_lieferservice/model/tour.dart';
|
||||
|
||||
import '../../../../model/delivery.dart';
|
||||
@ -11,7 +12,11 @@ import '../../../authentication/bloc/auth_bloc.dart';
|
||||
import '../../../authentication/bloc/auth_state.dart';
|
||||
|
||||
class DeliveryOverview extends StatefulWidget {
|
||||
const DeliveryOverview({super.key, required this.tour, required this.distances});
|
||||
const DeliveryOverview({
|
||||
super.key,
|
||||
required this.tour,
|
||||
required this.distances,
|
||||
});
|
||||
|
||||
final Tour tour;
|
||||
final Map<String, double> distances;
|
||||
@ -44,9 +49,7 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
|
||||
}
|
||||
|
||||
Future<void> _loadTour() async {
|
||||
Authenticated state = context
|
||||
.read<AuthBloc>()
|
||||
.state as Authenticated;
|
||||
Authenticated state = context.read<AuthBloc>().state as Authenticated;
|
||||
context.read<TourBloc>().add(LoadTour(teamId: state.user.number));
|
||||
}
|
||||
|
||||
@ -57,58 +60,47 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children:
|
||||
widget.tour.driver.cars.map((car) {
|
||||
Color? backgroundColor;
|
||||
Color? iconColor = Theme
|
||||
.of(context)
|
||||
.primaryColor;
|
||||
Color? textColor;
|
||||
widget.tour.driver.cars.map((car) {
|
||||
Color? backgroundColor;
|
||||
Color? iconColor = Theme.of(context).primaryColor;
|
||||
Color? textColor;
|
||||
|
||||
if (_selectedCarId == car.id) {
|
||||
backgroundColor = Theme
|
||||
.of(context)
|
||||
.primaryColor;
|
||||
textColor = Theme
|
||||
.of(context)
|
||||
.colorScheme
|
||||
.onSecondary;
|
||||
iconColor = Theme
|
||||
.of(context)
|
||||
.colorScheme
|
||||
.onSecondary;
|
||||
}
|
||||
if (_selectedCarId == car.id) {
|
||||
backgroundColor = Theme.of(context).primaryColor;
|
||||
textColor = Theme.of(context).colorScheme.onSecondary;
|
||||
iconColor = Theme.of(context).colorScheme.onSecondary;
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_selectedCarId = car.id;
|
||||
});
|
||||
},
|
||||
child: Chip(
|
||||
backgroundColor: backgroundColor,
|
||||
label: Row(
|
||||
children: [
|
||||
Icon(Icons.local_shipping, color: iconColor, size: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
child: Text(
|
||||
car.plate,
|
||||
style: TextStyle(color: textColor, fontSize: 12),
|
||||
),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_selectedCarId = car.id;
|
||||
});
|
||||
},
|
||||
child: Chip(
|
||||
backgroundColor: backgroundColor,
|
||||
label: Row(
|
||||
children: [
|
||||
Icon(Icons.local_shipping, color: iconColor, size: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 5),
|
||||
child: Text(
|
||||
car.plate,
|
||||
style: TextStyle(color: textColor, fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RefreshIndicator(
|
||||
@ -118,7 +110,12 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
|
||||
children: [
|
||||
DeliveryInfo(tour: widget.tour),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10, right: 10),
|
||||
padding: const EdgeInsets.only(
|
||||
left: 10,
|
||||
right: 10,
|
||||
top: 15,
|
||||
bottom: 10,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@ -126,10 +123,7 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
|
||||
children: [
|
||||
Text(
|
||||
"Fahrten",
|
||||
style: Theme
|
||||
.of(context)
|
||||
.textTheme
|
||||
.headlineSmall,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -147,25 +141,41 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
|
||||
_deliveries = _deliveries.reversed.toList();
|
||||
});
|
||||
}
|
||||
|
||||
if (value == "custom") {
|
||||
showDialog(
|
||||
context: context,
|
||||
fullscreenDialog: true,
|
||||
builder: (context) => CustomSortDialog(),
|
||||
);
|
||||
}
|
||||
|
||||
if (value == "distance") {
|
||||
// TODO: muss noch implementiert werden
|
||||
}
|
||||
});
|
||||
},
|
||||
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
|
||||
PopupMenuItem<String>(
|
||||
value: 'name-asc',
|
||||
child: Text('Name (A-Z)'),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'name-desc',
|
||||
child: Text('Name (Z-A)'),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'distance',
|
||||
child: Text('Entfernung'),
|
||||
),
|
||||
],
|
||||
itemBuilder:
|
||||
(BuildContext context) => <PopupMenuEntry<String>>[
|
||||
PopupMenuItem<String>(
|
||||
value: 'name-asc',
|
||||
child: Text('Name (A-Z)'),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'name-desc',
|
||||
child: Text('Name (Z-A)'),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'distance',
|
||||
child: Text('Entfernung'),
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
value: 'custom',
|
||||
child: Text('Eigene Sortierung'),
|
||||
),
|
||||
],
|
||||
child: Icon(Icons.filter_list),
|
||||
)
|
||||
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -177,13 +187,13 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
|
||||
child: DeliveryList(
|
||||
distances: widget.distances,
|
||||
deliveries:
|
||||
_deliveries
|
||||
.where(
|
||||
(delivery) =>
|
||||
delivery.carId == _selectedCarId &&
|
||||
delivery.allArticlesScanned(),
|
||||
)
|
||||
.toList(),
|
||||
_deliveries
|
||||
.where(
|
||||
(delivery) =>
|
||||
delivery.carId == _selectedCarId &&
|
||||
delivery.allArticlesScanned(),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@ -0,0 +1,113 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_bloc.dart';
|
||||
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_state.dart';
|
||||
|
||||
class CustomSortDialog extends StatefulWidget {
|
||||
const CustomSortDialog({super.key});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _CustomSortDialogState();
|
||||
}
|
||||
|
||||
class _CustomSortDialogState extends State<CustomSortDialog> {
|
||||
Widget _information() {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: 15),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 15),
|
||||
child: Icon(Icons.info_outline, color: Colors.blueAccent),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"Ziehen Sie die einzelnen Lieferungen mit dem Finger in die gewünschte Position.",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
_sortableList(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _sortableList() {
|
||||
return BlocBuilder<TourBloc, TourState>(
|
||||
builder: (context, state) {
|
||||
final currentState = state;
|
||||
|
||||
if (currentState is TourLoaded) {
|
||||
return Expanded(
|
||||
child: ReorderableListView(
|
||||
onReorder: (oldIndex, newIndex) {},
|
||||
children: currentState.tour.deliveries.indexed.fold([], (
|
||||
acc,
|
||||
current,
|
||||
) {
|
||||
final delivery = current.$2;
|
||||
final index = current.$1;
|
||||
|
||||
acc.add(
|
||||
ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
child: Text(
|
||||
"${index + 1}",
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSecondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text(delivery.customer.name),
|
||||
subtitle: Text(delivery.customer.address.toString(), style: TextStyle(fontSize: 11),),
|
||||
trailing: Icon(Icons.drag_handle),
|
||||
key: Key("reorder-item-${delivery.id}"),
|
||||
),
|
||||
);
|
||||
return acc;
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Center(child: CircularProgressIndicator());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 20, right: 10, top: 15),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Fahrten sortieren",
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Expanded(child: _information()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,12 @@ class _DeliveryOverviewPageState extends State<DeliveryOverviewPage> {
|
||||
if (state is TourLoaded) {
|
||||
final currentState = state;
|
||||
|
||||
return Center(child: DeliveryOverview(tour: currentState.tour, distances: currentState.distances));
|
||||
return Center(
|
||||
child: DeliveryOverview(
|
||||
tour: currentState.tour,
|
||||
distances: currentState.distances,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Container();
|
||||
|
||||
Reference in New Issue
Block a user