-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 127 additions & 0 deletions
127
lib/app/pages/orders/orders_qr_scan/orders_qr_scan_page.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:collection/collection.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_bloc/flutter_bloc.dart'; | ||
import 'package:u_app_utils/u_app_utils.dart'; | ||
|
||
import '/app/constants/qr_types.dart'; | ||
import '/app/constants/strings.dart'; | ||
import '/app/constants/style.dart'; | ||
import '/app/data/database.dart'; | ||
import '/app/entities/entities.dart'; | ||
import '/app/pages/shared/page_view_model.dart'; | ||
import '/app/repositories/orders_repository.dart'; | ||
|
||
part 'orders_qr_scan_state.dart'; | ||
part 'orders_qr_scan_view_model.dart'; | ||
|
||
class OrdersQRScanPagePage extends StatelessWidget { | ||
OrdersQRScanPagePage({ | ||
Key? key | ||
}) : super(key: key); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return BlocProvider<OrdersQRScanPageViewModel>( | ||
create: (context) => OrdersQRScanPageViewModel( | ||
RepositoryProvider.of<OrdersRepository>(context), | ||
), | ||
child: _OrdersQRScanPageView(), | ||
); | ||
} | ||
} | ||
|
||
class _OrdersQRScanPageView extends StatefulWidget { | ||
@override | ||
_OrdersQRScanPageViewState createState() => _OrdersQRScanPageViewState(); | ||
} | ||
|
||
class _OrdersQRScanPageViewState extends State<_OrdersQRScanPageView> { | ||
late final ProgressDialog _progressDialog = ProgressDialog(context: context); | ||
|
||
@override | ||
void dispose() { | ||
_progressDialog.close(); | ||
super.dispose(); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return BlocConsumer<OrdersQRScanPageViewModel, OrdersQRScanPageState>( | ||
builder: (context, state) { | ||
OrdersQRScanPageViewModel vm = context.read<OrdersQRScanPageViewModel>(); | ||
|
||
return ScanView( | ||
showScanner: true, | ||
onRead: vm.readQRCode, | ||
child: vm.state.orderScanned.isEmpty ? Container() : DraggableScrollableSheet( | ||
initialChildSize: 0.33, | ||
builder: (BuildContext context, scrollController) { | ||
return Container( | ||
clipBehavior: Clip.hardEdge, | ||
decoration: BoxDecoration( | ||
color: Theme.of(context).canvasColor, | ||
borderRadius: const BorderRadius.only( | ||
topLeft: Radius.circular(25), | ||
topRight: Radius.circular(25), | ||
), | ||
), | ||
child: ListView( | ||
controller: scrollController, | ||
children: [ | ||
ListTile( | ||
trailing: TextButton( | ||
onPressed: () {}, | ||
child: TextButton( | ||
onPressed: vm.confirmOrders, | ||
child: Text( | ||
'Завершить', | ||
style: Style.listTileTitleText.merge(const TextStyle(color: Colors.black)) | ||
) | ||
) | ||
) | ||
), | ||
...vm.state.orderScanned.entries.map((e) => _scannedOrderTile(context, e)) | ||
] | ||
) | ||
); | ||
} | ||
) | ||
); | ||
}, | ||
listener: (context, state) async { | ||
switch (state.status) { | ||
case OrdersQRScanPageStateStatus.inProgress: | ||
await _progressDialog.open(); | ||
break; | ||
case OrdersQRScanPageStateStatus.scanReadFailure: | ||
Misc.showMessage(context, state.message); | ||
break; | ||
case OrdersQRScanPageStateStatus.scanReadFinished: | ||
break; | ||
case OrdersQRScanPageStateStatus.failure: | ||
case OrdersQRScanPageStateStatus.success: | ||
Misc.showMessage(context, state.message); | ||
_progressDialog.close(); | ||
break; | ||
default: | ||
} | ||
} | ||
); | ||
} | ||
|
||
Widget _scannedOrderTile(BuildContext context, MapEntry<OrderEx, List<bool>> entry) { | ||
OrdersQRScanPageViewModel vm = context.read<OrdersQRScanPageViewModel>(); | ||
|
||
return Dismissible( | ||
key: Key(entry.hashCode.toString()), | ||
background: Container(color: Colors.red[500]), | ||
onDismissed: (direction) => vm.removeScannedOrder(entry.key), | ||
child: ListTile( | ||
title: Text('Заказ ${entry.key.order.trackingNumber}'), | ||
trailing: Text('Мест ${entry.value.where((k) => k).length}/${entry.key.order.packages}'), | ||
) | ||
); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
lib/app/pages/orders/orders_qr_scan/orders_qr_scan_state.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
part of 'orders_qr_scan_page.dart'; | ||
|
||
enum OrdersQRScanPageStateStatus { | ||
initial, | ||
dataLoaded, | ||
scanReadFailure, | ||
scanReadFinished, | ||
inProgress, | ||
failure, | ||
success | ||
} | ||
|
||
class OrdersQRScanPageState { | ||
OrdersQRScanPageState({ | ||
this.status = OrdersQRScanPageStateStatus.initial, | ||
this.orderExList = const [], | ||
this.orderScanned = const {}, | ||
this.message = '' | ||
}); | ||
|
||
final OrdersQRScanPageStateStatus status; | ||
final List<OrderEx> orderExList; | ||
final String message; | ||
final Map<OrderEx, List<bool>> orderScanned; | ||
|
||
OrdersQRScanPageState copyWith({ | ||
OrdersQRScanPageStateStatus? status, | ||
Map<OrderEx, List<bool>>? orderScanned, | ||
List<OrderEx>? orderExList, | ||
String? message | ||
}) { | ||
return OrdersQRScanPageState( | ||
status: status ?? this.status, | ||
orderExList: orderExList ?? this.orderExList, | ||
orderScanned: orderScanned ?? this.orderScanned, | ||
message: message ?? this.message | ||
); | ||
} | ||
} |
107 changes: 107 additions & 0 deletions
107
lib/app/pages/orders/orders_qr_scan/orders_qr_scan_view_model.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
part of 'orders_qr_scan_page.dart'; | ||
|
||
class OrdersQRScanPageViewModel extends PageViewModel<OrdersQRScanPageState, OrdersQRScanPageStateStatus> { | ||
static const String qrType = 'ORDER'; | ||
final OrdersRepository ordersRepository; | ||
|
||
StreamSubscription<List<OrderEx>>? orderExListSubscription; | ||
|
||
OrdersQRScanPageViewModel(this.ordersRepository) : super(OrdersQRScanPageState()); | ||
|
||
@override | ||
OrdersQRScanPageStateStatus get status => state.status; | ||
|
||
|
||
@override | ||
Future<void> initViewModel() async { | ||
await super.initViewModel(); | ||
|
||
orderExListSubscription = ordersRepository.watchOrderExList() | ||
.listen((event) { | ||
emit(state.copyWith(status: OrdersQRScanPageStateStatus.dataLoaded, orderExList: event)); | ||
}); | ||
} | ||
|
||
@override | ||
Future<void> close() async { | ||
await super.close(); | ||
|
||
await orderExListSubscription?.cancel(); | ||
} | ||
|
||
Future<void> readQRCode(String? qrCode) async { | ||
if (qrCode == null) return; | ||
|
||
List<String> qrCodeData = qrCode.split(' '); | ||
String version = qrCodeData[0]; | ||
|
||
if (version != Strings.qrCodeVersion) { | ||
emit(state.copyWith( | ||
status: OrdersQRScanPageStateStatus.scanReadFailure, | ||
message: 'Считан не поддерживаемый QR код' | ||
)); | ||
return; | ||
} | ||
|
||
if (qrCodeData[3] != QRType.order.typeName) { | ||
emit(state.copyWith(status: OrdersQRScanPageStateStatus.scanReadFailure, message: 'QR код не от заказа')); | ||
return; | ||
} | ||
|
||
return await _processQR(qrCodeData[4], int.parse(qrCodeData[5])); | ||
} | ||
|
||
Future<void> _processQR(String qrTrackingNumber, int packageNumber) async { | ||
OrdersQRScanPageState newState = state; | ||
|
||
OrderEx? orderEx = state.orderExList.firstWhereOrNull((e) => e.order.trackingNumber == qrTrackingNumber); | ||
|
||
if (orderEx == null) { | ||
emit(state.copyWith(status: OrdersQRScanPageStateStatus.scanReadFailure, message: 'Заказ не найден')); | ||
return; | ||
} | ||
|
||
Map<OrderEx, List<bool>> newOrderScanned = Map.of(state.orderScanned); | ||
List<bool> scannedPackages = newOrderScanned[orderEx] ?? List.generate(orderEx.order.packages, (_) => false); | ||
|
||
if (scannedPackages[packageNumber - 1]) { | ||
emit(state.copyWith(status: OrdersQRScanPageStateStatus.scanReadFailure, message: 'QR код уже был считан')); | ||
return; | ||
} | ||
|
||
scannedPackages[packageNumber - 1] = true; | ||
newOrderScanned[orderEx] = scannedPackages; | ||
emit(newState.copyWith(orderScanned: newOrderScanned, status: OrdersQRScanPageStateStatus.scanReadFinished)); | ||
} | ||
|
||
Future<void> confirmOrders() async { | ||
emit(state.copyWith(status: OrdersQRScanPageStateStatus.inProgress)); | ||
|
||
final fullyScannedOrders = state.orderScanned.entries.where((e) => e.value.none((v) => !v)); | ||
|
||
if (fullyScannedOrders.isEmpty) { | ||
emit(state.copyWith(status: OrdersQRScanPageStateStatus.failure, message: 'Нет заказов для выдачи')); | ||
return; | ||
} | ||
|
||
for (var order in fullyScannedOrders) { | ||
try { | ||
await ordersRepository.confirmOrder(order.key); | ||
|
||
removeScannedOrder(order.key); | ||
} on AppError catch(e) { | ||
emit(state.copyWith(status: OrdersQRScanPageStateStatus.failure, message: e.message)); | ||
return; | ||
} | ||
} | ||
|
||
emit(state.copyWith(status: OrdersQRScanPageStateStatus.success, message: 'Заказы успешно выданы')); | ||
} | ||
|
||
void removeScannedOrder(OrderEx orderEx) { | ||
Map<OrderEx, List<bool>> newOrderScanned = Map.of(state.orderScanned); | ||
newOrderScanned.remove(orderEx); | ||
|
||
emit(state.copyWith(orderScanned: newOrderScanned)); | ||
} | ||
} |