diff --git a/lib/api.dart b/lib/api.dart index ae2f339..69db310 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -20,6 +20,25 @@ class API { API._internal(); + Future prefetch() async { + // todo : prefetch + // fetch items + var resp = jsonDecode(await getRequest("$instance/items")); + var lst = resp["items"] as List; + items = lst.map((x) => Item(x)).toList(); + + // fetch locations + var locResp = jsonDecode(await getRequest("$instance/locations")) + as Map; + locations = locResp.map((key, value) => MapEntry(key, Location(value))); + + // fetch flowInfos + var flowResp = + jsonDecode(await getRequest("$instance/flows")) as Map; + + flowInfos = flowResp.map((key, value) => MapEntry(key, FlowInfo(value))); + } + Future init() async { pref = await SharedPreferences.getInstance(); instance = pref.getString("instance") ?? ""; @@ -60,14 +79,7 @@ class API { } // /items - Future> getItems() async { - if (items != null) { - return items!; - } - - var resp = jsonDecode(await getRequest("$instance/items")); - var lst = resp["items"] as List; - items = lst.map((x) => Item(x)).toList(); + List getItems() { return items!; } @@ -90,23 +102,12 @@ class API { return ret; } - Future> getLocations() async { - if (locations != null) { - return locations!; - } - - var resp = jsonDecode(await getRequest("$instance/locations")) - as Map; - locations = resp.map((key, value) => MapEntry(key, Location(value))); + Map getLocations() { return locations!; } - Future getItem(String item) async { - if (items != null) { - return items!.firstWhere((x) => x.id == item); - } - - return Item(jsonDecode(await getRequest("$instance/item/$item"))); + Item getItem(String item) { + return items!.firstWhere((x) => x.id == item); } Future getTransaction(String id) async { @@ -236,25 +237,13 @@ class API { // Flows // /flows - Future> getFlows() async { - if (flowInfos != null) { - return flowInfos!; - } - - var resp = - jsonDecode(await getRequest("$instance/flows")) as Map; - - flowInfos = resp.map((key, value) => MapEntry(key, FlowInfo(value))); + Map getFlows() { return flowInfos!; } // /flow//info - Future getFlowInfo(String id) async { - if (flowInfos != null) { - return flowInfos![id]!; - } - - return FlowInfo(jsonDecode(await getRequest("$instance/flow/$id/info"))); + FlowInfo getFlowInfo(String id) { + return flowInfos![id]!; } Future getFlow(String id) async { @@ -277,12 +266,20 @@ class API { } // /flow//end - Future?> endFlow(String id, {List? produced}) async { + Future>?> endFlow(String id, + {List? produced}) async { var resp = jsonDecode(await postRequest("$instance/flow/$id/end", {"produced": produced?.map((x) => x.json()).toList()})); + print(resp); + if (produced != null) { - return (resp["produced"] as List).cast(); + var produced = resp["produced"] as Map; + return produced.map( + (key, value) { + return MapEntry(key, (value as List).cast()); + }, + ); } return null; @@ -314,13 +311,8 @@ class API { "$instance/transaction/$id/move", {"to": newLocation})); } - Future getLocation(String id) async { - if (locations != null) { - return locations![id]!; - } - - var resp = jsonDecode(await getRequest("$instance/location/$id")); - return Location(resp); + Location getLocation(String id) { + return locations![id]!; } Future addNoteToFlow(String flowID, String content) async { diff --git a/lib/main.dart b/lib/main.dart index 6df00dd..1fb0955 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,6 +8,9 @@ import 'package:flutter/material.dart'; Future main() async { await API().init(); + if (API().isInit()) { + await API().prefetch(); + } runApp(const MyApp()); } diff --git a/lib/pages/flow/active_flow_page.dart b/lib/pages/flow/active_flow_page.dart index 33e9388..12eff76 100644 --- a/lib/pages/flow/active_flow_page.dart +++ b/lib/pages/flow/active_flow_page.dart @@ -67,17 +67,16 @@ class _ActiveFlowPageState extends State { if (widget.info.next != null) IconButton( onPressed: () { - API.API().getFlowInfo(widget.info.next!).then((newInfo) { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) { - return CreateFlowPage( - newInfo, - () {}, - previousFlow: widget.flow, - ); - }, - )); - }); + var newInfo = API.API().getFlowInfo(widget.info.next!); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) { + return CreateFlowPage( + newInfo, + () {}, + previousFlow: widget.flow, + ); + }, + )); }, icon: const Icon(Icons.arrow_forward)), ], diff --git a/lib/pages/flow/create_flow_page.dart b/lib/pages/flow/create_flow_page.dart index eb9ce91..0998424 100644 --- a/lib/pages/flow/create_flow_page.dart +++ b/lib/pages/flow/create_flow_page.dart @@ -25,11 +25,10 @@ class _CreateFlowPageState extends State { input: depends.map((x) => x.uuid).toList()) .then((x) { API.API().getFlow(x).then((flow) { - API.API().getFlowInfo(flow.kind).then((info) { - Navigator.of(context).pushReplacement(MaterialPageRoute( - builder: (context) => ActiveFlowPage(flow, info), - )); - }); + var info = API.API().getFlowInfo(flow.kind); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (context) => ActiveFlowPage(flow, info), + )); }); }); return; @@ -73,11 +72,13 @@ class _CreateFlowPageState extends State { return [ Column( children: widget.info.depends.map((x) { + var (item, variant) = API.itemVariant(x); return ElevatedButton( onPressed: () { selectDependItems(context, x); }, - child: Text("Add $x")); + child: + Text("Add ${API.API().getItem(item).variants[variant]!.name}")); }).toList()), const Divider(), ]; @@ -90,7 +91,7 @@ class _CreateFlowPageState extends State { Card( child: Padding( padding: const EdgeInsets.all(8.0), - child: Text(widget.previousFlow!.kind), + child: Text(API.API().getFlowInfo(widget.previousFlow!.kind).name), ), ), Card(child: Icon(Icons.arrow_right)), diff --git a/lib/pages/flow/end_flow_page.dart b/lib/pages/flow/end_flow_page.dart index 212aaef..cf4061b 100644 --- a/lib/pages/flow/end_flow_page.dart +++ b/lib/pages/flow/end_flow_page.dart @@ -23,13 +23,7 @@ class _EndFlowWithProduceState extends State { @override void initState() { super.initState(); - API.API().getLocations().then( - (value) { - setState(() { - locations = value; - }); - }, - ); + locations = API.API().getLocations(); } refresh() { @@ -46,25 +40,24 @@ class _EndFlowWithProduceState extends State { List ret = []; for (var i in widget.info.produces!) { + var (itemID, variant) = API.itemVariant(i); + var item = API.API().getItem(itemID); ret.add(ElevatedButton( onPressed: () { - var (itemID, variant) = API.itemVariant(i); - API.API().getItem(itemID).then((item) { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) { - return SupplyPage( - item, - refresh, - onlyVariants: [variant], - forcePrice: "0.00", - forceOrigin: "flow::${widget.flow.kind}::${widget.flow.id}", - onCreate: addProduced, - ); - }, - )); - }); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) { + return SupplyPage( + item, + refresh, + onlyVariants: [variant], + forcePrice: "0.00", + forceOrigin: "flow::${widget.flow.kind}::${widget.flow.id}", + onCreate: addProduced, + ); + }, + )); }, - child: Text("Produced $i"))); + child: Text("Produced ${item.variants[variant]!.name}"))); } return ret; diff --git a/lib/pages/flow/flow_info_page.dart b/lib/pages/flow/flow_info_page.dart index aea4b78..7ba14e7 100644 --- a/lib/pages/flow/flow_info_page.dart +++ b/lib/pages/flow/flow_info_page.dart @@ -24,13 +24,17 @@ class _FlowInfoPageState extends State { body: Column( children: [ // todo : ui improve - if (widget.info.next != null) Text("Next: ${widget.info.next}"), + if (widget.info.next != null) + Text("Next: ${API.API().getFlowInfo(widget.info.next!).name}"), if (widget.info.depends.isNotEmpty) Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ const Text("Flow can use: "), - ...widget.info.depends.map((x) => Text(x)).toList(), + ...widget.info.depends.map((x) { + var (item, variant) = API.itemVariant(x); + return Text(API.API().getItem(item).variants[variant]!.name); + }).toList(), ], ), if (widget.info.produces?.isNotEmpty ?? false) @@ -38,7 +42,10 @@ class _FlowInfoPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ const Text("Flow can produce: "), - ...widget.info.produces!.map((x) => Text(x)).toList(), + ...widget.info.produces!.map((x) { + var (item, variant) = API.itemVariant(x); + return Text(API.API().getItem(item).variants[variant]!.name); + }).toList(), ], ), const Divider(), diff --git a/lib/pages/flow/flows_page.dart b/lib/pages/flow/flows_page.dart index 8bcac95..5bfaf35 100644 --- a/lib/pages/flow/flows_page.dart +++ b/lib/pages/flow/flows_page.dart @@ -20,13 +20,7 @@ class _FlowsPageState extends State { @override void initState() { super.initState(); - API.API().getFlows().then( - (value) { - setState(() { - flowInfos = value; - }); - }, - ); + flowInfos = API.API().getFlows(); } Widget flowTile(BuildContext context, API.FlowInfo x) { @@ -94,7 +88,8 @@ class _FlowsPageState extends State { children: producedMapping[key]!.map((x) { return flowTile(context, x); }).toList()); - items.add(ExpandableListItem(body: flows, header: Text(key))); + items.add(ExpandableListItem( + body: flows, header: Text(API.API().getItem(key).name))); } return ExpandableList(items); @@ -122,7 +117,8 @@ class _FlowsPageState extends State { children: dependsMapping[key]!.map((x) { return flowTile(context, x); }).toList()); - items.add(ExpandableListItem(body: flows, header: Text(key))); + items.add(ExpandableListItem( + body: flows, header: Text(API.API().getItem(key).name))); } return ExpandableList(items); @@ -169,13 +165,12 @@ class _FlowsPageState extends State { code = code!.replaceFirst("Code scanned = ", ""); API.API().getFlow(code).then((flow) { - API.API().getFlowInfo(flow.kind).then((info) { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) { - return ActiveFlowPage(flow, info); - }, - )); - }); + var info = API.API().getFlowInfo(flow.kind); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) { + return ActiveFlowPage(flow, info); + }, + )); }); }, ); diff --git a/lib/pages/items.dart b/lib/pages/items.dart index fa5db2f..70304e5 100644 --- a/lib/pages/items.dart +++ b/lib/pages/items.dart @@ -13,20 +13,10 @@ class ItemsPage extends StatelessWidget { appBar: AppBar( title: const Text("Items"), ), - body: FutureBuilder( - future: API().getItems(), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return const CircularProgressIndicator(); - } - - var items = snapshot.data!; - - return ListView( - children: items.map((x) { - return ItemTile(x); - }).toList()); - }), + body: ListView( + children: API().getItems().map((x) { + return ItemTile(x); + }).toList()), floatingActionButton: FloatingActionButton( onPressed: () { // scan transaction code diff --git a/lib/pages/locations.dart b/lib/pages/locations.dart index 7d00bd9..ca12c23 100644 --- a/lib/pages/locations.dart +++ b/lib/pages/locations.dart @@ -17,13 +17,7 @@ class _LocationsPageState extends State { @override void initState() { super.initState(); - API().getLocations().then( - (value) { - setState(() { - locations = value; - }); - }, - ); + locations = API().getLocations(); } TreeNode buildTree(BuildContext context, String locID) { diff --git a/lib/pages/setup.dart b/lib/pages/setup.dart index 620413d..667861d 100644 --- a/lib/pages/setup.dart +++ b/lib/pages/setup.dart @@ -31,6 +31,8 @@ class _SetupPageState extends State { const SnackBar(content: Text('Setup Complete!')), ); + await API().prefetch(); + // Navigate or close the setup screen Navigator.pushReplacement( context, diff --git a/lib/pages/supply.dart b/lib/pages/supply.dart index 342a352..18c3bb3 100644 --- a/lib/pages/supply.dart +++ b/lib/pages/supply.dart @@ -126,7 +126,7 @@ class _SupplyPageState extends State { const SizedBox(height: 16), // Origin Field with Dropdown and Text Input - if (widget.forceOrigin == null) + if (widget.forceOrigin == null) ...[ AutocompletedTextField( options: origins, getValue: () => _selectedOrigin, @@ -146,11 +146,11 @@ class _SupplyPageState extends State { }); }, label: "Origin"), - - const SizedBox(height: 16), + const SizedBox(height: 16), + ], // Price Field - if (widget.forcePrice == null) + if (widget.forcePrice == null) ...[ TextFormField( decoration: const InputDecoration(labelText: 'Price'), keyboardType: TextInputType.number, @@ -165,8 +165,8 @@ class _SupplyPageState extends State { return null; }, ), - - const SizedBox(height: 16), + const SizedBox(height: 16), + ], // Location Dropdown Row( diff --git a/lib/pages/transaction.dart b/lib/pages/transaction.dart index a7d2d62..1de2095 100644 --- a/lib/pages/transaction.dart +++ b/lib/pages/transaction.dart @@ -40,84 +40,80 @@ class _TransactionPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(widget.transaction.item), + title: Text(API().getItem(transaction.item).name), actions: [ IconButton( onPressed: () { - API().getLocations().then((locations) { - List locationList = locations.keys.toList(); - String? selectedLocationID; + var locations = API().getLocations(); + List locationList = locations.keys.toList(); + String? selectedLocationID; - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Move Transaction'), - content: Row( - mainAxisSize: MainAxisSize.min, - children: [ - DropdownButton( - value: selectedLocationID, - onChanged: (value) { - selectedLocationID = value!; - API() - .moveTransaction(widget.transaction.uuid, - selectedLocationID!) - .then((x) { - Navigator.of(context).pop(); - }); + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Move Transaction'), + content: Row( + mainAxisSize: MainAxisSize.min, + children: [ + DropdownButton( + value: selectedLocationID, + onChanged: (value) { + selectedLocationID = value!; + API() + .moveTransaction(widget.transaction.uuid, + selectedLocationID!) + .then((x) { + Navigator.of(context).pop(); + }); + setState(() {}); + }, + items: locationList + .map>((locationID) { + return DropdownMenuItem( + value: locationID, + child: Text(locations[locationID]!.name), + ); + }).toList(), + ), + IconButton( + onPressed: () { + var locations = API().getLocations(); + QrBarCodeScannerDialog().getScannedQrBarCode( + context: context, + onCode: (code) { + // library is retarded + code = code! + .replaceFirst("Code scanned = ", ""); + if (!locations.containsKey(code)) { + ScaffoldMessenger.of(context) + .showSnackBar( + SnackBar( + content: Text( + 'The location $code does not exist.')), + ); + return; + } + + API() + .moveTransaction( + widget.transaction.uuid, + selectedLocationID!) + .then( + (x) { + Navigator.of(context).pop(); + }, + ); + }); setState(() {}); }, - items: locationList - .map>((locationID) { - return DropdownMenuItem( - value: locationID, - child: Text(locations[locationID]!.name), - ); - }).toList(), - ), - IconButton( - onPressed: () { - API().getLocations().then((locations) { - QrBarCodeScannerDialog() - .getScannedQrBarCode( - context: context, - onCode: (code) { - // library is retarded - code = code!.replaceFirst( - "Code scanned = ", ""); - if (!locations - .containsKey(code)) { - ScaffoldMessenger.of(context) - .showSnackBar( - SnackBar( - content: Text( - 'The location $code does not exist.')), - ); - return; - } - - API() - .moveTransaction( - widget.transaction.uuid, - selectedLocationID!) - .then( - (x) { - Navigator.of(context).pop(); - }, - ); - }); - }); - setState(() {}); - }, - icon: const Icon(Icons.qr_code)) - ], - ), - ); - }, - ); - }); + icon: const Icon(Icons.qr_code)) + ], + ), + ); + }, + ); }, icon: const Icon(Icons.move_up)) ], @@ -143,12 +139,12 @@ class _TransactionPageState extends State { children: [ // todo : human names Text( - "${transaction.item}", + "${API().getItem(transaction.item).name}", style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 28), ), Text( - "${transaction.variant}", + "${API().getItem(transaction.item).variants[transaction.variant]!.name}", style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 20, @@ -262,14 +258,14 @@ class TransactionCard extends StatelessWidget { Row( children: [ Text( - t.item, + API().getItem(t.item).name, style: const TextStyle(fontSize: 16), ), const SizedBox( - width: 4, + width: 8, ), Text( - t.variant, + API().getItem(t.item).variants[t.variant]!.name, style: TextStyle(fontSize: 14, color: Colors.grey[400]), ), ], @@ -358,29 +354,28 @@ class TransactionSelectPage extends StatelessWidget { selectionList.add(s); } - if (selectionList.isEmpty) { - Navigator.of(context).pop(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('No Transactions to select')), - ); - } - return Scaffold( appBar: AppBar( title: const Text("Select a Transaction"), ), body: ListView( - children: selectionList - .map((x) => TransactionCard( - x, - () {}, - onLongPress: (x) {}, - onTap: (t) { - onSelect(t); - Navigator.of(context).pop(); - }, - )) - .toList()), + children: selectionList.isEmpty + ? [ + ListTile( + title: Center(child: Text("No Transactions available")), + ) + ] + : selectionList + .map((x) => TransactionCard( + x, + () {}, + onLongPress: (x) {}, + onTap: (t) { + onSelect(t); + Navigator.of(context).pop(); + }, + )) + .toList()), ); } }