refactor
This commit is contained in:
parent
710ea6743b
commit
b33e65706b
8 changed files with 489 additions and 472 deletions
|
@ -1,5 +1,5 @@
|
|||
import 'package:cdb_ui/api.dart';
|
||||
import 'package:cdb_ui/pages/flow.dart';
|
||||
import 'package:cdb_ui/pages/flow/flows_page.dart';
|
||||
import 'package:cdb_ui/pages/items.dart';
|
||||
import 'package:cdb_ui/pages/locations.dart';
|
||||
import 'package:cdb_ui/pages/setup.dart';
|
||||
|
|
|
@ -1,471 +0,0 @@
|
|||
import 'package:cdb_ui/api.dart' as API;
|
||||
import 'package:cdb_ui/pages/expandable_list.dart';
|
||||
import 'package:cdb_ui/pages/transaction.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FlowsPage extends StatefulWidget {
|
||||
const FlowsPage({super.key});
|
||||
|
||||
@override
|
||||
State<FlowsPage> createState() => _FlowsPageState();
|
||||
}
|
||||
|
||||
class _FlowsPageState extends State<FlowsPage> {
|
||||
int tabSelection = 0;
|
||||
Map<String, API.FlowInfo>? 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 listFlowInfoByActive(
|
||||
BuildContext context, Map<String, API.FlowInfo> infos) {
|
||||
return FutureBuilder(future: () async {
|
||||
var included = [];
|
||||
|
||||
for (var key in infos.keys) {
|
||||
var active = await API.API().getActiveFlowsOf(key);
|
||||
if (active.isNotEmpty) {
|
||||
included.add(infos[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return included;
|
||||
}(), builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const CircularProgressIndicator();
|
||||
}
|
||||
|
||||
var included = snapshot.data!;
|
||||
|
||||
return ListView(
|
||||
children: included.map((x) => flowTile(context, x)).toList());
|
||||
});
|
||||
}
|
||||
|
||||
Widget listAllFlowInfos(
|
||||
BuildContext context, Map<String, API.FlowInfo> infos) {
|
||||
return ListView(
|
||||
children: infos.values.map((x) {
|
||||
return flowTile(context, x);
|
||||
}).toList());
|
||||
}
|
||||
|
||||
Widget listFlowInfoByProduced(
|
||||
BuildContext context, Map<String, API.FlowInfo> infos) {
|
||||
Map<String, List<API.FlowInfo>> 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<ExpandableListItem> 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<String, API.FlowInfo> infos) {
|
||||
Map<String, List<API.FlowInfo>> 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<ExpandableListItem> 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) {
|
||||
if (flowInfos == null) {
|
||||
return const CircularProgressIndicator();
|
||||
}
|
||||
|
||||
return DefaultTabController(
|
||||
length: 4,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Flows"),
|
||||
bottom: TabBar(
|
||||
tabs: const [
|
||||
Tab(text: "All"),
|
||||
Tab(text: "Produces"),
|
||||
Tab(text: "Depends"),
|
||||
Tab(text: "Active")
|
||||
],
|
||||
onTap: (value) {
|
||||
setState(() {
|
||||
tabSelection = value;
|
||||
});
|
||||
},
|
||||
)),
|
||||
body: switch (tabSelection) {
|
||||
0 => listAllFlowInfos(context, flowInfos!),
|
||||
1 => listFlowInfoByProduced(context, flowInfos!),
|
||||
2 => listFlowInfoByDependant(context, flowInfos!),
|
||||
3 => listFlowInfoByActive(context, flowInfos!),
|
||||
_ => const Text("..."),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
class FlowInfoPage extends StatefulWidget {
|
||||
final API.FlowInfo info;
|
||||
|
||||
const FlowInfoPage(this.info, {super.key});
|
||||
|
||||
@override
|
||||
State<FlowInfoPage> createState() => _FlowInfoPageState();
|
||||
}
|
||||
|
||||
class _FlowInfoPageState extends State<FlowInfoPage> {
|
||||
void refresh() {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(widget.info.name)),
|
||||
body: Column(
|
||||
children: [
|
||||
// todo : ui improve
|
||||
if (widget.info.next != null) Text("Next: ${widget.info.next}"),
|
||||
if (widget.info.depends.isNotEmpty)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
const Text("Flow can use: "),
|
||||
...widget.info.depends.map((x) => Text(x)).toList(),
|
||||
],
|
||||
),
|
||||
if (widget.info.produces?.isNotEmpty ?? false)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
const Text("Flow can produce: "),
|
||||
...widget.info.produces!.map((x) => Text(x)).toList(),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
FutureBuilder(
|
||||
future: API.API().getActiveFlowsOf(widget.info.id),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const CircularProgressIndicator();
|
||||
}
|
||||
|
||||
var data = snapshot.data!;
|
||||
|
||||
return Expanded(
|
||||
child: ListView(
|
||||
children: data
|
||||
.map((x) => ListTile(
|
||||
title: Text(x.id),
|
||||
onTap: () =>
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
ActiveFlowPage(x, widget.info),
|
||||
))))
|
||||
.toList()),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => CreateFlowPage(widget.info, refresh)));
|
||||
},
|
||||
child: const Icon(Icons.add)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CreateFlowPage extends StatefulWidget {
|
||||
final API.FlowInfo info;
|
||||
final Function refresh;
|
||||
final API.Flow? previousFlow;
|
||||
|
||||
const CreateFlowPage(this.info, this.refresh, {this.previousFlow, super.key});
|
||||
|
||||
@override
|
||||
State<CreateFlowPage> createState() => _CreateFlowPageState();
|
||||
}
|
||||
|
||||
class _CreateFlowPageState extends State<CreateFlowPage> {
|
||||
List<API.Transaction> depends = [];
|
||||
|
||||
void _create(BuildContext context) {
|
||||
if (widget.previousFlow != null) {
|
||||
API
|
||||
.API()
|
||||
.continueFlow(widget.previousFlow!.id,
|
||||
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),
|
||||
));
|
||||
});
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
API
|
||||
.API()
|
||||
.startFlow(widget.info.id, input: depends.map((x) => x.uuid).toList())
|
||||
.then((flowID) {
|
||||
widget.refresh();
|
||||
API.API().getFlow(flowID).then((flow) {
|
||||
Navigator.of(context).pushReplacement(MaterialPageRoute(
|
||||
builder: (context) => ActiveFlowPage(flow, widget.info)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void selectDependItems(BuildContext context, String itemVariant) {
|
||||
var (item, variant) = API.itemVariant(itemVariant);
|
||||
|
||||
API.API().getInventoryOfVariant(item, variant).then((transactions) {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return TransactionSelectPage(transactions, onSelect: (t) {
|
||||
if (!depends.contains(t)) {
|
||||
setState(() {
|
||||
depends.add(t);
|
||||
});
|
||||
}
|
||||
}, exclude: depends);
|
||||
},
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
Widget buildInputSelection(BuildContext context) {
|
||||
return Column(
|
||||
children: widget.info.depends.map((x) {
|
||||
return ElevatedButton(
|
||||
onPressed: () {
|
||||
selectDependItems(context, x);
|
||||
},
|
||||
child: Text("Add $x"));
|
||||
}).toList());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text("Create new ${widget.info.name} Flow")),
|
||||
body: Column(
|
||||
children: [
|
||||
// todo : flow continuation overview
|
||||
buildInputSelection(context),
|
||||
const Divider(),
|
||||
Card(
|
||||
child: Column(
|
||||
children: depends
|
||||
.map((x) => TransactionCard(x, () {},
|
||||
onTap: (x) {}, onLongPress: (x) {}))
|
||||
.toList())),
|
||||
ElevatedButton(
|
||||
onPressed: () => _create(context),
|
||||
child: const Text("Create Flow"))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TransactionSelectPage extends StatelessWidget {
|
||||
final Function(API.Transaction) onSelect;
|
||||
final List<API.Transaction> selections;
|
||||
final List<API.Transaction>? exclude;
|
||||
|
||||
const TransactionSelectPage(this.selections,
|
||||
{super.key, required this.onSelect, this.exclude});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var selectionList = [];
|
||||
|
||||
for (var s in selections) {
|
||||
if (exclude?.any((x) => x.uuid == s.uuid) ?? false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
selectionList.add(s);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Select a Transaction"),
|
||||
),
|
||||
body: ListView(
|
||||
children: selections
|
||||
.map((x) => TransactionCard(
|
||||
x,
|
||||
() {},
|
||||
onLongPress: (x) {},
|
||||
onTap: (t) {
|
||||
onSelect(t);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
))
|
||||
.toList()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EndFlowWithProduce extends StatelessWidget {
|
||||
final API.Flow flow;
|
||||
final API.FlowInfo info;
|
||||
|
||||
const EndFlowWithProduce(this.flow, this.info, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// todo : show end screen with produce
|
||||
return Scaffold();
|
||||
}
|
||||
}
|
||||
|
||||
class ActiveFlowPage extends StatelessWidget {
|
||||
final API.Flow flow;
|
||||
final API.FlowInfo info;
|
||||
|
||||
const ActiveFlowPage(this.flow, this.info, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(info.name),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
if (info.produces?.isNotEmpty ?? false) {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => EndFlowWithProduce(flow, info)));
|
||||
return;
|
||||
}
|
||||
|
||||
// simple dialog
|
||||
var confirm = await showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Are you sure?'),
|
||||
content: const Text('This will end the flow.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: const Text('End'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (confirm) {
|
||||
await API
|
||||
.API()
|
||||
.endFlow(flow.id)
|
||||
.then((x) => Navigator.of(context).pop());
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.stop)),
|
||||
// todo : continue next flow
|
||||
if (info.next != null)
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
API.API().getFlowInfo(info.next!).then((newInfo) {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return CreateFlowPage(
|
||||
newInfo,
|
||||
() {},
|
||||
previousFlow: flow,
|
||||
);
|
||||
},
|
||||
));
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.arrow_forward)),
|
||||
|
||||
// todo : add notes to flow
|
||||
IconButton(onPressed: () {}, icon: const Icon(Icons.note))
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Text("ID: ${flow.id}"),
|
||||
Text("Started since: ${tsFormat(flow.started)}"),
|
||||
...flow.input!.map((x) => Text("Input: $x")).toList(),
|
||||
if (flow.done != null) ...[
|
||||
Text("Ended: ${tsFormat(flow.done!.ended)}"),
|
||||
if (flow.done!.next != null) Text("Next: ${flow.done!.next!}"),
|
||||
...flow.done!.produced!.map((x) => Text("Produced: $x")).toList(),
|
||||
],
|
||||
|
||||
const Divider(),
|
||||
// todo : show notes
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
92
lib/pages/flow/active_flow_page.dart
Normal file
92
lib/pages/flow/active_flow_page.dart
Normal file
|
@ -0,0 +1,92 @@
|
|||
import 'package:cdb_ui/api.dart' as API;
|
||||
import 'package:cdb_ui/pages/flow/create_flow_page.dart';
|
||||
import 'package:cdb_ui/pages/flow/end_flow_page.dart';
|
||||
import 'package:cdb_ui/pages/transaction.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ActiveFlowPage extends StatelessWidget {
|
||||
final API.Flow flow;
|
||||
final API.FlowInfo info;
|
||||
|
||||
const ActiveFlowPage(this.flow, this.info, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(info.name),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
if (info.produces?.isNotEmpty ?? false) {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => EndFlowWithProduce(flow, info)));
|
||||
return;
|
||||
}
|
||||
|
||||
// simple dialog
|
||||
var confirm = await showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Are you sure?'),
|
||||
content: const Text('This will end the flow.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: const Text('End'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (confirm) {
|
||||
await API
|
||||
.API()
|
||||
.endFlow(flow.id)
|
||||
.then((x) => Navigator.of(context).pop());
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.stop)),
|
||||
// todo : continue next flow
|
||||
if (info.next != null)
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
API.API().getFlowInfo(info.next!).then((newInfo) {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return CreateFlowPage(
|
||||
newInfo,
|
||||
() {},
|
||||
previousFlow: flow,
|
||||
);
|
||||
},
|
||||
));
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.arrow_forward)),
|
||||
|
||||
// todo : add notes to flow
|
||||
IconButton(onPressed: () {}, icon: const Icon(Icons.note))
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Text("ID: ${flow.id}"),
|
||||
Text("Started since: ${tsFormat(flow.started)}"),
|
||||
...flow.input!.map((x) => Text("Input: $x")).toList(),
|
||||
if (flow.done != null) ...[
|
||||
Text("Ended: ${tsFormat(flow.done!.ended)}"),
|
||||
if (flow.done!.next != null) Text("Next: ${flow.done!.next!}"),
|
||||
...flow.done!.produced!.map((x) => Text("Produced: $x")).toList(),
|
||||
],
|
||||
|
||||
const Divider(),
|
||||
// todo : show notes
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
102
lib/pages/flow/create_flow_page.dart
Normal file
102
lib/pages/flow/create_flow_page.dart
Normal file
|
@ -0,0 +1,102 @@
|
|||
import 'package:cdb_ui/api.dart' as API;
|
||||
import 'package:cdb_ui/pages/flow/active_flow_page.dart';
|
||||
import 'package:cdb_ui/pages/transaction.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
class CreateFlowPage extends StatefulWidget {
|
||||
final API.FlowInfo info;
|
||||
final Function refresh;
|
||||
final API.Flow? previousFlow;
|
||||
|
||||
const CreateFlowPage(this.info, this.refresh, {this.previousFlow, super.key});
|
||||
|
||||
@override
|
||||
State<CreateFlowPage> createState() => _CreateFlowPageState();
|
||||
}
|
||||
|
||||
class _CreateFlowPageState extends State<CreateFlowPage> {
|
||||
List<API.Transaction> depends = [];
|
||||
|
||||
void _create(BuildContext context) {
|
||||
if (widget.previousFlow != null) {
|
||||
API
|
||||
.API()
|
||||
.continueFlow(widget.previousFlow!.id,
|
||||
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),
|
||||
));
|
||||
});
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
API
|
||||
.API()
|
||||
.startFlow(widget.info.id, input: depends.map((x) => x.uuid).toList())
|
||||
.then((flowID) {
|
||||
widget.refresh();
|
||||
API.API().getFlow(flowID).then((flow) {
|
||||
Navigator.of(context).pushReplacement(MaterialPageRoute(
|
||||
builder: (context) => ActiveFlowPage(flow, widget.info)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void selectDependItems(BuildContext context, String itemVariant) {
|
||||
var (item, variant) = API.itemVariant(itemVariant);
|
||||
|
||||
API.API().getInventoryOfVariant(item, variant).then((transactions) {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return TransactionSelectPage(transactions, onSelect: (t) {
|
||||
if (!depends.contains(t)) {
|
||||
setState(() {
|
||||
depends.add(t);
|
||||
});
|
||||
}
|
||||
}, exclude: depends);
|
||||
},
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
Widget buildInputSelection(BuildContext context) {
|
||||
return Column(
|
||||
children: widget.info.depends.map((x) {
|
||||
return ElevatedButton(
|
||||
onPressed: () {
|
||||
selectDependItems(context, x);
|
||||
},
|
||||
child: Text("Add $x"));
|
||||
}).toList());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text("Create new ${widget.info.name} Flow")),
|
||||
body: Column(
|
||||
children: [
|
||||
// todo : flow continuation overview
|
||||
buildInputSelection(context),
|
||||
const Divider(),
|
||||
Card(
|
||||
child: Column(
|
||||
children: depends
|
||||
.map((x) => TransactionCard(x, () {},
|
||||
onTap: (x) {}, onLongPress: (x) {}))
|
||||
.toList())),
|
||||
ElevatedButton(
|
||||
onPressed: () => _create(context),
|
||||
child: const Text("Create Flow"))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
15
lib/pages/flow/end_flow_page.dart
Normal file
15
lib/pages/flow/end_flow_page.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
import 'package:cdb_ui/api.dart' as API;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class EndFlowWithProduce extends StatelessWidget {
|
||||
final API.Flow flow;
|
||||
final API.FlowInfo info;
|
||||
|
||||
const EndFlowWithProduce(this.flow, this.info, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// todo : show end screen with produce
|
||||
return Scaffold();
|
||||
}
|
||||
}
|
78
lib/pages/flow/flow_info_page.dart
Normal file
78
lib/pages/flow/flow_info_page.dart
Normal file
|
@ -0,0 +1,78 @@
|
|||
import 'package:cdb_ui/api.dart' as API;
|
||||
import 'package:cdb_ui/pages/flow/active_flow_page.dart';
|
||||
import 'package:cdb_ui/pages/flow/create_flow_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FlowInfoPage extends StatefulWidget {
|
||||
final API.FlowInfo info;
|
||||
|
||||
const FlowInfoPage(this.info, {super.key});
|
||||
|
||||
@override
|
||||
State<FlowInfoPage> createState() => _FlowInfoPageState();
|
||||
}
|
||||
|
||||
class _FlowInfoPageState extends State<FlowInfoPage> {
|
||||
void refresh() {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(widget.info.name)),
|
||||
body: Column(
|
||||
children: [
|
||||
// todo : ui improve
|
||||
if (widget.info.next != null) Text("Next: ${widget.info.next}"),
|
||||
if (widget.info.depends.isNotEmpty)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
const Text("Flow can use: "),
|
||||
...widget.info.depends.map((x) => Text(x)).toList(),
|
||||
],
|
||||
),
|
||||
if (widget.info.produces?.isNotEmpty ?? false)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
const Text("Flow can produce: "),
|
||||
...widget.info.produces!.map((x) => Text(x)).toList(),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
FutureBuilder(
|
||||
future: API.API().getActiveFlowsOf(widget.info.id),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const CircularProgressIndicator();
|
||||
}
|
||||
|
||||
var data = snapshot.data!;
|
||||
|
||||
return Expanded(
|
||||
child: ListView(
|
||||
children: data
|
||||
.map((x) => ListTile(
|
||||
title: Text(x.id),
|
||||
onTap: () =>
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
ActiveFlowPage(x, widget.info),
|
||||
))))
|
||||
.toList()),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (context) => CreateFlowPage(widget.info, refresh)));
|
||||
},
|
||||
child: const Icon(Icons.add)),
|
||||
);
|
||||
}
|
||||
}
|
161
lib/pages/flow/flows_page.dart
Normal file
161
lib/pages/flow/flows_page.dart
Normal file
|
@ -0,0 +1,161 @@
|
|||
import 'package:cdb_ui/api.dart' as API;
|
||||
import 'package:cdb_ui/pages/expandable_list.dart';
|
||||
import 'package:cdb_ui/pages/flow/flow_info_page.dart';
|
||||
import 'package:cdb_ui/pages/transaction.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FlowsPage extends StatefulWidget {
|
||||
const FlowsPage({super.key});
|
||||
|
||||
@override
|
||||
State<FlowsPage> createState() => _FlowsPageState();
|
||||
}
|
||||
|
||||
class _FlowsPageState extends State<FlowsPage> {
|
||||
int tabSelection = 0;
|
||||
Map<String, API.FlowInfo>? 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 listFlowInfoByActive(
|
||||
BuildContext context, Map<String, API.FlowInfo> infos) {
|
||||
return FutureBuilder(future: () async {
|
||||
var included = [];
|
||||
|
||||
for (var key in infos.keys) {
|
||||
var active = await API.API().getActiveFlowsOf(key);
|
||||
if (active.isNotEmpty) {
|
||||
included.add(infos[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return included;
|
||||
}(), builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const CircularProgressIndicator();
|
||||
}
|
||||
|
||||
var included = snapshot.data!;
|
||||
|
||||
return ListView(
|
||||
children: included.map((x) => flowTile(context, x)).toList());
|
||||
});
|
||||
}
|
||||
|
||||
Widget listAllFlowInfos(
|
||||
BuildContext context, Map<String, API.FlowInfo> infos) {
|
||||
return ListView(
|
||||
children: infos.values.map((x) {
|
||||
return flowTile(context, x);
|
||||
}).toList());
|
||||
}
|
||||
|
||||
Widget listFlowInfoByProduced(
|
||||
BuildContext context, Map<String, API.FlowInfo> infos) {
|
||||
Map<String, List<API.FlowInfo>> 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<ExpandableListItem> 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<String, API.FlowInfo> infos) {
|
||||
Map<String, List<API.FlowInfo>> 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<ExpandableListItem> 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) {
|
||||
if (flowInfos == null) {
|
||||
return const CircularProgressIndicator();
|
||||
}
|
||||
|
||||
return DefaultTabController(
|
||||
length: 4,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Flows"),
|
||||
bottom: TabBar(
|
||||
tabs: const [
|
||||
Tab(text: "All"),
|
||||
Tab(text: "Produces"),
|
||||
Tab(text: "Depends"),
|
||||
Tab(text: "Active")
|
||||
],
|
||||
onTap: (value) {
|
||||
setState(() {
|
||||
tabSelection = value;
|
||||
});
|
||||
},
|
||||
)),
|
||||
body: switch (tabSelection) {
|
||||
0 => listAllFlowInfos(context, flowInfos!),
|
||||
1 => listFlowInfoByProduced(context, flowInfos!),
|
||||
2 => listFlowInfoByDependant(context, flowInfos!),
|
||||
3 => listFlowInfoByActive(context, flowInfos!),
|
||||
_ => const Text("..."),
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -281,3 +281,43 @@ class IconText extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TransactionSelectPage extends StatelessWidget {
|
||||
final Function(Transaction) onSelect;
|
||||
final List<Transaction> selections;
|
||||
final List<Transaction>? exclude;
|
||||
|
||||
const TransactionSelectPage(this.selections,
|
||||
{super.key, required this.onSelect, this.exclude});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var selectionList = [];
|
||||
|
||||
for (var s in selections) {
|
||||
if (exclude?.any((x) => x.uuid == s.uuid) ?? false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
selectionList.add(s);
|
||||
}
|
||||
|
||||
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()),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue