Merge remote-tracking branch 'tzw/master'

This commit is contained in:
phyothandar
2021-09-10 16:54:04 +06:30
52 changed files with 317 additions and 334 deletions

View File

@@ -64,8 +64,9 @@ class Carton {
// String get packageNumber => // String get packageNumber =>
// shipmentNumber + "-" + receiverNumber + " #" + boxNumber; // shipmentNumber + "-" + receiverNumber + " #" + boxNumber;
double get actualWeight => double get actualWeight => cargoTypes == null
cargoTypes == null ? 0 : cargoTypes.fold(0, (p, e) => e.weight + p); ? 0
: cargoTypes.fold(0, (p, e) => e.weight + p);
int getShipmentWeight(double volumetricRatio) { int getShipmentWeight(double volumetricRatio) {
if (length == null || if (length == null ||
@@ -114,8 +115,8 @@ class Carton {
double total = 0; double total = 0;
cargoTypes.forEach((e) { cargoTypes.forEach((e) {
double r = double r = e.rate -
e.rate - (discountByWeight != null ? (discountByWeight.discount) : 0); (discountByWeight != null ? (discountByWeight.discount) : 0);
double amount = e.weight * r; double amount = e.weight * r;
total += amount; total += amount;
}); });

View File

@@ -19,9 +19,7 @@ class Rate {
return discountByWeights.firstWhere((e) => e.weight < weight); return discountByWeights.firstWhere((e) => e.weight < weight);
} }
CargoType? get defaultCargoType => cargoTypes == null CargoType get defaultCargoType => cargoTypes.firstWhere((e) => e.name == "General");
? null
: cargoTypes.firstWhere((e) => e.name == "General");
Rate( Rate(
{this.deliveryFee = 0, {this.deliveryFee = 0,

View File

@@ -59,7 +59,7 @@ class _CargoTableState extends State<CargoTable> {
} }
double total = 0; double total = 0;
var rows = widget.cargoTypes!.map((c) { var rows = widget.cargoTypes!.map((c) {
total += c.weight!; total += c.weight;
return MyDataRow( return MyDataRow(
onSelectChanged: (bool selected) async {}, onSelectChanged: (bool selected) async {},
cells: [ cells: [
@@ -81,7 +81,7 @@ class _CargoTableState extends State<CargoTable> {
), ),
)), )),
MyDataCell( MyDataCell(
Text(c.weight == null ? "0" : c.weight!.toStringAsFixed(2), Text(c.weight == null ? "0" : c.weight.toStringAsFixed(2),
style: textStyle), style: textStyle),
), ),
], ],

View File

@@ -61,7 +61,7 @@ class _CargoTypeAdditionState extends State<CargoTypeAddition> {
child: InkWell( child: InkWell(
onTap: () { onTap: () {
setState(() { setState(() {
c.isChecked = !c.isChecked!; c.isChecked = !c.isChecked;
}); });
}, },
child: Row( child: Row(
@@ -71,7 +71,7 @@ class _CargoTypeAdditionState extends State<CargoTypeAddition> {
activeColor: primaryColor, activeColor: primaryColor,
onChanged: (bool? check) { onChanged: (bool? check) {
setState(() { setState(() {
c.isChecked = check; c.isChecked = check ?? false;
}); });
}), }),
new Text(c.name ?? '', style: textStyle), new Text(c.name ?? '', style: textStyle),
@@ -88,9 +88,9 @@ class _CargoTypeAdditionState extends State<CargoTypeAddition> {
getLocalString(context, 'box.cargo.select.btn'), getLocalString(context, 'box.cargo.select.btn'),
callack: () { callack: () {
List<CargoType> _cargos = List<CargoType> _cargos =
this.cargos.where((c) => c.isChecked!).toList(); this.cargos.where((c) => c.isChecked).toList();
List<CargoType> _scargos = List<CargoType> _scargos =
this.specialCargos.where((c) => c.isChecked!).toList(); this.specialCargos.where((c) => c.isChecked).toList();
_cargos.addAll(_scargos); _cargos.addAll(_scargos);
Navigator.pop(context, _cargos); Navigator.pop(context, _cargos);
}, },

View File

@@ -30,7 +30,7 @@ class _CargoTypeEditorState extends State<CargoTypeEditor> {
super.initState(); super.initState();
if (widget.cargo != null) { if (widget.cargo != null) {
_cargo = widget.cargo; _cargo = widget.cargo;
_weightController.text = _cargo!.weight!.toStringAsFixed(2); _weightController.text = _cargo!.weight.toStringAsFixed(2);
} else { } else {
_loadDefalut(); _loadDefalut();
} }
@@ -39,7 +39,7 @@ class _CargoTypeEditorState extends State<CargoTypeEditor> {
_loadDefalut() { _loadDefalut() {
ShipmentRateModel shipmentRateModel = ShipmentRateModel shipmentRateModel =
Provider.of<ShipmentRateModel>(context, listen: false); Provider.of<ShipmentRateModel>(context, listen: false);
_cargo = shipmentRateModel.rate.defaultCargoType.clone(); _cargo = shipmentRateModel.rate.defaultCargoType?.clone();
} }
@override @override

View File

@@ -33,7 +33,7 @@ class _CargoTableState extends State<CargoTable> {
cargoTypes = widget.cargoTypes; cargoTypes = widget.cargoTypes;
if (!widget.isNew!) { if (!widget.isNew!) {
totalWeight = totalWeight =
cargoTypes!.fold(0, (previous, current) => previous + current.weight!); cargoTypes!.fold(0, (previous, current) => previous + current.weight);
} }
super.initState(); super.initState();
@@ -86,7 +86,7 @@ class _CargoTableState extends State<CargoTable> {
cells: [ cells: [
MyDataCell( MyDataCell(
new Text( new Text(
c.name ??'', c.name ?? '',
style: textStyle, style: textStyle,
), ),
), ),
@@ -144,7 +144,7 @@ class _CargoTableState extends State<CargoTable> {
context: context, context: context,
builder: (_) => DialogInput( builder: (_) => DialogInput(
label: "cargo.weight", label: "cargo.weight",
value: c.weight!.toStringAsFixed(2))); value: c.weight.toStringAsFixed(2)));
if (_t == null) return; if (_t == null) return;
setState(() { setState(() {
@@ -162,7 +162,7 @@ class _CargoTableState extends State<CargoTable> {
borderRadius: BorderRadius.all(Radius.circular(5.0)), borderRadius: BorderRadius.all(Radius.circular(5.0)),
), ),
child: Text( child: Text(
c.weight == null ? "0.00" : c.weight!.toStringAsFixed(2), c.weight == null ? "0.00" : c.weight.toStringAsFixed(2),
style: textStyle), style: textStyle),
), ),
), ),
@@ -252,11 +252,10 @@ class _CargoTableState extends State<CargoTable> {
} }
CargoType? autoCalWeight(List<CargoType> cargoTypes, double total) { CargoType? autoCalWeight(List<CargoType> cargoTypes, double total) {
if ((cargoTypes?.length ?? 0) == 0 || total == 0) return null;
List<CargoType> noWeight = cargoTypes.where((c) => c.weight == 0).toList(); List<CargoType> noWeight = cargoTypes.where((c) => c.weight == 0).toList();
if (noWeight.length != 1) return null; if (noWeight.length != 1) return null;
var _existing = double _existing =
cargoTypes.fold(0, (previous, current) => previous + current.weight); cargoTypes.fold(0, (previous, current) => previous + current.weight);
noWeight[0].weight = total - _existing; noWeight[0].weight = total - _existing;

View File

@@ -1,12 +1,10 @@
import 'package:fcs/domain/entities/cargo_type.dart'; import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/my_data_table.dart'; import 'package:fcs/pages/widgets/my_data_table.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'cargo_type_editor.dart';
import 'total_weight_edit.dart'; import 'total_weight_edit.dart';
typedef OnAdd(CargoType cargoType); typedef OnAdd(CargoType cargoType);
@@ -68,7 +66,7 @@ class _CargoTableState extends State<CargoTable> {
double _total = 0; double _total = 0;
var rows = widget.cargoTypes!.map((c) { var rows = widget.cargoTypes!.map((c) {
_total += c.weight!; _total += c.weight;
return MyDataRow( return MyDataRow(
onSelectChanged: (bool selected) async {}, onSelectChanged: (bool selected) async {},
cells: [ cells: [
@@ -88,7 +86,7 @@ class _CargoTableState extends State<CargoTable> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
Text(c.weight!.toStringAsFixed(2), style: textStyle), Text(c.weight.toStringAsFixed(2), style: textStyle),
widget.onRemove == null widget.onRemove == null
? SizedBox( ? SizedBox(
width: 50, width: 50,

View File

@@ -51,7 +51,7 @@ class _CartonEditorState extends State<CartonEditor> {
TextEditingController _widthController = new TextEditingController(); TextEditingController _widthController = new TextEditingController();
TextEditingController _heightController = new TextEditingController(); TextEditingController _heightController = new TextEditingController();
TextEditingController _lengthController = new TextEditingController(); TextEditingController _lengthController = new TextEditingController();
DeliveryAddress _deliveryAddress = new DeliveryAddress(); DeliveryAddress? _deliveryAddress = new DeliveryAddress();
List<CargoType> _cargoTypes = []; List<CargoType> _cargoTypes = [];
Carton? _carton; Carton? _carton;
@@ -151,12 +151,12 @@ class _CartonEditorState extends State<CartonEditor> {
PackageModel packageModel = PackageModel packageModel =
Provider.of<PackageModel>(context, listen: false); Provider.of<PackageModel>(context, listen: false);
List<Package> packages = await packageModel.getPackages( List<Package> packages = await packageModel.getPackages(
_user!.id, [package_processed_status, package_packed_status]); _user!.id!, [package_processed_status, package_packed_status]);
if (_isNew) { if (_isNew) {
String? prevCompare; String? prevCompare;
packages.forEach((p) { packages.forEach((p) {
String compare = String compare = (p.deliveryAddress?.fullName ?? "") +
(p.deliveryAddress.fullName) + (p.deliveryAddress.phoneNumber); (p.deliveryAddress?.phoneNumber ?? "");
if (prevCompare != null && compare == prevCompare) { if (prevCompare != null && compare == prevCompare) {
p.isChecked = true; p.isChecked = true;
} else { } else {
@@ -195,9 +195,9 @@ class _CartonEditorState extends State<CartonEditor> {
// } // }
_calShipmentWeight() { _calShipmentWeight() {
double l = double.parse(_lengthController.text, (s) => 0); double l = double.parse(_lengthController.text);
double w = double.parse(_widthController.text, (s) => 0); double w = double.parse(_widthController.text);
double h = double.parse(_heightController.text, (s) => 0); double h = double.parse(_heightController.text);
setState(() { setState(() {
shipmentWeight = l * w * h / volumetricRatio; shipmentWeight = l * w * h / volumetricRatio;
}); });
@@ -757,7 +757,7 @@ class _CartonEditorState extends State<CartonEditor> {
.map<DropdownMenuItem<CartonSize>>((CartonSize value) { .map<DropdownMenuItem<CartonSize>>((CartonSize value) {
return DropdownMenuItem<CartonSize>( return DropdownMenuItem<CartonSize>(
value: value, value: value,
child: Text(value.name, child: Text(value.name ?? "",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
color: value.name == MANAGE_CARTONSIZE color: value.name == MANAGE_CARTONSIZE
@@ -863,7 +863,7 @@ class _CartonEditorState extends State<CartonEditor> {
); );
if (_c == null) return; if (_c == null) return;
var cartonModel = Provider.of<CartonModel>(context, listen: false); var cartonModel = Provider.of<CartonModel>(context, listen: false);
Carton _carton = await cartonModel.getCarton(_c.id); Carton _carton = await cartonModel.getCarton(_c.id ?? "");
if (isFromPackages) { if (isFromPackages) {
_cartons.add(_carton); _cartons.add(_carton);
} }
@@ -935,13 +935,13 @@ class _CartonEditorState extends State<CartonEditor> {
showMsgDialog(context, "Error", "Expect at least one cargo type"); showMsgDialog(context, "Error", "Expect at least one cargo type");
return; return;
} }
if (_cargoTypes.where((c) => c.weight! <= 0).isNotEmpty) { if (_cargoTypes.where((c) => c.weight <= 0).isNotEmpty) {
showMsgDialog(context, "Error", "Invalid cargo weight"); showMsgDialog(context, "Error", "Invalid cargo weight");
return; return;
} }
double l = double.parse(_lengthController.text, (s) => 0); double l = double.parse(_lengthController.text);
double w = double.parse(_widthController.text, (s) => 0); double w = double.parse(_widthController.text);
double h = double.parse(_heightController.text, (s) => 0); double h = double.parse(_heightController.text);
if ((l <= 0 || w <= 0 || h <= 0) && (isFromPackages || isFromCartons)) { if ((l <= 0 || w <= 0 || h <= 0) && (isFromPackages || isFromCartons)) {
showMsgDialog(context, "Error", "Invalid dimension"); showMsgDialog(context, "Error", "Invalid dimension");
return; return;

View File

@@ -1,7 +1,5 @@
import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/entities/carton.dart';
import 'package:fcs/domain/entities/carton_size.dart';
import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/domain/entities/package.dart';
import 'package:fcs/domain/vo/delivery_address.dart'; import 'package:fcs/domain/vo/delivery_address.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
@@ -43,7 +41,7 @@ class CartonInfo extends StatefulWidget {
class _CartonInfoState extends State<CartonInfo> { class _CartonInfoState extends State<CartonInfo> {
bool _isLoading = false; bool _isLoading = false;
Carton? _box; Carton? _box;
DeliveryAddress _deliveryAddress = new DeliveryAddress(); DeliveryAddress? _deliveryAddress = new DeliveryAddress();
TextEditingController _widthController = new TextEditingController(); TextEditingController _widthController = new TextEditingController();
TextEditingController _heightController = new TextEditingController(); TextEditingController _heightController = new TextEditingController();
TextEditingController _lengthController = new TextEditingController(); TextEditingController _lengthController = new TextEditingController();
@@ -80,7 +78,7 @@ class _CartonInfoState extends State<CartonInfo> {
_widthController.text = _box!.width.toString(); _widthController.text = _box!.width.toString();
_heightController.text = _box!.height.toString(); _heightController.text = _box!.height.toString();
_lengthController.text = _box!.length.toString(); _lengthController.text = _box!.length.toString();
_cartonSizeController.text = _box!.cartonSizeName; _cartonSizeController.text = _box!.cartonSizeName ?? "";
_deliveryAddress = _box!.deliveryAddress; _deliveryAddress = _box!.deliveryAddress;
isMixBox = _box!.cartonType == carton_mix_box; isMixBox = _box!.cartonType == carton_mix_box;
isFromShipments = _box!.cartonType == carton_from_shipments; isFromShipments = _box!.cartonType == carton_from_shipments;
@@ -101,7 +99,7 @@ class _CartonInfoState extends State<CartonInfo> {
c.width == _box!.width && c.width == _box!.width &&
c.height == _box!.height) { c.height == _box!.height) {
setState(() { setState(() {
_cartonSizeController.text = c.name; _cartonSizeController.text = c.name ?? "";
}); });
} }
}); });
@@ -114,7 +112,8 @@ class _CartonInfoState extends State<CartonInfo> {
return; return;
PackageModel packageModel = PackageModel packageModel =
Provider.of<PackageModel>(context, listen: false); Provider.of<PackageModel>(context, listen: false);
List<Package> packages = await packageModel.getPackages(_box!.userID, [ List<Package> packages =
await packageModel.getPackages(_box!.userID ?? "", [
package_processed_status, package_processed_status,
package_packed_status, package_packed_status,
package_shipped_status, package_shipped_status,
@@ -145,9 +144,9 @@ class _CartonInfoState extends State<CartonInfo> {
} }
_calShipmentWeight() { _calShipmentWeight() {
double l = double.parse(_lengthController.text, (s) => 0); double l = double.parse(_lengthController.text);
double w = double.parse(_widthController.text, (s) => 0); double w = double.parse(_widthController.text);
double h = double.parse(_heightController.text, (s) => 0); double h = double.parse(_heightController.text);
setState(() { setState(() {
shipmentWeight = l * w * h / volumetricRatio; shipmentWeight = l * w * h / volumetricRatio;
}); });
@@ -167,8 +166,9 @@ class _CartonInfoState extends State<CartonInfo> {
final cartonTypeBox = LocalRadioButtons( final cartonTypeBox = LocalRadioButtons(
readOnly: true, readOnly: true,
values: cartonModel.cartonTypesInfo, values: cartonModel.cartonTypesInfo,
selectedValue: selectedValue: (_box!.isShipmentCarton ?? false)
_box!.isShipmentCarton ? carton_from_shipments : _box!.cartonType); ? carton_from_shipments
: _box!.cartonType);
final shipmentBox = DisplayText( final shipmentBox = DisplayText(
text: _box!.fcsShipmentNumber, text: _box!.fcsShipmentNumber,
labelTextKey: "box.fcs_shipment_num", labelTextKey: "box.fcs_shipment_num",
@@ -416,7 +416,7 @@ class _CartonInfoState extends State<CartonInfo> {
); );
if (updated ?? false) { if (updated ?? false) {
var cartonModel = Provider.of<CartonModel>(context, listen: false); var cartonModel = Provider.of<CartonModel>(context, listen: false);
var c = await cartonModel.getCarton(widget.box!.id); var c = await cartonModel.getCarton(widget.box!.id ?? "");
setState(() { setState(() {
_box = c; _box = c;
_loadPackages(); _loadPackages();

View File

@@ -8,8 +8,8 @@ import 'package:intl/intl.dart';
import 'carton_info.dart'; import 'carton_info.dart';
class CartonListRow extends StatelessWidget { class CartonListRow extends StatelessWidget {
final Carton? box; final Carton box;
CartonListRow({Key? key, this.box}) : super(key: key); CartonListRow({Key? key, required this.box}) : super(key: key);
final double dotSize = 15.0; final double dotSize = 15.0;
final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); final DateFormat dateFormat = new DateFormat("dd MMM yyyy");
@@ -47,7 +47,7 @@ class CartonListRow extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: new Text( child: new Text(
box!.cartonNumber , box.cartonNumber ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 15.0, color: Colors.black), fontSize: 15.0, color: Colors.black),
), ),
@@ -55,7 +55,7 @@ class CartonListRow extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10), padding: const EdgeInsets.only(left: 10.0, top: 10),
child: new Text( child: new Text(
box!.userName, box.userName ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 15.0, color: Colors.grey), fontSize: 15.0, color: Colors.grey),
), ),
@@ -71,14 +71,14 @@ class CartonListRow extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
child: getStatus(box!.status == null ? "" : box!.status), child: getStatus(box.status ?? ""),
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
new Text( new Text(
"${box!.cartonWeight.toStringAsFixed(2)} lb", "${box.cartonWeight?.toStringAsFixed(2)} lb",
style: style:
new TextStyle(fontSize: 15.0, color: Colors.grey), new TextStyle(fontSize: 15.0, color: Colors.grey),
), ),

View File

@@ -35,7 +35,7 @@ class CartonMixTable extends StatelessWidget {
? [Container()] ? [Container()]
: cartons!.asMap().entries.map((p) { : cartons!.asMap().entries.map((p) {
return Container( return Container(
color: p.value.isChecked color: (p.value.isChecked ?? false)
? Colors.grey.withOpacity(0.2) ? Colors.grey.withOpacity(0.2)
: Colors.grey.shade50.withOpacity(0.2), : Colors.grey.shade50.withOpacity(0.2),
child: Container( child: Container(
@@ -60,7 +60,7 @@ class CartonMixTable extends StatelessWidget {
}), }),
Expanded( Expanded(
child: new Text( child: new Text(
p.value.cartonNumber, p.value.cartonNumber ?? "",
style: textStyle, style: textStyle,
)), )),
new Text( new Text(

View File

@@ -70,15 +70,15 @@ class CartonPackageTable extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
p.value.trackingID, p.value.trackingID ?? "",
style: textStyle, style: textStyle,
), ),
Text( Text(
p.value.deliveryAddress.fullName, p.value.deliveryAddress?.fullName ?? "",
style: textStyle, style: textStyle,
), ),
Text( Text(
p.value.deliveryAddress.phoneNumber, p.value.deliveryAddress?.phoneNumber ?? "",
style: textStyle, style: textStyle,
), ),
], ],
@@ -88,7 +88,7 @@ class CartonPackageTable extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
new Text( new Text(
p.value.desc, p.value.desc ?? "",
style: textStyle, style: textStyle,
), ),
new Text( new Text(

View File

@@ -8,9 +8,9 @@ import 'package:intl/intl.dart';
typedef OnRemove(Carton carton); typedef OnRemove(Carton carton);
class CartonRow extends StatelessWidget { class CartonRow extends StatelessWidget {
final Carton? box; final Carton box;
final OnRemove? onRemove; final OnRemove? onRemove;
CartonRow({Key? key, this.box, this.onRemove}) : super(key: key); CartonRow({Key? key, required this.box, this.onRemove}) : super(key: key);
final double dotSize = 15.0; final double dotSize = 15.0;
final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); final DateFormat dateFormat = new DateFormat("dd MMM yyyy");
@@ -45,7 +45,7 @@ class CartonRow extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: new Text( child: new Text(
box!.cartonNumber, box.cartonNumber ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 15.0, color: Colors.black), fontSize: 15.0, color: Colors.black),
), ),
@@ -53,7 +53,7 @@ class CartonRow extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10), padding: const EdgeInsets.only(left: 10.0, top: 10),
child: new Text( child: new Text(
box!.userName, box.userName ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 15.0, color: Colors.grey), fontSize: 15.0, color: Colors.grey),
), ),
@@ -75,16 +75,16 @@ class CartonRow extends StatelessWidget {
color: primaryColor, color: primaryColor,
), ),
onPressed: () { onPressed: () {
if (onRemove != null) onRemove!(box!); if (onRemove != null) onRemove!(box);
}), }),
box!.actualWeight == 0 box.actualWeight == 0
? Container() ? Container()
: Padding( : Padding(
padding: const EdgeInsets.only(left: 8.0, bottom: 5), padding: const EdgeInsets.only(left: 8.0, bottom: 5),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
new Text( new Text(
"${box!.actualWeight.toStringAsFixed(2)} lb", "${box.actualWeight.toStringAsFixed(2)} lb",
style: new TextStyle( style: new TextStyle(
fontSize: 15.0, color: Colors.grey), fontSize: 15.0, color: Colors.grey),
), ),

View File

@@ -12,7 +12,7 @@ import 'package:logging/logging.dart';
class CartonModel extends BaseModel { class CartonModel extends BaseModel {
List<Carton> _boxes = []; List<Carton> _boxes = [];
PaginatorListener? cartonsByFilter; late PaginatorListener<Carton> cartonsByFilter;
final log = Logger('CartonModel'); final log = Logger('CartonModel');
List<Carton> get boxes => _selectedIndex == 1 List<Carton> get boxes => _selectedIndex == 1
@@ -24,8 +24,8 @@ class CartonModel extends BaseModel {
int _selectedIndexFilter = 1; int _selectedIndexFilter = 1;
bool isLoading = false; bool isLoading = false;
StreamSubscription<QuerySnapshot> listener; StreamSubscription<QuerySnapshot>? listener;
StreamSubscription<QuerySnapshot> cartonListener; StreamSubscription<QuerySnapshot>? cartonListener;
static List<ShipmentStatus> statusHistory = [ static List<ShipmentStatus> statusHistory = [
ShipmentStatus(status: "Packed", date: DateTime(2020, 6, 1), done: true), ShipmentStatus(status: "Packed", date: DateTime(2020, 6, 1), done: true),
ShipmentStatus(status: "Shipped", date: DateTime(2020, 6, 5), done: false), ShipmentStatus(status: "Shipped", date: DateTime(2020, 6, 5), done: false),
@@ -101,7 +101,7 @@ class CartonModel extends BaseModel {
@override @override
void privilegeChanged() { void privilegeChanged() {
if (user != null || !user.hasCarton()) { if (user != null || !user!.hasCarton()) {
_initData(); _initData();
} }
} }
@@ -119,12 +119,12 @@ class CartonModel extends BaseModel {
} }
Future<void> _loadBoxes() async { Future<void> _loadBoxes() async {
if (user == null || !user.hasCarton()) return; if (user == null || !user!.hasCarton()) return;
String path = "/$cartons_collection/"; String path = "/$cartons_collection/";
if (listener != null) listener.cancel(); if (listener != null) listener!.cancel();
_boxes = []; _boxes = [];
try { try {
listener = Firestore.instance listener = FirebaseFirestore.instance
.collection("$path") .collection("$path")
.where("status", .where("status",
whereIn: [carton_packed_status, carton_shipped_status]) whereIn: [carton_packed_status, carton_shipped_status])
@@ -133,9 +133,10 @@ class CartonModel extends BaseModel {
.snapshots() .snapshots()
.listen((QuerySnapshot snapshot) { .listen((QuerySnapshot snapshot) {
_boxes.clear(); _boxes.clear();
_boxes = snapshot.documents.map((documentSnapshot) { _boxes = snapshot.docs.map((documentSnapshot) {
var s = Carton.fromMap( var s = Carton.fromMap(
documentSnapshot.data, documentSnapshot.documentID); documentSnapshot.data() as Map<String, dynamic>,
documentSnapshot.id);
return s; return s;
}).toList(); }).toList();
notifyListeners(); notifyListeners();
@@ -146,18 +147,18 @@ class CartonModel extends BaseModel {
} }
Future<void> _loadCartonsByFilter(String orderName) async { Future<void> _loadCartonsByFilter(String orderName) async {
if (user == null || !user.hasCarton()) return null; if (user == null || !user!.hasCarton()) return null;
String path = "/$cartons_collection"; String path = "/$cartons_collection";
try { try {
Query listenerQuery = Firestore.instance Query listenerQuery = FirebaseFirestore.instance
.collection("$path") .collection("$path")
.where("carton_type", whereIn: [ .where("carton_type", whereIn: [
carton_from_packages, carton_from_packages,
carton_from_cartons carton_from_cartons
]).where("status", isEqualTo: carton_packed_status); ]).where("status", isEqualTo: carton_packed_status);
Query pageQuery = Firestore.instance Query pageQuery = FirebaseFirestore.instance
.collection("$path") .collection("$path")
.where("carton_type", .where("carton_type",
whereIn: [carton_from_packages, carton_from_cartons]) whereIn: [carton_from_packages, carton_from_cartons])
@@ -171,10 +172,10 @@ class CartonModel extends BaseModel {
} }
} }
Paginator _getDelivered() { Paginator? _getDelivered() {
if (user == null || !user.hasCarton()) return null; if (user == null || !user!.hasCarton()) return null;
var pageQuery = Firestore.instance var pageQuery = FirebaseFirestore.instance
.collection("/$cartons_collection") .collection("/$cartons_collection")
.where("is_delivered", isEqualTo: true) .where("is_delivered", isEqualTo: true)
.where("is_deleted", isEqualTo: false); .where("is_deleted", isEqualTo: false);
@@ -185,10 +186,10 @@ class CartonModel extends BaseModel {
} }
Future<void> loadMore() async { Future<void> loadMore() async {
if (_delivered.ended || selectedIndex == 1) return; if (_delivered == null && _delivered!.ended || selectedIndex == 1) return;
isLoading = true; isLoading = true;
notifyListeners(); notifyListeners();
await _delivered.load(onFinished: () { await _delivered!.load(onFinished: () {
isLoading = false; isLoading = false;
notifyListeners(); notifyListeners();
}); });
@@ -196,7 +197,7 @@ class CartonModel extends BaseModel {
Future<void> refresh() async { Future<void> refresh() async {
if (selectedIndex == 1) return; if (selectedIndex == 1) return;
await _delivered.refresh(onFinished: () { await _delivered?.refresh(onFinished: () {
notifyListeners(); notifyListeners();
}); });
} }
@@ -207,69 +208,62 @@ class CartonModel extends BaseModel {
@override @override
logout() async { logout() async {
if (listener != null) await listener.cancel(); if (listener != null) await listener!.cancel();
if (cartonListener != null) await cartonListener.cancel(); if (cartonListener != null) await cartonListener!.cancel();
if (_delivered != null) _delivered.close(); if (_delivered != null) _delivered!.close();
if (cartonsByFilter != null) cartonsByFilter.close(); if (cartonsByFilter != null) cartonsByFilter.close();
_boxes = []; _boxes = [];
} }
Future<List<Carton>> getCartons(String shipmentID) async { Future<List<Carton>> getCartons(String shipmentID) async {
String path = "/$cartons_collection"; String path = "/$cartons_collection";
var querySnap = await Firestore.instance var querySnap = await FirebaseFirestore.instance
.collection(path) .collection(path)
.where("shipment_id", isEqualTo: shipmentID) .where("shipment_id", isEqualTo: shipmentID)
.getDocuments(); .get();
return querySnap.documents return querySnap.docs.map((e) => Carton.fromMap(e.data(), e.id)).toList();
.map((e) => Carton.fromMap(e.data, e.documentID))
.toList();
} }
Future<List<Carton>> getCartonsByFcsShipment(String fcsShipmentID) async { Future<List<Carton>> getCartonsByFcsShipment(String fcsShipmentID) async {
String path = "/$cartons_collection"; String path = "/$cartons_collection";
var querySnap = await Firestore.instance var querySnap = await FirebaseFirestore.instance
.collection(path) .collection(path)
.where("fcs_shipment_id", isEqualTo: fcsShipmentID) .where("fcs_shipment_id", isEqualTo: fcsShipmentID)
.where("is_deleted", isEqualTo: false) .where("is_deleted", isEqualTo: false)
.getDocuments(); .get();
return querySnap.documents return querySnap.docs.map((e) => Carton.fromMap(e.data(), e.id)).toList();
.map((e) => Carton.fromMap(e.data, e.documentID))
.toList();
} }
Future<List<Carton>> getCartonsForInvoice( Future<List<Carton>> getCartonsForInvoice(
String fcsShipmentID, String userID) async { String fcsShipmentID, String userID) async {
String path = "/$cartons_collection"; String path = "/$cartons_collection";
var querySnap = await Firestore.instance var querySnap = await FirebaseFirestore.instance
.collection(path) .collection(path)
.where("fcs_shipment_id", isEqualTo: fcsShipmentID) .where("fcs_shipment_id", isEqualTo: fcsShipmentID)
.where("user_id", isEqualTo: userID) .where("user_id", isEqualTo: userID)
.where("is_deleted", isEqualTo: false) .where("is_deleted", isEqualTo: false)
.where("is_invoiced", isEqualTo: false) .where("is_invoiced", isEqualTo: false)
.getDocuments(); .get();
List<Carton> cartons = querySnap.documents List<Carton> cartons =
.map((e) => Carton.fromMap(e.data, e.documentID)) querySnap.docs.map((e) => Carton.fromMap(e.data(), e.id)).toList();
.toList();
return cartons; return cartons;
} }
Future<List<Carton>> getMixCartonsByFcsShipment(String fcsShipmentID) async { Future<List<Carton>> getMixCartonsByFcsShipment(String fcsShipmentID) async {
String path = "/$cartons_collection"; String path = "/$cartons_collection";
var querySnap = await Firestore.instance var querySnap = await FirebaseFirestore.instance
.collection(path) .collection(path)
.where("fcs_shipment_id", isEqualTo: fcsShipmentID) .where("fcs_shipment_id", isEqualTo: fcsShipmentID)
.where("carton_type", isEqualTo: carton_mix_box) .where("carton_type", isEqualTo: carton_mix_box)
.where("is_deleted", isEqualTo: false) .where("is_deleted", isEqualTo: false)
.getDocuments(); .get();
return querySnap.documents return querySnap.docs.map((e) => Carton.fromMap(e.data(), e.id)).toList();
.map((e) => Carton.fromMap(e.data, e.documentID))
.toList();
} }
Future<Carton> getCarton(String id) async { Future<Carton> getCarton(String id) async {
String path = "/$cartons_collection"; String path = "/$cartons_collection";
var snap = await Firestore.instance.collection(path).document(id).get(); var snap = await FirebaseFirestore.instance.collection(path).doc(id).get();
return Carton.fromMap(snap.data, snap.documentID); return Carton.fromMap(snap.data() as Map<String, dynamic>, snap.id);
} }
Future<Carton> createCarton(Carton carton) { Future<Carton> createCarton(Carton carton) {

View File

@@ -8,12 +8,9 @@ import 'package:fcs/domain/vo/delivery_address.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/carton_size/carton_size_list.dart'; import 'package:fcs/pages/carton_size/carton_size_list.dart';
import 'package:fcs/pages/carton_size/model/carton_size_model.dart'; import 'package:fcs/pages/carton_size/model/carton_size_model.dart';
import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart';
import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/rates/model/shipment_rate_model.dart';
import 'package:fcs/pages/widgets/defalut_delivery_address.dart'; import 'package:fcs/pages/widgets/defalut_delivery_address.dart';
import 'package:fcs/pages/widgets/delivery_address_selection.dart'; import 'package:fcs/pages/widgets/delivery_address_selection.dart';
import 'package:fcs/pages/widgets/display_text.dart';
import 'package:fcs/pages/widgets/length_picker.dart'; import 'package:fcs/pages/widgets/length_picker.dart';
import 'package:fcs/pages/widgets/local_button.dart'; import 'package:fcs/pages/widgets/local_button.dart';
import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_text.dart';
@@ -45,7 +42,7 @@ class _PackageCartonEditorState extends State<PackageCartonEditor> {
Carton? _carton; Carton? _carton;
bool _isLoading = false; bool _isLoading = false;
DeliveryAddress _deliveryAddress = new DeliveryAddress(); DeliveryAddress? _deliveryAddress = new DeliveryAddress();
List<CargoType> _cargoTypes = []; List<CargoType> _cargoTypes = [];
CartonSize? selectedCatonSize; CartonSize? selectedCatonSize;
bool isFromPackages = false; bool isFromPackages = false;
@@ -263,7 +260,7 @@ class _PackageCartonEditorState extends State<PackageCartonEditor> {
.map<DropdownMenuItem<CartonSize>>((CartonSize value) { .map<DropdownMenuItem<CartonSize>>((CartonSize value) {
return DropdownMenuItem<CartonSize>( return DropdownMenuItem<CartonSize>(
value: value, value: value,
child: Text(value.name, child: Text(value.name ?? "",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
color: value.name == MANAGE_CARTONSIZE color: value.name == MANAGE_CARTONSIZE
@@ -354,7 +351,7 @@ class _PackageCartonEditorState extends State<PackageCartonEditor> {
Navigator.pop(context, _c); Navigator.pop(context, _c);
} else { } else {
await cartonModel.updateCarton(carton); await cartonModel.updateCarton(carton);
Carton _c = await cartonModel.getCarton(_carton!.id); Carton _c = await cartonModel.getCarton(_carton!.id!);
Navigator.pop(context, _c); Navigator.pop(context, _c);
} }
} catch (e) { } catch (e) {

View File

@@ -17,7 +17,7 @@ Widget getCartonNumberStatus(BuildContext context, Carton carton) {
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Chip(label: Text(carton.status)), child: Chip(label: Text(carton.status??"")),
), ),
], ],
); );

View File

@@ -5,27 +5,15 @@ import 'package:flutter_vector_icons/flutter_vector_icons.dart';
import 'carton_search.dart'; import 'carton_search.dart';
class CartonListRow extends StatefulWidget { class CartonListRow extends StatelessWidget {
final CallbackCartonSelect? callbackCartonSelect; final CallbackCartonSelect? callbackCartonSelect;
final Carton? carton; final Carton carton;
// const CartonListRow({this.carton, this.callbackCartonSelect}); // const CartonListRow({this.carton, this.callbackCartonSelect});
CartonListRow( CartonListRow({Key? key, required this.carton, this.callbackCartonSelect})
{Key? key, this.carton, this.callbackCartonSelect})
: super(key: key); : super(key: key);
@override
_CartonListRowState createState() => _CartonListRowState();
}
class _CartonListRowState extends State<CartonListRow> {
final double dotSize = 15.0; final double dotSize = 15.0;
Carton? _carton;
@override
void initState() {
super.initState();
this._carton = widget.carton;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -38,8 +26,7 @@ class _CartonListRowState extends State<CartonListRow> {
child: InkWell( child: InkWell(
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
if (widget.callbackCartonSelect != null) if (callbackCartonSelect != null) callbackCartonSelect!(carton);
widget.callbackCartonSelect!(widget.carton!);
}, },
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
@@ -64,7 +51,7 @@ class _CartonListRowState extends State<CartonListRow> {
Padding( Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: new Text( child: new Text(
_carton!.cartonNumber, carton.cartonNumber ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 15.0, color: Colors.black), fontSize: 15.0, color: Colors.black),
), ),
@@ -72,7 +59,7 @@ class _CartonListRowState extends State<CartonListRow> {
Padding( Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10), padding: const EdgeInsets.only(left: 10.0, top: 10),
child: new Text( child: new Text(
_carton!.userName, carton.userName ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 15.0, color: Colors.grey), fontSize: 15.0, color: Colors.grey),
), ),
@@ -86,7 +73,7 @@ class _CartonListRowState extends State<CartonListRow> {
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
new Text( new Text(
"${_carton!.cartonWeight.toStringAsFixed(2)} lb", "${carton.cartonWeight?.toStringAsFixed(2)} lb",
style: new TextStyle( style: new TextStyle(
fontSize: 15.0, color: Colors.grey), fontSize: 15.0, color: Colors.grey),
), ),

View File

@@ -36,7 +36,7 @@ class _CartonSizeEditorState extends State<CartonSizeEditor> {
if (widget.cartonSize != null) { if (widget.cartonSize != null) {
_cartonSize = widget.cartonSize; _cartonSize = widget.cartonSize;
_isNew = false; _isNew = false;
_nameController.text = _cartonSize!.name; _nameController.text = _cartonSize!.name ?? "";
_widthController.text = _cartonSize!.width.toString(); _widthController.text = _cartonSize!.width.toString();
_heightController.text = _cartonSize!.height.toString(); _heightController.text = _cartonSize!.height.toString();
_lengthController.text = _cartonSize!.length.toString(); _lengthController.text = _cartonSize!.length.toString();

View File

@@ -40,7 +40,7 @@ class _CartonSizeListState extends State<CartonSizeList> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
new Text( new Text(
p.name, p.name ?? "",
style: TextStyle(fontSize: 15.0), style: TextStyle(fontSize: 15.0),
), ),
Padding( Padding(
@@ -135,7 +135,7 @@ class _CartonSizeListState extends State<CartonSizeList> {
CartonSizeModel cartonSizeModel = CartonSizeModel cartonSizeModel =
Provider.of<CartonSizeModel>(context, listen: false); Provider.of<CartonSizeModel>(context, listen: false);
try { try {
await cartonSizeModel.deleteCartonSize(cartonSize.id); await cartonSizeModel.deleteCartonSize(cartonSize.id!);
} catch (e) { } catch (e) {
showMsgDialog(context, "Error", e.toString()); showMsgDialog(context, "Error", e.toString());
} finally { } finally {

View File

@@ -13,7 +13,7 @@ class CartonSizeModel extends BaseModel {
List<CartonSize> cartonSizes = []; List<CartonSize> cartonSizes = [];
final log = Logger('CartonSizeModel'); final log = Logger('CartonSizeModel');
StreamSubscription<QuerySnapshot> listener; StreamSubscription<QuerySnapshot>? listener;
List<CartonSize> get getCartonSizes { List<CartonSize> get getCartonSizes {
var _cartonSizes = new List<CartonSize>.from(cartonSizes); var _cartonSizes = new List<CartonSize>.from(cartonSizes);
@@ -27,17 +27,18 @@ class CartonSizeModel extends BaseModel {
Future<void> _loadCartonSizes() async { Future<void> _loadCartonSizes() async {
try { try {
if (listener != null) listener.cancel(); if (listener != null) listener!.cancel();
listener = Firestore.instance listener = FirebaseFirestore.instance
.collection( .collection(
"/$config_collection/$setting_doc_id/$carton_sizes_collection") "/$config_collection/$setting_doc_id/$carton_sizes_collection")
.snapshots() .snapshots()
.listen((QuerySnapshot snapshot) { .listen((QuerySnapshot snapshot) {
cartonSizes.clear(); cartonSizes.clear();
cartonSizes = snapshot.documents.map((documentSnapshot) { cartonSizes = snapshot.docs.map((documentSnapshot) {
var c = CartonSize.fromMap( var c = CartonSize.fromMap(
documentSnapshot.data, documentSnapshot.documentID); documentSnapshot.data() as Map<String, dynamic>,
documentSnapshot.id);
return c; return c;
}).toList(); }).toList();
notifyListeners(); notifyListeners();
@@ -49,7 +50,7 @@ class CartonSizeModel extends BaseModel {
@override @override
logout() async { logout() async {
if (listener != null) await listener.cancel(); if (listener != null) await listener!.cancel();
cartonSizes = []; cartonSizes = [];
} }

View File

@@ -2,7 +2,6 @@ import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/package/package_info.dart'; import 'package:fcs/pages/package/package_info.dart';
import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
@@ -14,18 +13,18 @@ typedef CallbackOnViewDetail();
class Bubble extends StatelessWidget { class Bubble extends StatelessWidget {
Bubble( Bubble(
{this.message, {this.message,
this.date, required this.date,
this.delivered, required this.delivered,
this.isMine, required this.isMine,
this.sender, this.sender,
this.isSystem, required this.isSystem,
this.isCustomer, required this.isCustomer,
this.showDate, required this.showDate,
this.callbackOnViewDetail}); this.callbackOnViewDetail});
final CallbackOnViewDetail callbackOnViewDetail; final CallbackOnViewDetail? callbackOnViewDetail;
final DateTime date; final DateTime date;
final String message, sender; final String? message, sender;
final bool delivered, isMine, isSystem, isCustomer, showDate; final bool delivered, isMine, isSystem, isCustomer, showDate;
@override @override
@@ -84,7 +83,7 @@ class Bubble extends StatelessWidget {
fontWeight: FontWeight.bold))) fontWeight: FontWeight.bold)))
] ]
: [ : [
Text(isCustomer ? "FCS Team" : sender, Text(isCustomer ? "FCS Team" : sender ?? "",
style: TextStyle( style: TextStyle(
color: Colors.black38, color: Colors.black38,
fontSize: 10.0, fontSize: 10.0,
@@ -102,8 +101,8 @@ class Bubble extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: EdgeInsets.only(right: 48.0), padding: EdgeInsets.only(right: 48.0),
child: Text(message, child: Text(message ?? "",
style: hasUnicode(message) style: hasUnicode(message ?? "")
? newLabelStyleMM(color: primaryColor) ? newLabelStyleMM(color: primaryColor)
: newLabelStyle(color: primaryColor))), : newLabelStyle(color: primaryColor))),
Positioned( Positioned(
@@ -130,6 +129,6 @@ class Bubble extends StatelessWidget {
} }
_viewDetail() { _viewDetail() {
if (callbackOnViewDetail != null) callbackOnViewDetail(); if (callbackOnViewDetail != null) callbackOnViewDetail!();
} }
} }

View File

@@ -21,14 +21,17 @@ import 'package:provider/provider.dart';
import 'bubble.dart'; import 'bubble.dart';
class MessageDetail extends StatelessWidget { class MessageDetail extends StatelessWidget {
final String receiverName; final String? receiverName;
final String receiverID; final String? receiverID;
final MessageModel messageModel; final MessageModel messageModel;
final TextEditingController textEditingController = TextEditingController(); final TextEditingController textEditingController = TextEditingController();
final ScrollController listScrollController = ScrollController(); final ScrollController listScrollController = ScrollController();
MessageDetail( MessageDetail(
{Key key, this.messageModel, this.receiverName, this.receiverID}) {Key? key,
required this.messageModel,
this.receiverName,
this.receiverID})
: super(key: key) { : super(key: key) {
listScrollController.addListener(() { listScrollController.addListener(() {
if (listScrollController.offset >= if (listScrollController.offset >=
@@ -44,7 +47,7 @@ class MessageDetail extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String userID = Provider.of<MessageModel>(context).user.id; String userID = Provider.of<MessageModel>(context).user?.id ?? "";
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
@@ -96,8 +99,8 @@ class MessageDetail extends StatelessWidget {
Widget buildBubble(Message msg, String userID, bool showDate, Widget buildBubble(Message msg, String userID, bool showDate,
CallbackOnViewDetail callback) { CallbackOnViewDetail callback) {
return Bubble( return Bubble(
message: msg.message, message: msg.message ?? "",
date: msg.date, date: msg.date!,
delivered: true, delivered: true,
sender: msg.senderName, sender: msg.senderName,
isMine: msg.senderID == userID || msg.receiverID == receiverID, isMine: msg.senderID == userID || msg.receiverID == receiverID,
@@ -117,8 +120,8 @@ class MessageDetail extends StatelessWidget {
child: Container( child: Container(
child: TextField( child: TextField(
onSubmitted: (value) { onSubmitted: (value) {
Provider.of<MessageModel>(context, listen: false) Provider.of<MessageModel>(context, listen: false).sendMessage(
.sendMessage(textEditingController.text, receiverID); textEditingController.text, receiverID ?? "");
textEditingController.text = ""; textEditingController.text = "";
}, },
style: TextStyle(color: primaryColor, fontSize: 15.0), style: TextStyle(color: primaryColor, fontSize: 15.0),
@@ -152,8 +155,8 @@ class MessageDetail extends StatelessWidget {
child: IconButton( child: IconButton(
icon: Icon(Icons.send), icon: Icon(Icons.send),
onPressed: () { onPressed: () {
Provider.of<MessageModel>(context, listen: false) Provider.of<MessageModel>(context, listen: false).sendMessage(
.sendMessage(textEditingController.text, receiverID); textEditingController.text, receiverID ?? "");
textEditingController.text = ""; textEditingController.text = "";
}, },
color: primaryColor, color: primaryColor,
@@ -165,7 +168,8 @@ class MessageDetail extends StatelessWidget {
), ),
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.grey[700], width: 0.5)), border:
Border(top: BorderSide(color: Colors.grey.shade700, width: 0.5)),
color: Colors.white), color: Colors.white),
); );
} }
@@ -176,7 +180,7 @@ class MessageDetail extends StatelessWidget {
message.messageID != "") { message.messageID != "") {
PackageModel packageModel = PackageModel packageModel =
Provider.of<PackageModel>(context, listen: false); Provider.of<PackageModel>(context, listen: false);
Package p = await packageModel.getPackage(message.messageID); Package p = await packageModel.getPackage(message.messageID!);
if (p == null) return; if (p == null) return;
Navigator.push<bool>(context, Navigator.push<bool>(context,
CupertinoPageRoute(builder: (context) => PackageInfo(package: p))); CupertinoPageRoute(builder: (context) => PackageInfo(package: p)));
@@ -186,7 +190,7 @@ class MessageDetail extends StatelessWidget {
message.messageID != "") { message.messageID != "") {
MainModel mainModel = Provider.of<MainModel>(context, listen: false); MainModel mainModel = Provider.of<MainModel>(context, listen: false);
if (mainModel.user.isCustomer()) { if (mainModel.user?.isCustomer() ?? false) {
Navigator.push<bool>( Navigator.push<bool>(
context, CupertinoPageRoute(builder: (context) => Profile())); context, CupertinoPageRoute(builder: (context) => Profile()));
} else { } else {
@@ -202,7 +206,7 @@ class MessageDetail extends StatelessWidget {
message.messageID != "") { message.messageID != "") {
ShipmentModel shipmentModel = ShipmentModel shipmentModel =
Provider.of<ShipmentModel>(context, listen: false); Provider.of<ShipmentModel>(context, listen: false);
Shipment s = await shipmentModel.getShipment(message.messageID); Shipment s = await shipmentModel.getShipment(message.messageID!);
if (s == null) return; if (s == null) return;
await Navigator.push<bool>( await Navigator.push<bool>(
context, context,

View File

@@ -10,45 +10,46 @@ import 'package:logging/logging.dart';
class MessageModel extends BaseModel { class MessageModel extends BaseModel {
final log = Logger('MessageModel'); final log = Logger('MessageModel');
List<Message> messages; List<Message> messages = [];
@override @override
logout() async { logout() async {
if (listener != null) await listener.cancel(); if (listener != null) await listener!.cancel();
messages = []; messages = [];
} }
Query query; late Query query;
DocumentSnapshot prevSnap; DocumentSnapshot? prevSnap;
bool isEnded; late bool isEnded;
bool isLoading; late bool isLoading;
String userID; String? userID;
StreamSubscription<QuerySnapshot> listener; StreamSubscription<QuerySnapshot>? listener;
static const int rowPerLoad = 20; static const int rowPerLoad = 20;
void initQuery(String? userID) { void initQuery(String? userID) {
if(userID == null)return; if (userID == null) return;
this.messages = []; this.messages = [];
this.userID = userID; this.userID = userID;
this.prevSnap = null; this.prevSnap = null;
query = Firestore.instance query = FirebaseFirestore.instance
.collection("$user_collection/$userID/$messages_collection") .collection("$user_collection/$userID/$messages_collection")
.orderBy('date', descending: true); .orderBy('date', descending: true);
load(); load();
} }
Future<void> load() async { Future<void> load() async {
if (prevSnap == null) return;
Query _query = Query _query =
prevSnap != null ? query.startAfterDocument(prevSnap) : query; prevSnap != null ? query.startAfterDocument(prevSnap!) : query;
QuerySnapshot snapshot = QuerySnapshot snapshot =
await _query.limit(rowPerLoad).getDocuments(source: Source.server); await _query.limit(rowPerLoad).get(GetOptions(source: Source.server));
int count = snapshot.documents.length; int count = snapshot.docs.length;
isEnded = count < rowPerLoad; isEnded = count < rowPerLoad;
prevSnap = count > 0 ? snapshot.documents[count - 1] : prevSnap; prevSnap = count > 0 ? snapshot.docs[count - 1] : prevSnap;
snapshot.documents.forEach((e) { snapshot.docs.forEach((e) {
messages.add(Message.fromMap(e.data, e.documentID)); messages.add(Message.fromMap(e.data() as Map<String, dynamic>, e.id));
if (messages.length == 1) { if (messages.length == 1) {
_initListener(e); _initListener(e);
} }
@@ -57,20 +58,22 @@ class MessageModel extends BaseModel {
} }
void _initListener(DocumentSnapshot snap) { void _initListener(DocumentSnapshot snap) {
if (listener != null) listener.cancel(); if (listener != null) listener!.cancel();
listener = Firestore.instance listener = FirebaseFirestore.instance
.collection("$user_collection/$userID/$messages_collection") .collection("$user_collection/$userID/$messages_collection")
.endBeforeDocument(snap) .endBeforeDocument(snap)
.orderBy('date', descending: true) .orderBy('date', descending: true)
.snapshots(includeMetadataChanges: true) .snapshots(includeMetadataChanges: true)
.listen((qs) { .listen((qs) {
qs.documentChanges.forEach((c) { qs.docChanges.forEach((c) {
switch (c.type) { switch (c.type) {
case DocumentChangeType.added: case DocumentChangeType.added:
log.info("added!! $c"); log.info("added!! $c");
messages.insert( messages.insert(
0, Message.fromMap(c.document.data, c.document.documentID)); 0,
Message.fromMap(
c.doc.data() as Map<String, dynamic>, c.doc.id));
notifyListeners(); notifyListeners();
break; break;
case DocumentChangeType.modified: case DocumentChangeType.modified:

View File

@@ -21,7 +21,8 @@ class ContactPage extends StatefulWidget {
class _ContactPageState extends State<ContactPage> { class _ContactPageState extends State<ContactPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Setting setting = Provider.of<MainModel>(context).setting; Setting? setting = Provider.of<MainModel>(context).setting;
if (setting == null) return Container();
bool isEditable = context.select((MainModel m) => m.contactEditable()); bool isEditable = context.select((MainModel m) => m.contactEditable());
return Scaffold( return Scaffold(
@@ -61,14 +62,14 @@ class _ContactPageState extends State<ContactPage> {
children: [ children: [
itemTitle(context, "contact.callus"), itemTitle(context, "contact.callus"),
contactItem(context, setting.usaContactNumber, CupertinoIcons.phone, contactItem(context, setting.usaContactNumber, CupertinoIcons.phone,
onTap: () => _call(setting.usaContactNumber), onTap: () => _call(setting.usaContactNumber ?? ""),
labelKey: "contact.usa.phone"), labelKey: "contact.usa.phone"),
contactItem( contactItem(
context, context,
setting.mmContactNumber, setting.mmContactNumber,
CupertinoIcons.phone, CupertinoIcons.phone,
onTap: () => _call( onTap: () => _call(
setting.mmContactNumber, setting.mmContactNumber ?? "",
), ),
labelKey: "contact.mm.phone", labelKey: "contact.mm.phone",
), ),
@@ -90,7 +91,7 @@ class _ContactPageState extends State<ContactPage> {
context, context,
setting.emailAddress, setting.emailAddress,
CupertinoIcons.mail, CupertinoIcons.mail,
onTap: () => _email(setting.emailAddress), onTap: () => _email(setting.emailAddress ?? ""),
labelKey: "contact.fcs.email", labelKey: "contact.fcs.email",
), ),
itemTitle(context, "contact.visitus"), itemTitle(context, "contact.visitus"),
@@ -98,7 +99,7 @@ class _ContactPageState extends State<ContactPage> {
context, context,
setting.facebookLink, setting.facebookLink,
FontAwesomeIcons.facebook, FontAwesomeIcons.facebook,
onTap: () => _opencontactItem(setting.facebookLink), onTap: () => _opencontactItem(setting.facebookLink ?? ""),
labelKey: "contact.facebook", labelKey: "contact.facebook",
), ),
], ],

View File

@@ -40,7 +40,7 @@ class _CustomerEditorState extends State<CustomerEditor> {
)), )),
IconButton( IconButton(
icon: Icon(Icons.open_in_new, color: primaryColor), icon: Icon(Icons.open_in_new, color: primaryColor),
onPressed: () => call(context, widget.customer!.phoneNumber)), onPressed: () => call(context, widget.customer?.phoneNumber ?? "")),
], ],
); );
@@ -68,7 +68,7 @@ class _CustomerEditorState extends State<CustomerEditor> {
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
title: Text( title: Text(
widget.customer!.name, widget.customer?.name ?? "",
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
color: primaryColor, color: primaryColor,
@@ -119,7 +119,7 @@ class _CustomerEditorState extends State<CustomerEditor> {
CustomerModel customerModel = CustomerModel customerModel =
Provider.of<CustomerModel>(context, listen: false); Provider.of<CustomerModel>(context, listen: false);
try { try {
await customerModel.acceptRequest(widget.customer!.id); await customerModel.acceptRequest(widget.customer?.id ?? "");
Navigator.pop(context); Navigator.pop(context);
} catch (e) { } catch (e) {
showMsgDialog(context, "Error", e.toString()); showMsgDialog(context, "Error", e.toString());

View File

@@ -125,7 +125,7 @@ class _CustomerListState extends State<CustomerList> {
Padding( Padding(
padding: const EdgeInsets.only(top: 2.0), padding: const EdgeInsets.only(top: 2.0),
child: new Text( child: new Text(
customer.name, customer.name ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 20.0, color: primaryColor), fontSize: 20.0, color: primaryColor),
), ),
@@ -171,7 +171,7 @@ class _CustomerListState extends State<CustomerList> {
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(right: 5), padding: const EdgeInsets.only(right: 5),
child: _status(customer.status), child: _status(customer.status ?? ""),
), ),
Padding( Padding(
padding: const EdgeInsets.only(right: 5), padding: const EdgeInsets.only(right: 5),
@@ -222,17 +222,17 @@ class _CustomerListState extends State<CustomerList> {
))) )))
.then((value) { .then((value) {
if (customer.fcsUnseenCount > 0) { if (customer.fcsUnseenCount > 0) {
messageModel.seenMessages(customer.id, false); messageModel.seenMessages(customer.id ?? "", false);
} }
}); });
if (customer.fcsUnseenCount > 0) { if (customer.fcsUnseenCount > 0) {
messageModel.seenMessages(customer.id, false); messageModel.seenMessages(customer.id ?? "", false);
} }
} }
_share(User user) async { _share(User user) async {
MainModel mainModel = Provider.of<MainModel>(context, listen: false); MainModel mainModel = Provider.of<MainModel>(context, listen: false);
String appUrl = mainModel.setting.appUrl; String appUrl = mainModel.setting?.appUrl ?? "";
final RenderBox? box = context.findRenderObject() as RenderBox; final RenderBox? box = context.findRenderObject() as RenderBox;
await Share.share( await Share.share(
"Join us on FCS Logistics App. Here is the link:\n $appUrl\n" + "Join us on FCS Logistics App. Here is the link:\n $appUrl\n" +

View File

@@ -37,7 +37,7 @@ class _InvitationEditorState extends State<InvitationEditor> {
)), )),
IconButton( IconButton(
icon: Icon(Icons.open_in_new, color: primaryColor), icon: Icon(Icons.open_in_new, color: primaryColor),
onPressed: () => call(context, widget.customer!.phoneNumber)), onPressed: () => call(context, widget.customer?.phoneNumber ?? "")),
], ],
); );
@@ -57,7 +57,7 @@ class _InvitationEditorState extends State<InvitationEditor> {
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
title: Text( title: Text(
widget.customer!.name, widget.customer?.name ?? "",
style: TextStyle(fontSize: 20, color: primaryColor), style: TextStyle(fontSize: 20, color: primaryColor),
), ),
), ),
@@ -87,7 +87,7 @@ class _InvitationEditorState extends State<InvitationEditor> {
CustomerModel customerModel = CustomerModel customerModel =
Provider.of<CustomerModel>(context, listen: false); Provider.of<CustomerModel>(context, listen: false);
try { try {
await customerModel.deleteInvite(widget.customer!.phoneNumber); await customerModel.deleteInvite(widget.customer?.phoneNumber ?? "");
Navigator.pop(context); Navigator.pop(context);
} catch (e) { } catch (e) {
showMsgDialog(context, "Error", e.toString()); showMsgDialog(context, "Error", e.toString());

View File

@@ -12,8 +12,8 @@ class CustomerModel extends BaseModel {
List<User> customers = []; List<User> customers = [];
List<User> invitations = []; List<User> invitations = [];
late StreamSubscription<QuerySnapshot?> customerListener; late StreamSubscription<QuerySnapshot>? customerListener;
late StreamSubscription<QuerySnapshot?> invitationListener; late StreamSubscription<QuerySnapshot>? invitationListener;
@override @override
void privilegeChanged() { void privilegeChanged() {
@@ -24,8 +24,8 @@ class CustomerModel extends BaseModel {
@override @override
logout() async { logout() async {
if (customerListener != null) customerListener.cancel(); if (customerListener != null) customerListener!.cancel();
if (invitationListener != null) invitationListener.cancel(); if (invitationListener != null) invitationListener!.cancel();
customers = []; customers = [];
invitations = []; invitations = [];
} }
@@ -43,21 +43,22 @@ class CustomerModel extends BaseModel {
} }
Future<void> _loadCustomer() async { Future<void> _loadCustomer() async {
if (user == null || !user.hasCustomers()) return; if (user == null && !user!.hasCustomers()) return;
try { try {
if (customerListener != null) customerListener.cancel(); if (customerListener != null) customerListener!.cancel();
customerListener = Firestore.instance customerListener = FirebaseFirestore.instance
.collection("/$user_collection") .collection("/$user_collection")
.where("is_sys_admin", isEqualTo: false) .where("is_sys_admin", isEqualTo: false)
.orderBy("message_time", descending: true) .orderBy("message_time", descending: true)
.snapshots() .snapshots()
.listen((QuerySnapshot snapshot) { .listen((QuerySnapshot snapshot) {
customers.clear(); customers.clear();
customers = snapshot.documents.map((documentSnapshot) { customers = snapshot.docs.map((documentSnapshot) {
var user = var user = User.fromMap(
User.fromMap(documentSnapshot.data, documentSnapshot.documentID); documentSnapshot.data() as Map<String, dynamic>,
documentSnapshot.id);
return user; return user;
}).toList(); }).toList();
notifyListeners(); notifyListeners();
@@ -68,19 +69,20 @@ class CustomerModel extends BaseModel {
} }
Future<void> _loadInvitations() async { Future<void> _loadInvitations() async {
if (user == null || !user.hasCustomers()) return; if (user == null && !user!.hasCustomers()) return;
try { try {
if (invitationListener != null) invitationListener.cancel(); if (invitationListener != null) invitationListener!.cancel();
invitationListener = Firestore.instance invitationListener = FirebaseFirestore.instance
.collection("/$invitations_collection") .collection("/$invitations_collection")
.snapshots() .snapshots()
.listen((QuerySnapshot snapshot) { .listen((QuerySnapshot snapshot) {
invitations.clear(); invitations.clear();
invitations = snapshot.documents.map((documentSnapshot) { invitations = snapshot.docs.map((documentSnapshot) {
var user = var user = User.fromMap(
User.fromMap(documentSnapshot.data, documentSnapshot.documentID); documentSnapshot.data() as Map<String, dynamic>,
documentSnapshot.id);
return user; return user;
}).toList(); }).toList();
notifyListeners(); notifyListeners();
@@ -92,21 +94,20 @@ class CustomerModel extends BaseModel {
Future<User> getUser(String? id) async { Future<User> getUser(String? id) async {
String path = "/$user_collection"; String path = "/$user_collection";
var snap = await Firestore.instance.collection(path).document(id).get(); var snap = await FirebaseFirestore.instance.collection(path).doc(id).get();
return User.fromMap(snap.data, snap.documentID); return User.fromMap(snap.data() as Map<String, dynamic>, snap.id);
} }
Future<List<User>> getInvoiceUsers(String fcsShipmentID) async { Future<List<User>> getInvoiceUsers(String fcsShipmentID) async {
List<User> users = []; List<User> users = [];
try { try {
var snaps = await Firestore.instance var snaps = await FirebaseFirestore.instance
.collection( .collection(
"/$fcs_shipment_collection/$fcsShipmentID/$user_collection") "/$fcs_shipment_collection/$fcsShipmentID/$user_collection")
.where("pending_invoice_carton_count", isGreaterThan: 0) .where("pending_invoice_carton_count", isGreaterThan: 0)
.getDocuments(source: Source.server); .get(GetOptions(source: Source.server));
users = snaps.documents.map((documentSnapshot) { users = snaps.docs.map((documentSnapshot) {
var user = var user = User.fromMap(documentSnapshot.data(), documentSnapshot.id);
User.fromMap(documentSnapshot.data, documentSnapshot.documentID);
return user; return user;
}).toList(); }).toList();
} catch (e) { } catch (e) {
@@ -116,6 +117,6 @@ class CustomerModel extends BaseModel {
} }
Future<void> enableUser(User user, bool enabled) { Future<void> enableUser(User user, bool enabled) {
return Services.instance.userService.enableUser(user.id, enabled); return Services.instance.userService.enableUser(user.id ?? "", enabled);
} }
} }

View File

@@ -151,7 +151,7 @@ class _HomePageState extends State<HomePage> {
new AndroidInitializationSettings('@mipmap/ic_launcher'); new AndroidInitializationSettings('@mipmap/ic_launcher');
var initializationSettingsIOS = new IOSInitializationSettings(); var initializationSettingsIOS = new IOSInitializationSettings();
var initializationSettings = new InitializationSettings( var initializationSettings = new InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS); android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
_flutterLocalNotificationsPlugin.initialize(initializationSettings); _flutterLocalNotificationsPlugin.initialize(initializationSettings);
} }
@@ -179,13 +179,15 @@ class _HomePageState extends State<HomePage> {
'your channel id', 'your channel name', 'your channel description', 'your channel id', 'your channel name', 'your channel description',
playSound: true, playSound: true,
enableVibration: true, enableVibration: true,
importance: Importance.Max, importance: Importance.max,
priority: Priority.High); priority: Priority.high);
// @formatter:on // @formatter:on
var platformChannelSpecificsIos = var platformChannelSpecificsIos =
new IOSNotificationDetails(presentSound: true); new IOSNotificationDetails(presentSound: true);
var platformChannelSpecifics = new NotificationDetails( var platformChannelSpecifics = new NotificationDetails(
platformChannelSpecificsAndroid, platformChannelSpecificsIos); android: platformChannelSpecificsAndroid,
iOS: platformChannelSpecificsIos);
new Future.delayed(Duration.zero, () { new Future.delayed(Duration.zero, () {
_flutterLocalNotificationsPlugin.show( _flutterLocalNotificationsPlugin.show(

View File

@@ -31,7 +31,7 @@ class _CargoEditorState extends State<CargoEditor> {
super.initState(); super.initState();
if (widget.cargo != null) { if (widget.cargo != null) {
_cargo = widget.cargo!; _cargo = widget.cargo!;
_descController.text = _cargo.name; _descController.text = _cargo.name ?? "";
_rateController.text = _cargo.rate.toStringAsFixed(2); _rateController.text = _cargo.rate.toStringAsFixed(2);
} else { } else {
_isNew = true; _isNew = true;
@@ -138,7 +138,7 @@ class _CargoEditorState extends State<CargoEditor> {
try { try {
var shipmentRateModel = var shipmentRateModel =
Provider.of<ShipmentRateModel>(context, listen: false); Provider.of<ShipmentRateModel>(context, listen: false);
await shipmentRateModel.deleteCargoType(this._cargo.id); await shipmentRateModel.deleteCargoType(this._cargo.id!);
Navigator.pop(context); Navigator.pop(context);
} catch (e) { } catch (e) {
showMsgDialog(context, "Error", e.toString()); showMsgDialog(context, "Error", e.toString());

View File

@@ -75,7 +75,7 @@ class _CargoTypeListState extends State<CargoTypeList> {
))); )));
}, },
child: Container( child: Container(
child: _row(cargo.name, child: _row(cargo.name ?? "",
"\$ " + cargo.rate.toStringAsFixed(2), 'per pound'), "\$ " + cargo.rate.toStringAsFixed(2), 'per pound'),
), ),
); );

View File

@@ -33,7 +33,7 @@ class _CustomEditorState extends State<CustomEditor> {
super.initState(); super.initState();
if (widget.custom != null) { if (widget.custom != null) {
_custom = widget.custom!; _custom = widget.custom!;
_productController.text = _custom.name; _productController.text = _custom.name??"";
_feeController.text = _custom.customDutyFee.toStringAsFixed(2); _feeController.text = _custom.customDutyFee.toStringAsFixed(2);
_shipmentRateController.text = _shipmentRateController.text =
_custom.rate == null ? "" : _custom.rate.toStringAsFixed(2); _custom.rate == null ? "" : _custom.rate.toStringAsFixed(2);
@@ -154,7 +154,7 @@ class _CustomEditorState extends State<CustomEditor> {
try { try {
var shipmentRateModel = var shipmentRateModel =
Provider.of<ShipmentRateModel>(context, listen: false); Provider.of<ShipmentRateModel>(context, listen: false);
await shipmentRateModel.deleteCustomDuty(this._custom.id); await shipmentRateModel.deleteCustomDuty(this._custom.id!);
Navigator.pop(context); Navigator.pop(context);
} catch (e) { } catch (e) {
showMsgDialog(context, "Error", e.toString()); showMsgDialog(context, "Error", e.toString());

View File

@@ -81,7 +81,7 @@ class _CustomListState extends State<CustomList> {
}, },
child: Container( child: Container(
child: _row( child: _row(
custom.name, custom.name??"",
"Custom Fee \$ " + custom.customDutyFee.toStringAsFixed(2), "Custom Fee \$ " + custom.customDutyFee.toStringAsFixed(2),
custom.rate == null custom.rate == null
? "" ? ""

View File

@@ -1,9 +1,9 @@
import 'package:fcs/domain/entities/custom_duty.dart'; import 'package:fcs/domain/entities/custom_duty.dart';
import 'package:fcs/domain/vo/delivery_address.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_text.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart';
typedef SelectionCallback(CustomDuty custom); typedef SelectionCallback(CustomDuty custom);

View File

@@ -143,7 +143,7 @@ class _DiscountByWeightEditorState extends State<DiscountByWeightEditor> {
var shipmentRateModel = var shipmentRateModel =
Provider.of<ShipmentRateModel>(context, listen: false); Provider.of<ShipmentRateModel>(context, listen: false);
await shipmentRateModel await shipmentRateModel
.deleteDiscountByWeight(this._discountByWeight.id); .deleteDiscountByWeight(this._discountByWeight.id!);
Navigator.pop(context); Navigator.pop(context);
} catch (e) { } catch (e) {
showMsgDialog(context, "Error", e.toString()); showMsgDialog(context, "Error", e.toString());

View File

@@ -2,7 +2,6 @@ import 'dart:async';
import 'package:fcs/data/services/services.dart'; import 'package:fcs/data/services/services.dart';
import 'package:fcs/domain/entities/cargo_type.dart'; import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/domain/entities/custom_duty.dart';
import 'package:fcs/domain/entities/discount_by_weight.dart'; import 'package:fcs/domain/entities/discount_by_weight.dart';
import 'package:fcs/domain/entities/rate.dart'; import 'package:fcs/domain/entities/rate.dart';
import 'package:fcs/pages/main/model/base_model.dart'; import 'package:fcs/pages/main/model/base_model.dart';
@@ -11,12 +10,12 @@ import 'package:logging/logging.dart';
class ShipmentRateModel extends BaseModel { class ShipmentRateModel extends BaseModel {
final log = Logger('ShipmentRateModel'); final log = Logger('ShipmentRateModel');
StreamSubscription<Rate> listener; StreamSubscription<Rate>? listener;
Rate rate; late Rate rate;
void initUser(user) { void initUser(user) {
super.initUser(user); super.initUser(user);
if (listener != null) listener.cancel(); if (listener != null) listener!.cancel();
listener = Services.instance.rateService.getRateStream().listen((rate) { listener = Services.instance.rateService.getRateStream().listen((rate) {
this.rate = rate; this.rate = rate;
notifyListeners(); notifyListeners();
@@ -25,7 +24,7 @@ class ShipmentRateModel extends BaseModel {
@override @override
logout() async { logout() async {
if (listener != null) await listener.cancel(); if (listener != null) await listener!.cancel();
} }
// Rate // Rate
@@ -51,12 +50,12 @@ class ShipmentRateModel extends BaseModel {
//CustomDuty //CustomDuty
Future<void> addCustomDuty(CargoType customDuty) { Future<void> addCustomDuty(CargoType customDuty) {
customDuty.isCutomDuty=true; customDuty.isCutomDuty = true;
return Services.instance.rateService.createCargoType(customDuty); return Services.instance.rateService.createCargoType(customDuty);
} }
Future<void> updateCustomDuty(CargoType customDuty) { Future<void> updateCustomDuty(CargoType customDuty) {
customDuty.isCutomDuty=true; customDuty.isCutomDuty = true;
return Services.instance.rateService.updateCargoType(customDuty); return Services.instance.rateService.updateCargoType(customDuty);
} }

View File

@@ -1,5 +1,4 @@
import 'package:fcs/domain/entities/cargo_type.dart'; import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/domain/entities/custom_duty.dart';
import 'package:fcs/domain/entities/discount_by_weight.dart'; import 'package:fcs/domain/entities/discount_by_weight.dart';
import 'package:fcs/domain/entities/rate.dart'; import 'package:fcs/domain/entities/rate.dart';
import 'package:fcs/helpers/theme.dart'; import 'package:fcs/helpers/theme.dart';
@@ -185,8 +184,8 @@ class _ShipmentRatesState extends State<ShipmentRates> {
List<Widget> getCargoWidget(List<CargoType> cargos) { List<Widget> getCargoWidget(List<CargoType> cargos) {
return cargos.map((cargo) { return cargos.map((cargo) {
return Container( return Container(
child: _row( child: _row(cargo.name ?? "", "\$ " + cargo.rate.toStringAsFixed(2),
cargo.name, "\$ " + cargo.rate.toStringAsFixed(2), 'per pound'), 'per pound'),
); );
}).toList(); }).toList();
} }
@@ -194,7 +193,8 @@ class _ShipmentRatesState extends State<ShipmentRates> {
List<Widget> getCustonWidget(List<CargoType> customs) { List<Widget> getCustonWidget(List<CargoType> customs) {
return customs.map((c) { return customs.map((c) {
return Container( return Container(
child: _row(c.name, "\$ " + c.customDutyFee.toStringAsFixed(2), ''), child:
_row(c.name ?? "", "\$ " + c.customDutyFee.toStringAsFixed(2), ''),
); );
}).toList(); }).toList();
} }

View File

@@ -11,6 +11,7 @@ import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/progress.dart'; import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class ShipmentRatesCal extends StatefulWidget { class ShipmentRatesCal extends StatefulWidget {

View File

@@ -35,12 +35,11 @@ class _ShipmentRatesEditState extends State<ShipmentRatesEdit> {
Provider.of<ShipmentRateModel>(context, listen: false); Provider.of<ShipmentRateModel>(context, listen: false);
rate = shipmentRateModel.rate; rate = shipmentRateModel.rate;
_minWeight.text = rate.freeDeliveryWeight?.toStringAsFixed(2) ?? ""; _minWeight.text = rate.freeDeliveryWeight.toStringAsFixed(2);
_deliveryFee.text = rate.deliveryFee?.toStringAsFixed(2) ?? ""; _deliveryFee.text = rate.deliveryFee.toStringAsFixed(2);
_volumetricRatio.text = rate.volumetricRatio?.toStringAsFixed(2) ?? ""; _volumetricRatio.text = rate.volumetricRatio.toStringAsFixed(2);
_diffDiscountWeight.text = _diffDiscountWeight.text = rate.diffDiscountWeight.toStringAsFixed(2);
rate.diffDiscountWeight?.toStringAsFixed(2) ?? ""; _diffWeightRate.text = rate.diffWeightRate.toStringAsFixed(2);
_diffWeightRate.text = rate.diffWeightRate?.toStringAsFixed(2) ?? "";
} }
@override @override

View File

@@ -3,21 +3,20 @@ import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/signin/invitation_request_page.dart'; import 'package:fcs/pages/signin/invitation_request_page.dart';
import 'package:fcs/pages/signin/signup_page.dart'; import 'package:fcs/pages/signin/signup_page.dart';
import 'package:fcs/pages/widgets/bottom_up_page_route.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
navigateAfterAuthVerified(BuildContext context) async { navigateAfterAuthVerified(BuildContext context) async {
User user = Provider.of<MainModel>(context, listen: false).user; User? user = Provider.of<MainModel>(context, listen: false).user;
Setting setting = Provider.of<MainModel>(context, listen: false).setting; Setting? setting = Provider.of<MainModel>(context, listen: false).setting;
if (setting == null) return; if (setting == null) return;
if (user != null && (user.joined || user.requested)) { if (user != null && (user.joined || user.requested)) {
Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false); Navigator.pushNamedAndRemoveUntil(context, "/home", (r) => false);
} else { } else {
if (setting.inviteRequired) { if (setting.inviteRequired ?? false) {
bool invited = bool invited =
await Provider.of<MainModel>(context, listen: false).hasInvite(); await Provider.of<MainModel>(context, listen: false).hasInvite();
if (!invited) { if (!invited) {

View File

@@ -181,7 +181,7 @@ class _SigninPageState extends State<SigninPage> {
await navigateAfterAuthVerified(context); await navigateAfterAuthVerified(context);
} }
if (auth.authStatus == AuthStatus.ERROR) { if (auth.authStatus == AuthStatus.ERROR) {
showMsgDialog(context, "Error", auth.authErrorMsg); showMsgDialog(context, "Error", auth.authErrorMsg ?? "");
} }
} catch (e) { } catch (e) {
showMsgDialog(context, "Error", e.toString()); showMsgDialog(context, "Error", e.toString());

View File

@@ -3,23 +3,12 @@ import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/user_search/user_serach.dart'; import 'package:fcs/pages/user_search/user_serach.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class UserListRow extends StatefulWidget { class UserListRow extends StatelessWidget {
final OnUserRowSelect onUserRowSelect; final OnUserRowSelect? onUserRowSelect;
final User user; final User user;
const UserListRow({this.user, this.onUserRowSelect}); const UserListRow({required this.user, this.onUserRowSelect});
@override
_UserListRowState createState() => _UserListRowState();
}
class _UserListRowState extends State<UserListRow> {
final double dotSize = 15.0; final double dotSize = 15.0;
User user;
@override
void initState() {
super.initState();
this.user = widget.user;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -30,8 +19,7 @@ class _UserListRowState extends State<UserListRow> {
color: Colors.white, color: Colors.white,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
if (widget.onUserRowSelect != null) if (onUserRowSelect != null) onUserRowSelect!(user);
widget.onUserRowSelect(widget.user);
}, },
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
@@ -53,17 +41,17 @@ class _UserListRowState extends State<UserListRow> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
new Text( new Text(
user.name == null ? '' : user.name, user.name ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 15.0, color: Colors.black), fontSize: 15.0, color: Colors.black),
), ),
new Text( new Text(
user.fcsID == null ? "" : user.fcsID, user.fcsID ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 13.0, color: Colors.grey), fontSize: 13.0, color: Colors.grey),
), ),
new Text( new Text(
user.phoneNumber == null ? "" : user.phoneNumber, user.phoneNumber ?? "",
style: new TextStyle( style: new TextStyle(
fontSize: 13.0, color: Colors.grey), fontSize: 13.0, color: Colors.grey),
), ),

View File

@@ -8,8 +8,8 @@ import 'package:provider/provider.dart';
typedef OnUserSelect(User suer); typedef OnUserSelect(User suer);
typedef OnUserRowSelect(User suer); typedef OnUserRowSelect(User suer);
Future<User> searchUser(BuildContext context, Future<User?> searchUser(BuildContext context,
{OnUserSelect onUserSelect, bool popPage = false}) async => {required OnUserSelect onUserSelect, bool popPage = false}) async =>
await showSearch<User>( await showSearch<User>(
context: context, context: context,
delegate: delegate:
@@ -20,7 +20,7 @@ class UserSearchDelegate extends SearchDelegate<User> {
final OnUserSelect onUserSelect; final OnUserSelect onUserSelect;
final bool popPage; final bool popPage;
UserSearchDelegate({this.onUserSelect, this.popPage}); UserSearchDelegate({required this.onUserSelect, required this.popPage});
@override @override
String get searchFieldLabel => 'Search by FCS ID or Name'; String get searchFieldLabel => 'Search by FCS ID or Name';
@@ -31,10 +31,10 @@ class UserSearchDelegate extends SearchDelegate<User> {
return theme.copyWith( return theme.copyWith(
inputDecorationTheme: InputDecorationTheme( inputDecorationTheme: InputDecorationTheme(
hintStyle: TextStyle( hintStyle: TextStyle(
color: theme.primaryTextTheme.caption.color, fontSize: 14)), color: theme.primaryTextTheme.caption?.color, fontSize: 14)),
textTheme: theme.textTheme.copyWith( textTheme: theme.textTheme.copyWith(
title: theme.textTheme.title.copyWith( title: theme.textTheme.title?.copyWith(
color: theme.primaryTextTheme.title.color, fontSize: 16)), color: theme.primaryTextTheme.title?.color, fontSize: 16)),
primaryColor: primaryColor, primaryColor: primaryColor,
); );
} }
@@ -53,7 +53,7 @@ class UserSearchDelegate extends SearchDelegate<User> {
Widget buildLeading(BuildContext context) { Widget buildLeading(BuildContext context) {
return IconButton( return IconButton(
icon: Icon(Icons.arrow_back), icon: Icon(Icons.arrow_back),
onPressed: () => close(context, null), onPressed: () => close(context, new User()),
); );
} }
@@ -64,7 +64,7 @@ class UserSearchDelegate extends SearchDelegate<User> {
future: packageModel.searchUser(query), future: packageModel.searchUser(query),
builder: (context, AsyncSnapshot<List<User>> snapshot) { builder: (context, AsyncSnapshot<List<User>> snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
if (snapshot.data.length == 0) { if (snapshot.data == null || snapshot.data!.length == 0) {
return Container( return Container(
child: Center( child: Center(
child: Text( child: Text(
@@ -77,7 +77,7 @@ class UserSearchDelegate extends SearchDelegate<User> {
return Container( return Container(
padding: EdgeInsets.only(top: 15), padding: EdgeInsets.only(top: 15),
child: ListView( child: ListView(
children: snapshot.data children: snapshot.data!
.map((u) => UserListRow( .map((u) => UserListRow(
user: u, user: u,
onUserRowSelect: (u) => _onUserRowSelect(context, u), onUserRowSelect: (u) => _onUserRowSelect(context, u),

View File

@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
class FlavorBanner extends StatelessWidget { class FlavorBanner extends StatelessWidget {
final Widget child; final Widget child;
FlavorBanner({@required this.child}); FlavorBanner({required this.child});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@@ -1,9 +1,9 @@
import 'package:barcode_scan/barcode_scan.dart'; import 'package:barcode_scan2/platform_wrapper.dart';
Future<String> scanBarcode() async { Future<String?> scanBarcode() async {
try { try {
String barcode = await BarcodeScanner.scan(); var scanResult = await BarcodeScanner.scan();
if (barcode == null) return null; String barcode = scanResult.rawContent;
String gs = String.fromCharCode(29); String gs = String.fromCharCode(29);
if (barcode.contains(gs)) { if (barcode.contains(gs)) {

View File

@@ -13,7 +13,7 @@ class BottomWidgets extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var pkgInfo = Provider.of<MainModel>(context).packageInfo; var pkgInfo = Provider.of<MainModel>(context).packageInfo;
final versionBox = Text( final versionBox = Text(
"v${pkgInfo.version}+${pkgInfo.buildNumber}", "v${pkgInfo?.version}+${pkgInfo?.buildNumber}",
style: TextStyle(color: Colors.white30), style: TextStyle(color: Colors.white30),
); );
return Column( return Column(

View File

@@ -8,17 +8,26 @@ class DisplayImageSource {
File? file; File? file;
DisplayImageSource({this.url, this.file}); DisplayImageSource({this.url, this.file});
ImageProvider? get imageProvider => ImageProvider get imageProvider {
file == null ? CachedNetworkImageProvider(url!) : FileImage(file!); if (file == null) {
return CachedNetworkImageProvider(url!);
} else {
return FileImage(file!);
}
}
@override @override
bool operator ==(other) { bool operator ==(other) {
if (identical(this, other)) { if (identical(this, other) && other is DisplayImageSource) {
return true; return true;
} }
return (other.file == this.file &&
return (other is DisplayImageSource &&
other.file == this.file &&
(other.file != null || this.file != null)) || (other.file != null || this.file != null)) ||
(other.url == this.url && (other.url != null || this.url != null)); (other is DisplayImageSource &&
other.url == this.url &&
(other.url != null || this.url != null));
} }
@override @override

View File

@@ -7,7 +7,7 @@ import 'local_text.dart';
typedef OnFile = void Function(File); typedef OnFile = void Function(File);
modelBottomSheet(BuildContext context, {final OnFile onFile}) { modelBottomSheet(BuildContext context, {final OnFile? onFile}) {
showModalBottomSheet( showModalBottomSheet(
elevation: 10, elevation: 10,
backgroundColor: Colors.white, backgroundColor: Colors.white,
@@ -84,7 +84,7 @@ class _ImageFileState extends State<ImageFile> {
} }
pickImage(ImageSource source) async { pickImage(ImageSource source) async {
var tempImage = await ImagePicker.pickImage(source: source); var tempImage = await ImagePicker().pickImage(source: source);
return tempImage; return tempImage;
} }
} }

View File

@@ -1,5 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:fcs/helpers/theme.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
@@ -7,19 +8,19 @@ import 'package:image_picker/image_picker.dart';
import 'show_img.dart'; import 'show_img.dart';
typedef OnFile = void Function(File); typedef OnFile = void Function(File?);
class LocalImagePicker extends StatefulWidget { class LocalImagePicker extends StatefulWidget {
final Color color; final Color? color;
final String title; final String title;
final OnFile onFile; final OnFile? onFile;
final bool enabled; final bool enabled;
final String initialImgUrl; final String? initialImgUrl;
final ImageSource imageSource; final ImageSource imageSource;
const LocalImagePicker( const LocalImagePicker(
{Key key, {Key? key,
this.title, required this.title,
this.onFile, this.onFile,
this.enabled = true, this.enabled = true,
this.initialImgUrl, this.initialImgUrl,
@@ -31,8 +32,8 @@ class LocalImagePicker extends StatefulWidget {
} }
class _LocalImagePickerState extends State<LocalImagePicker> { class _LocalImagePickerState extends State<LocalImagePicker> {
String url; String? url;
File file; File? file;
@override @override
void initState() { void initState() {
@@ -56,16 +57,16 @@ class _LocalImagePickerState extends State<LocalImagePicker> {
await _dialog( await _dialog(
context, () => camera = true, () => gallery = true); context, () => camera = true, () => gallery = true);
if (camera || gallery) { if (camera || gallery) {
var selectedFile = await ImagePicker.pickImage( var selectedFile = await ImagePicker().pickImage(
source: camera ? ImageSource.camera : ImageSource.gallery, source: camera ? ImageSource.camera : ImageSource.gallery,
imageQuality: 80, imageQuality: 80,
maxWidth: 1000); maxWidth: 1000);
if (selectedFile != null) { if (selectedFile != null) {
setState(() { setState(() {
this.file = selectedFile; this.file = File(selectedFile.path);
}); });
if (widget.onFile != null) { if (widget.onFile != null) {
widget.onFile(selectedFile); widget.onFile!(File(selectedFile.path));
} }
} }
} }
@@ -93,7 +94,7 @@ class _LocalImagePickerState extends State<LocalImagePicker> {
this.file = null; this.file = null;
this.url = null; this.url = null;
if (widget.onFile != null) { if (widget.onFile != null) {
widget.onFile(null); widget.onFile!(null);
} }
}); });
}, },

View File

@@ -144,7 +144,8 @@ class _LengthPickerDialogState extends State<LengthPickerDialog> {
borderSide: BorderSide(color: primaryColor, width: 1.0), borderSide: BorderSide(color: primaryColor, width: 1.0),
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey.shade400, width: 1.0), borderSide:
BorderSide(color: Colors.grey.shade400, width: 1.0),
), ),
), ),
), ),
@@ -196,7 +197,8 @@ class _LengthPickerDialogState extends State<LengthPickerDialog> {
borderSide: BorderSide(color: primaryColor, width: 1.0), borderSide: BorderSide(color: primaryColor, width: 1.0),
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey.shade400, width: 1.0), borderSide:
BorderSide(color: Colors.grey.shade400, width: 1.0),
), ),
), ),
), ),
@@ -273,7 +275,7 @@ class _LengthPickerDialogState extends State<LengthPickerDialog> {
min: 0, min: 0,
max: MAX_FEET, max: MAX_FEET,
divisions: 100, divisions: 100,
label: (_valueFeet ?? 0).round().toString(), label: _valueFeet.round().toString(),
onChanged: (double v) { onChanged: (double v) {
_updateFeet(v); _updateFeet(v);
}, },
@@ -301,7 +303,7 @@ class _LengthPickerDialogState extends State<LengthPickerDialog> {
min: 0, min: 0,
max: widget.displayFeet! ? 11 : MAX_INC, max: widget.displayFeet! ? 11 : MAX_INC,
divisions: 100, divisions: 100,
label: (_valueInc ?? 0).round().toString(), label: _valueInc.round().toString(),
onChanged: (double v) { onChanged: (double v) {
_updateInc(v); _updateInc(v);
}, },

View File

@@ -5,12 +5,12 @@ import 'display_image_source.dart';
class MultiImgController { class MultiImgController {
List<String> imageUrls = []; List<String> imageUrls = [];
List<File> imageFiles = []; List<File?> imageFiles = [];
List<DisplayImageSource> addedFiles = []; List<DisplayImageSource> addedFiles = [];
List<DisplayImageSource> removedFiles = []; List<DisplayImageSource> removedFiles = [];
List<DisplayImageSource> fileContainers = []; List<DisplayImageSource> fileContainers = [];
CallBack callback; CallBack? callback;
MultiImgController() { MultiImgController() {
fileContainers = []; fileContainers = [];
} }
@@ -26,7 +26,7 @@ class MultiImgController {
fileContainers.add(DisplayImageSource(url: e)); fileContainers.add(DisplayImageSource(url: e));
}); });
if (callback != null) { if (callback != null) {
callback(); callback!();
} }
} }
@@ -42,7 +42,7 @@ class MultiImgController {
fileContainers.add(DisplayImageSource(file: e)); fileContainers.add(DisplayImageSource(file: e));
}); });
if (callback != null) { if (callback != null) {
callback(); callback!();
} }
} }
@@ -54,7 +54,7 @@ class MultiImgController {
// if (fileContainers.contains(fileContainer)) return; // if (fileContainers.contains(fileContainer)) return;
addedFiles.add(fileContainer); addedFiles.add(fileContainer);
if (callback != null) { if (callback != null) {
callback(); callback!();
} }
} }
@@ -74,7 +74,7 @@ class MultiImgController {
} }
if (callback != null) { if (callback != null) {
callback(); callback!();
} }
} }

View File

@@ -46,7 +46,7 @@ dependencies:
flutter_icons_null_safety: ^1.1.0 flutter_icons_null_safety: ^1.1.0
country_icons: ^2.0.2 country_icons: ^2.0.2
timeline_list: ^0.0.5 timeline_list: ^0.0.5
# barcode_scan: ^2.0.2 barcode_scan2: ^4.1.3
barcode_scan2: ^4.1.4 barcode_scan2: ^4.1.4
flutter_pdfview: ^1.2.1 flutter_pdfview: ^1.2.1
flutter_local_notifications: ^8.2.0 flutter_local_notifications: ^8.2.0