update carton filter and merge api for shipment

This commit is contained in:
tzw
2024-03-02 18:15:05 +06:30
parent b1e45debc7
commit c63353636a
22 changed files with 410 additions and 150 deletions

View File

@@ -63,17 +63,6 @@ class _CartonEditorState extends State<CartonEditor> {
_isNew = true;
_selectedCartonType = carton_from_packages;
_cartons = [];
_sender = User(
name: "ptd-phyo44 kaelone",
fcsID: "FCS-8X6V",
phoneNumber: "+959444444444",
id: "48u_4s-HiQeW-HwSqeRd9TSMWh3mLZfSk5rpaUEh_zw");
_consignee = User(
id: "HsIwG88K-0_HSazgEy5QR27kcjkOvfv7_Sr1JP18Q1A",
name: "One One",
phoneNumber: "+959111111111",
fcsID: "FCS-EFRF");
}
if (mounted) {
setState(() {});

View File

@@ -3,11 +3,14 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../domain/constants.dart';
import '../../domain/entities/fcs_shipment.dart';
import '../../domain/entities/user.dart';
import '../../helpers/theme.dart';
import '../../localization/app_translations.dart';
import '../main/util.dart';
import '../widgets/local_text.dart';
import 'model/shipment_selection_model.dart';
import 'widget/shipment_result.dart';
import 'widget/user_search_result.dart';
import 'model/carton_model.dart';
import 'model/consignee_selection_model.dart';
@@ -24,6 +27,8 @@ class _CartonFilterState extends State<CartonFilter> {
String? _selectedStatus;
User? _selectedSender;
User? _selectedConsignee;
FcsShipment? _selectedShipment;
bool _isLoadMoreShipment = false;
List<String> statusList = [
all_status,
@@ -48,11 +53,13 @@ class _CartonFilterState extends State<CartonFilter> {
_selectedStatus = model.filterByStatus ?? all_status;
_selectedConsignee = model.filterByConsingee ?? User(id: all, name: "All");
_selectedSender = model.filterBySender ?? User(id: all, name: "All");
_selectedShipment = model.shipment ?? model.defaultShipment;
init();
super.initState();
}
init() async {
_initShipment();
_initConsignee();
_initSender();
if (mounted) {
@@ -60,6 +67,13 @@ class _CartonFilterState extends State<CartonFilter> {
}
}
_initShipment() async {
await context.read<ShipmentSelectionModel>().refresh();
if (mounted) {
setState(() {});
}
}
_initConsignee() {
var model = context.read<ConsigneeSelectionModel>();
_consigneeCtl.text = model.query;
@@ -109,6 +123,21 @@ class _CartonFilterState extends State<CartonFilter> {
});
}
Future<void> _loadMoreShipment() async {
if (_isLoadMoreShipment) return;
var model = context.read<ShipmentSelectionModel>();
if (model.ended) return;
setState(() {
_isLoadMoreShipment = true;
});
await model.loadMoreData();
setState(() {
_isLoadMoreShipment = false;
});
}
Future<void> _loadMoreSender() async {
if (_isLoadMoreSender) return;
var model = context.read<SenderSelectionModel>();
@@ -130,9 +159,11 @@ class _CartonFilterState extends State<CartonFilter> {
@override
Widget build(BuildContext context) {
var consigneeModel = context.watch<ConsigneeSelectionModel>();
List<User> consignees = consigneeModel.getConsginees;
var senderModel = context.watch<SenderSelectionModel>();
var shipmentModel = context.watch<ShipmentSelectionModel>();
List<User> consignees = consigneeModel.getConsginees;
List<User> senders = senderModel.getSenders;
List<FcsShipment> shipments = shipmentModel.getShipments;
final _titleWidget = SizedBox(
height: 30,
@@ -144,6 +175,9 @@ class _CartonFilterState extends State<CartonFilter> {
labelPadding: const EdgeInsets.all(0),
indicatorPadding: const EdgeInsets.all(0),
tabs: [
Tab(
text: AppTranslations.of(context)?.text("box.fcs_shipment_num"),
),
Tab(
text: AppTranslations.of(context)?.text("box.consignee.title"),
),
@@ -157,6 +191,30 @@ class _CartonFilterState extends State<CartonFilter> {
),
);
final _shipmentWidget = Column(
children: [
Expanded(
child: ShipmentResult(
searchResults: shipments,
isLoading: shipmentModel.isLoading,
noDataLabelKey: 'user.no_consignee',
selectedUser: _selectedShipment,
controller: widget.controller,
isLoadingMore: _isLoadMoreShipment,
onLoadMore: _loadMoreShipment,
onRefresh: () async {
_initShipment();
},
onTap: (a) async {
setState(() {
_selectedShipment = a;
});
},
),
)
],
);
final _consingeeWidget = Column(
children: [
const SizedBox(height: 15),
@@ -335,13 +393,14 @@ class _CartonFilterState extends State<CartonFilter> {
),
Expanded(
child: DefaultTabController(
length: 3,
length: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_titleWidget,
Expanded(
child: TabBarView(children: <Widget>[
_shipmentWidget,
_consingeeWidget,
_senderWidget,
_statusWidget
@@ -428,14 +487,16 @@ class _CartonFilterState extends State<CartonFilter> {
_clearFilter() async {
await context.read<CartonModel>().filterCarton(
User(id: all, name: "All"), User(id: all, name: "All"), all_status);
Navigator.pop(context);
FcsShipment(shipmentNumber: "All shipments", id: all),
User(id: all, name: "All"),
User(id: all, name: "All"),
all_status);
Navigator.pop(context, true);
}
_filter() async {
await context
.read<CartonModel>()
.filterCarton(_selectedConsignee, _selectedSender, _selectedStatus);
Navigator.pop(context);
await context.read<CartonModel>().filterCarton(_selectedShipment,
_selectedConsignee, _selectedSender, _selectedStatus);
Navigator.pop(context, true);
}
}

View File

@@ -8,8 +8,6 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_vector_icons/flutter_vector_icons.dart';
import 'package:provider/provider.dart';
import '../../domain/constants.dart';
import '../../domain/entities/carton.dart';
import '../../pagination/paginator_listview.dart';
import '../carton_search/carton_search.dart';
@@ -38,10 +36,9 @@ class _CartonListState extends State<CartonList> {
_init() async {
var model = context.read<CartonModel>();
_shipments = await context.read<FcsShipmentModel>().getAllShipments();
_shipments.insert(0, FcsShipment(shipmentNumber: "All Shipments", id: all));
_selectedShipment =
model.shipment ?? FcsShipment(shipmentNumber: "All Shipments", id: all);
_shipments = await context.read<FcsShipmentModel>().getShipments();
_shipments.insert(0, model.defaultShipment);
_selectedShipment = model.shipment ?? model.defaultShipment;
model.loadPaginationCartons();
if (mounted) {
@@ -309,7 +306,7 @@ class _CartonListState extends State<CartonList> {
],
),
onPressed: () async {
await showModalBottomSheet(
bool? updated = await showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
@@ -323,6 +320,12 @@ class _CartonListState extends State<CartonList> {
expand: false,
builder: (_, controller) =>
CartonFilter(controller: controller)));
var model = context.read<CartonModel>();
if (updated ?? false) {
setState(() {
_selectedShipment = model.shipment ?? model.defaultShipment;
});
}
});
}

View File

@@ -17,6 +17,8 @@ import 'package:path/path.dart' as Path;
class CartonModel extends BaseModel {
final log = Logger('CartonModel');
var defaultShipment =FcsShipment(shipmentNumber: "All shipments", id: all);
PaginatorListener<Carton>? cartonsByFilter;
PaginatorListener<Carton>? getBoxes;
@@ -56,7 +58,8 @@ class CartonModel extends BaseModel {
_loadPaginationCartons();
}
filterCarton(User? consignee, User? sender, String? status) async {
filterCarton(FcsShipment? fcsShipment, User? consignee, User? sender,
String? status) async {
filterByStatus = status;
if (status == all_status) {
@@ -77,6 +80,12 @@ class CartonModel extends BaseModel {
filterBySender = sender;
}
if (fcsShipment?.id == all) {
shipment = null;
} else {
shipment = fcsShipment;
}
loadPaginationCartons();
notifyListeners();
}

View File

@@ -0,0 +1,75 @@
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:logging/logging.dart';
import '../../../domain/constants.dart';
import '../../main/model/base_model.dart';
class ShipmentSelectionModel extends BaseModel {
final log = Logger("ShipmentSelectionModel");
List<FcsShipment> _shipments = [];
List<FcsShipment> get getShipments {
var list = new List<FcsShipment>.from(_shipments);
return list
..insert(0, FcsShipment(id: all, shipmentNumber: "All shipments"));
}
bool isLoading = false;
DocumentSnapshot? _lastDocument;
bool ended = false;
Future<void> refresh() async {
_shipments.clear();
_lastDocument = null;
ended = false;
await loadMoreData();
notifyListeners();
}
Future<void> loadMoreData() async {
int rowPerPage = 20;
try {
isLoading = true;
String path = "/$fcs_shipment_collection";
Query query = FirebaseFirestore.instance
.collection(path)
.where("status", whereIn: [
fcs_shipment_processing_status,
fcs_shipment_shipped_status,
fcs_shipment_arrived_status,
fcs_shipment_invoiced_status
])
.where("is_deleted", isEqualTo: false)
.orderBy("update_time", descending: true);
if (_lastDocument != null) {
query = query.startAfterDocument(_lastDocument!);
}
QuerySnapshot querySnap = await query.limit(rowPerPage).get();
if (querySnap.docs.isEmpty) return;
_lastDocument = querySnap.docs[querySnap.docs.length - 1];
List<FcsShipment> list = querySnap.docs.map((documentSnapshot) {
var p = FcsShipment.fromMap(
documentSnapshot.data() as Map<String, dynamic>,
documentSnapshot.id);
return p;
}).toList();
_shipments.addAll(list);
if (list.length < rowPerPage) ended = true;
notifyListeners();
} catch (e) {
log.warning("error:$e");
} finally {
isLoading = false;
}
}
}

View File

@@ -13,7 +13,6 @@ import '../widgets/continue_button.dart';
import '../widgets/display_text.dart';
import '../widgets/local_title.dart';
import '../widgets/previous_button.dart';
import 'model/carton_selection_model.dart';
import 'model/package_selection_model.dart';
import 'package_selection_result.dart';
@@ -63,25 +62,26 @@ class _PackageSelectionWidgetState extends State<PackageSelectionWidget> {
_init() {
var searchModel = context.read<PackageSelectionModel>();
searchModel.addDefaultPackages(
shipmentId: widget.shipment.id!,
consigneeId: widget.consignee.id!,
senderId: widget.sender.id!);
searchModel.addSelectedPackage(widget.packages);
_controller.text = searchModel.query;
_query = searchModel.query;
if (mounted) {
setState(() {});
}
}
@override
void didUpdateWidget(covariant PackageSelectionWidget oldWidget) {
_init();
super.didUpdateWidget(oldWidget);
}
// @override
// void didUpdateWidget(covariant PackageSelectionWidget oldWidget) {
// _init();
// super.didUpdateWidget(oldWidget);
// }
Future<void> _loadMoreData() async {
if (_isLoadMore) return;
@@ -278,7 +278,7 @@ class _PackageSelectionWidgetState extends State<PackageSelectionWidget> {
isLoadingMore: _isLoadMore,
onLoadMore: _loadMoreData,
onRefresh: () async {
_init();
_search();
setState(() {
_down = true;
});
@@ -330,9 +330,11 @@ class _PackageSelectionWidgetState extends State<PackageSelectionWidget> {
_search({bool imm = false}) async {
try {
await context
.read<CartonSelectionModel>()
.search(_query, imm: imm, shipmentId: widget.shipment.id!);
await context.read<PackageSelectionModel>().search(_query,
imm: imm,
shipmentId: widget.shipment.id!,
senderId: widget.sender.id!,
consigneeId: widget.consignee.id!);
} catch (e) {
showMsgDialog(context, 'Error', e.toString());
}

View File

@@ -0,0 +1,97 @@
import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:flutter/material.dart';
import '../../../../helpers/theme.dart';
typedef OnAction = Future<void> Function();
class ShipmentResult extends StatelessWidget {
final bool isLoadingMore;
final OnAction onLoadMore;
final OnAction onRefresh;
final Function(FcsShipment)? onTap;
final ScrollController controller;
final FcsShipment? selectedUser;
final List<FcsShipment> searchResults;
final String? noDataLabelKey;
final bool isLoading;
const ShipmentResult(
{super.key,
required this.isLoadingMore,
required this.onLoadMore,
required this.onRefresh,
this.onTap,
required this.controller,
this.selectedUser,
this.searchResults = const [],
this.noDataLabelKey,
this.isLoading = false});
bool _scrollNotification(ScrollNotification scrollInfo) {
if (!isLoadingMore &&
scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
onLoadMore();
}
return true;
}
@override
Widget build(BuildContext context) {
return searchResults.isEmpty && !isLoading
? noDataLabelKey == null
? const SizedBox()
: Center(
child: LocalText(context, noDataLabelKey!,
color: Colors.black, fontSize: 15))
: Column(children: [
Expanded(
child: NotificationListener<ScrollNotification>(
onNotification: _scrollNotification,
child: RefreshIndicator(
color: primaryColor,
onRefresh: () => onRefresh(),
child: ListView.builder(
controller: controller,
shrinkWrap: true,
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (context, index) {
FcsShipment user = searchResults[index];
return ListTile(
onTap: () {
if (onTap != null) {
onTap!(user);
}
},
title: Row(
children: [
Text(user.shipmentNumber ?? "",
style: const TextStyle(
fontSize: 15, color: Colors.black)),
const SizedBox(
width: 20,
),
selectedUser?.id == user.id
? const Icon(
Icons.check,
color: Colors.grey,
)
: const SizedBox()
],
),
);
},
itemCount: searchResults.length)),
)),
Container(
height: isLoadingMore ? 50.0 : 0,
color: Colors.transparent,
child: const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(primaryColor)),
)),
]);
}
}