diff --git a/lib/api.dart b/lib/api.dart index 739a772..186e46f 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -490,3 +490,8 @@ class GlobalItemStat { total_price = json["total_price"]; } } + +(String, String) itemVariant(String iv) { + var split = iv.split("::"); + return (split[0], split[1]); +} diff --git a/lib/pages/expandable_list.dart b/lib/pages/expandable_list.dart new file mode 100644 index 0000000..69c917b --- /dev/null +++ b/lib/pages/expandable_list.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; + +class ExpandableListItem { + ExpandableListItem({ + required this.body, + required this.header, + this.isExpanded = false, + }); + + Widget body; + Widget header; + bool isExpanded; +} + +class ExpandableList extends StatefulWidget { + final List entries; + + const ExpandableList(this.entries, {super.key}); + + @override + State createState() => _ExpandableListState(); +} + +class _ExpandableListState extends State { + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Container( + child: _buildPanel(), + ), + ); + } + + Widget _buildPanel() { + return ExpansionPanelList( + expansionCallback: (int index, bool isExpanded) { + setState(() { + widget.entries[index].isExpanded = isExpanded; + }); + }, + children: widget.entries.map((ExpandableListItem item) { + return ExpansionPanel( + headerBuilder: (BuildContext context, bool isExpanded) { + return item.header; + }, + body: item.body, + isExpanded: item.isExpanded, + ); + }).toList(), + ); + } +} diff --git a/lib/pages/flow.dart b/lib/pages/flow.dart index 484441a..a886e56 100644 --- a/lib/pages/flow.dart +++ b/lib/pages/flow.dart @@ -1,49 +1,136 @@ import 'package:cdb_ui/api.dart' as API; +import 'package:cdb_ui/pages/expandable_list.dart'; import 'package:flutter/material.dart'; -class FlowsPage extends StatelessWidget { +class FlowsPage extends StatefulWidget { const FlowsPage({super.key}); + @override + State createState() => _FlowsPageState(); +} + +class _FlowsPageState extends State { + int tabSelection = 0; + Map? flowInfos; + + @override + void initState() { + super.initState(); + API.API().getFlows().then( + (value) { + setState(() { + flowInfos = value; + }); + }, + ); + } + + Widget flowTile(BuildContext context, API.FlowInfo x) { + return ListTile( + title: Text(x.name), + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => FlowInfoPage(x), + )); + }, + ); + } + Widget listAllFlowInfos( BuildContext context, Map infos) { return ListView( children: infos.values.map((x) { - return ListTile( - title: Text(x.name), - onTap: () { - Navigator.of(context).push(MaterialPageRoute( - builder: (context) => FlowPage(x), - )); - }, - ); + return flowTile(context, x); }).toList()); } + Widget listFlowInfoByProduced( + BuildContext context, Map infos) { + Map> producedMapping = {}; + + for (var f in infos.values) { + for (var produces in f.produces ?? []) { + var item = API.itemVariant(produces).$1; + producedMapping.putIfAbsent(item, () { + return []; + }); + producedMapping[item]!.add(f); + } + } + + List items = []; + + for (var key in producedMapping.keys) { + var flows = Column( + children: producedMapping[key]!.map((x) { + return flowTile(context, x); + }).toList()); + items.add(ExpandableListItem(body: flows, header: Text(key))); + } + + return ExpandableList(items); + } + + Widget listFlowInfoByDependant( + BuildContext context, Map infos) { + Map> dependsMapping = {}; + + for (var f in infos.values) { + for (var produces in f.depends) { + var item = API.itemVariant(produces).$1; + // todo : add only if item is in inventory + dependsMapping.putIfAbsent(item, () { + return []; + }); + dependsMapping[item]!.add(f); + } + } + + List items = []; + + for (var key in dependsMapping.keys) { + var flows = Column( + children: dependsMapping[key]!.map((x) { + return flowTile(context, x); + }).toList()); + items.add(ExpandableListItem(body: flows, header: Text(key))); + } + + return ExpandableList(items); + } + @override Widget build(BuildContext context) { - // todo : flows (info) by item produced // todo : list currently active - // todo : flows by item needed (show only avail) + + if (flowInfos == null) { + return const CircularProgressIndicator(); + } + return Scaffold( - appBar: AppBar(title: const Text("Flows")), - body: FutureBuilder( - future: API.API().getFlows(), - builder: (ctx, snap) { - if (!snap.hasData) { - return const CircularProgressIndicator(); - } - - var data = snap.data!; - - return listAllFlowInfos(context, data); - })); + appBar: AppBar( + title: const Text("Flows"), + bottom: TabBar( + tabs: const [Text("All"), Text("Produces"), Text("Depends")], + onTap: (value) { + setState(() { + tabSelection = value; + }); + }, + )), + body: switch (tabSelection) { + 0 => listAllFlowInfos(context, flowInfos!), + 1 => listFlowInfoByProduced(context, flowInfos!), + 2 => listFlowInfoByDependant(context, flowInfos!), + _ => const Text("..."), + }); } } -class FlowPage extends StatelessWidget { +class FlowInfoPage extends StatelessWidget { final API.FlowInfo info; - const FlowPage(this.info, {super.key}); + const FlowInfoPage(this.info, {super.key}); @override Widget build(BuildContext context) {