Brandon Presley
6908623ba2
This just messes up our navigation stack too much and makes it confusing when you go backwards.
192 lines
6.0 KiB
Dart
192 lines
6.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/material.dart' as material;
|
|
import 'package:flutter/services.dart';
|
|
import 'package:fmassive/database.dart';
|
|
import 'package:fmassive/main.dart';
|
|
import 'package:moor_flutter/moor_flutter.dart';
|
|
|
|
class StartPlan extends StatefulWidget {
|
|
final PlansCompanion plan;
|
|
|
|
const StartPlan({required this.plan, super.key});
|
|
|
|
@override
|
|
createState() => _StartPlanState();
|
|
}
|
|
|
|
class _StartPlanState extends State<StartPlan> {
|
|
late List<String> exercises;
|
|
List<int> counts = [];
|
|
List<int> totals = [];
|
|
int selectedExercise = 0;
|
|
final repsController = TextEditingController();
|
|
final repsNode = FocusNode();
|
|
final weightController = TextEditingController();
|
|
final weightNode = FocusNode();
|
|
|
|
Future<void> getTotals() async {
|
|
final query = await (db.selectOnly(db.gymSets)
|
|
..addColumns([db.gymSets.name, db.gymSets.sets])
|
|
..where(db.gymSets.name.isIn(exercises))
|
|
..groupBy([db.gymSets.name, db.gymSets.sets]))
|
|
.map(
|
|
(row) =>
|
|
MapEntry(row.read(db.gymSets.name), row.read(db.gymSets.sets)),
|
|
)
|
|
.get();
|
|
final map = Map.fromIterables(
|
|
query.map((entry) => entry.key),
|
|
query.map((entry) => entry.value),
|
|
);
|
|
setState(() {
|
|
totals = [];
|
|
for (var exercise in exercises) {
|
|
totals.add(map[exercise] ?? 0);
|
|
}
|
|
});
|
|
print("totals=$totals");
|
|
}
|
|
|
|
Future<void> getCounts() async {
|
|
var countExp = db.gymSets.name.count();
|
|
final today = DateTime.now().toIso8601String().split('T')[0];
|
|
final query = await (db.selectOnly(db.gymSets)
|
|
..addColumns([countExp, db.gymSets.name])
|
|
..where(db.gymSets.created.contains(today))
|
|
..groupBy([db.gymSets.name]))
|
|
.map((row) => MapEntry(row.read(db.gymSets.name), row.read(countExp)))
|
|
.get();
|
|
final map = Map.fromIterables(
|
|
query.map((entry) => entry.key),
|
|
query.map((entry) => entry.value),
|
|
);
|
|
setState(() {
|
|
counts = [];
|
|
for (var exercise in exercises) {
|
|
counts.add(map[exercise] ?? 0);
|
|
}
|
|
});
|
|
print("counts=$counts");
|
|
}
|
|
|
|
Future<void> focus(int index) async {
|
|
final name = exercises[index];
|
|
final sets = await (db.gymSets.select()
|
|
..where((gymSet) => gymSet.name.contains(name))
|
|
..orderBy([
|
|
(u) => OrderingTerm(expression: u.created, mode: OrderingMode.desc),
|
|
])
|
|
..limit(1))
|
|
.get();
|
|
final firstSet = sets.first;
|
|
repsController.text = firstSet.reps.toString();
|
|
repsController.selection = TextSelection(
|
|
baseOffset: 0,
|
|
extentOffset: firstSet.reps.toString().length,
|
|
);
|
|
weightController.text = firstSet.weight.toString();
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
exercises = widget.plan.exercises.value.split(',');
|
|
repsNode.requestFocus();
|
|
|
|
getCounts();
|
|
getTotals();
|
|
|
|
focus(selectedExercise);
|
|
}
|
|
|
|
@override
|
|
dispose() {
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (totals.isEmpty || counts.isEmpty) return Container();
|
|
|
|
return SafeArea(
|
|
child: Scaffold(
|
|
appBar: AppBar(title: const Text('Start plan')),
|
|
body: Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: material.Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Expanded(
|
|
child: ListView.builder(
|
|
itemBuilder: ((context, index) {
|
|
return ListTile(
|
|
title: Text(exercises[index]),
|
|
subtitle: Text("${counts[index]}/${totals[index]}"),
|
|
onTap: () {
|
|
setState(() {
|
|
selectedExercise = index;
|
|
focus(index);
|
|
});
|
|
},
|
|
leading: Radio<int>(
|
|
value: index,
|
|
groupValue: selectedExercise,
|
|
onChanged: (value) {
|
|
print("onChanged $value");
|
|
if (value == null) return;
|
|
setState(() {
|
|
selectedExercise = value;
|
|
focus(index);
|
|
});
|
|
},
|
|
),
|
|
);
|
|
}),
|
|
itemCount: exercises.length,
|
|
),
|
|
),
|
|
TextFormField(
|
|
decoration: const InputDecoration(labelText: 'Reps'),
|
|
controller: repsController,
|
|
focusNode: repsNode,
|
|
onTap: () {
|
|
repsController.selection = TextSelection(
|
|
baseOffset: 0,
|
|
extentOffset: repsController.text.length,
|
|
);
|
|
},
|
|
),
|
|
TextFormField(
|
|
decoration: const InputDecoration(labelText: 'Weight'),
|
|
controller: weightController,
|
|
focusNode: weightNode,
|
|
onTap: () {
|
|
weightController.selection = TextSelection(
|
|
baseOffset: 0,
|
|
extentOffset: weightController.text.length,
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
floatingActionButton: FloatingActionButton(
|
|
onPressed: () async {
|
|
final gymSet = GymSetsCompanion(
|
|
created: Value(DateTime.now().toIso8601String()),
|
|
name: Value(exercises[selectedExercise]),
|
|
reps: Value(int.tryParse(repsController.text) ?? 0),
|
|
weight: Value(double.tryParse(weightController.text) ?? 0),
|
|
);
|
|
await db.into(db.gymSets).insert(gymSet);
|
|
const platform = MethodChannel('com.massive/android');
|
|
platform.invokeMethod('timer', [180000]);
|
|
await getCounts();
|
|
},
|
|
child: const Icon(Icons.check),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|