Make CRUD work for Plans
This commit is contained in:
parent
fb278e4487
commit
ea745c1cec
|
@ -1,6 +1,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:fmassive/gym_set.dart';
|
||||
import 'package:fmassive/gym_sets.dart';
|
||||
import 'package:fmassive/main.dart';
|
||||
import 'package:fmassive/plans.dart';
|
||||
import 'package:moor/ffi.dart';
|
||||
|
|
|
@ -1248,8 +1248,8 @@ class $GymSetsTable extends GymSets with TableInfo<$GymSetsTable, GymSet> {
|
|||
class Plan extends DataClass implements Insertable<Plan> {
|
||||
final int id;
|
||||
final String days;
|
||||
final String workouts;
|
||||
Plan({required this.id, required this.days, required this.workouts});
|
||||
final String? exercises;
|
||||
Plan({required this.id, required this.days, this.exercises});
|
||||
factory Plan.fromData(Map<String, dynamic> data, GeneratedDatabase db,
|
||||
{String? prefix}) {
|
||||
final effectivePrefix = prefix ?? '';
|
||||
|
@ -1258,8 +1258,8 @@ class Plan extends DataClass implements Insertable<Plan> {
|
|||
.mapFromDatabaseResponse(data['${effectivePrefix}id'])!,
|
||||
days: const StringType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}days'])!,
|
||||
workouts: const StringType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}workouts'])!,
|
||||
exercises: const StringType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}exercises']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
|
@ -1267,7 +1267,9 @@ class Plan extends DataClass implements Insertable<Plan> {
|
|||
final map = <String, Expression>{};
|
||||
map['id'] = Variable<int>(id);
|
||||
map['days'] = Variable<String>(days);
|
||||
map['workouts'] = Variable<String>(workouts);
|
||||
if (!nullToAbsent || exercises != null) {
|
||||
map['exercises'] = Variable<String?>(exercises);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
@ -1275,7 +1277,9 @@ class Plan extends DataClass implements Insertable<Plan> {
|
|||
return PlansCompanion(
|
||||
id: Value(id),
|
||||
days: Value(days),
|
||||
workouts: Value(workouts),
|
||||
exercises: exercises == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(exercises),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1285,7 +1289,7 @@ class Plan extends DataClass implements Insertable<Plan> {
|
|||
return Plan(
|
||||
id: serializer.fromJson<int>(json['id']),
|
||||
days: serializer.fromJson<String>(json['days']),
|
||||
workouts: serializer.fromJson<String>(json['workouts']),
|
||||
exercises: serializer.fromJson<String?>(json['exercises']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
|
@ -1294,69 +1298,68 @@ class Plan extends DataClass implements Insertable<Plan> {
|
|||
return <String, dynamic>{
|
||||
'id': serializer.toJson<int>(id),
|
||||
'days': serializer.toJson<String>(days),
|
||||
'workouts': serializer.toJson<String>(workouts),
|
||||
'exercises': serializer.toJson<String?>(exercises),
|
||||
};
|
||||
}
|
||||
|
||||
Plan copyWith({int? id, String? days, String? workouts}) => Plan(
|
||||
Plan copyWith({int? id, String? days, String? exercises}) => Plan(
|
||||
id: id ?? this.id,
|
||||
days: days ?? this.days,
|
||||
workouts: workouts ?? this.workouts,
|
||||
exercises: exercises ?? this.exercises,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('Plan(')
|
||||
..write('id: $id, ')
|
||||
..write('days: $days, ')
|
||||
..write('workouts: $workouts')
|
||||
..write('exercises: $exercises')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, days, workouts);
|
||||
int get hashCode => Object.hash(id, days, exercises);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is Plan &&
|
||||
other.id == this.id &&
|
||||
other.days == this.days &&
|
||||
other.workouts == this.workouts);
|
||||
other.exercises == this.exercises);
|
||||
}
|
||||
|
||||
class PlansCompanion extends UpdateCompanion<Plan> {
|
||||
final Value<int> id;
|
||||
final Value<String> days;
|
||||
final Value<String> workouts;
|
||||
final Value<String?> exercises;
|
||||
const PlansCompanion({
|
||||
this.id = const Value.absent(),
|
||||
this.days = const Value.absent(),
|
||||
this.workouts = const Value.absent(),
|
||||
this.exercises = const Value.absent(),
|
||||
});
|
||||
PlansCompanion.insert({
|
||||
this.id = const Value.absent(),
|
||||
required String days,
|
||||
required String workouts,
|
||||
}) : days = Value(days),
|
||||
workouts = Value(workouts);
|
||||
this.exercises = const Value.absent(),
|
||||
}) : days = Value(days);
|
||||
static Insertable<Plan> custom({
|
||||
Expression<int>? id,
|
||||
Expression<String>? days,
|
||||
Expression<String>? workouts,
|
||||
Expression<String?>? exercises,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (days != null) 'days': days,
|
||||
if (workouts != null) 'workouts': workouts,
|
||||
if (exercises != null) 'exercises': exercises,
|
||||
});
|
||||
}
|
||||
|
||||
PlansCompanion copyWith(
|
||||
{Value<int>? id, Value<String>? days, Value<String>? workouts}) {
|
||||
{Value<int>? id, Value<String>? days, Value<String?>? exercises}) {
|
||||
return PlansCompanion(
|
||||
id: id ?? this.id,
|
||||
days: days ?? this.days,
|
||||
workouts: workouts ?? this.workouts,
|
||||
exercises: exercises ?? this.exercises,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1369,8 +1372,8 @@ class PlansCompanion extends UpdateCompanion<Plan> {
|
|||
if (days.present) {
|
||||
map['days'] = Variable<String>(days.value);
|
||||
}
|
||||
if (workouts.present) {
|
||||
map['workouts'] = Variable<String>(workouts.value);
|
||||
if (exercises.present) {
|
||||
map['exercises'] = Variable<String?>(exercises.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
@ -1380,7 +1383,7 @@ class PlansCompanion extends UpdateCompanion<Plan> {
|
|||
return (StringBuffer('PlansCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('days: $days, ')
|
||||
..write('workouts: $workouts')
|
||||
..write('exercises: $exercises')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
@ -1403,13 +1406,13 @@ class $PlansTable extends Plans with TableInfo<$PlansTable, Plan> {
|
|||
late final GeneratedColumn<String?> days = GeneratedColumn<String?>(
|
||||
'days', aliasedName, false,
|
||||
type: const StringType(), requiredDuringInsert: true);
|
||||
final VerificationMeta _workoutsMeta = const VerificationMeta('workouts');
|
||||
final VerificationMeta _exercisesMeta = const VerificationMeta('exercises');
|
||||
@override
|
||||
late final GeneratedColumn<String?> workouts = GeneratedColumn<String?>(
|
||||
'workouts', aliasedName, false,
|
||||
type: const StringType(), requiredDuringInsert: true);
|
||||
late final GeneratedColumn<String?> exercises = GeneratedColumn<String?>(
|
||||
'exercises', aliasedName, true,
|
||||
type: const StringType(), requiredDuringInsert: false);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, days, workouts];
|
||||
List<GeneratedColumn> get $columns => [id, days, exercises];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'plans';
|
||||
@override
|
||||
|
@ -1428,11 +1431,9 @@ class $PlansTable extends Plans with TableInfo<$PlansTable, Plan> {
|
|||
} else if (isInserting) {
|
||||
context.missing(_daysMeta);
|
||||
}
|
||||
if (data.containsKey('workouts')) {
|
||||
context.handle(_workoutsMeta,
|
||||
workouts.isAcceptableOrUnknown(data['workouts']!, _workoutsMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_workoutsMeta);
|
||||
if (data.containsKey('exercises')) {
|
||||
context.handle(_exercisesMeta,
|
||||
exercises.isAcceptableOrUnknown(data['exercises']!, _exercisesMeta));
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@ import 'package:flutter/material.dart';
|
|||
|
||||
class Days extends StatefulWidget {
|
||||
final ValueChanged<String> onChanged;
|
||||
final String days;
|
||||
|
||||
const Days({required this.onChanged, super.key});
|
||||
const Days({required this.onChanged, required this.days, super.key});
|
||||
|
||||
@override
|
||||
createState() => _DaysState();
|
||||
}
|
||||
|
||||
class _DaysState extends State<Days> {
|
||||
final List<bool> _selections = List.generate(7, (_) => false);
|
||||
final List<String> _days = [
|
||||
'Monday',
|
||||
'Tuesday',
|
||||
|
@ -20,14 +20,19 @@ class _DaysState extends State<Days> {
|
|||
'Saturday',
|
||||
'Sunday'
|
||||
];
|
||||
late List<bool> _selections;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final dayList = widget.days.split(',');
|
||||
_selections = _days.map((day) => dayList.contains(day)).toList();
|
||||
}
|
||||
|
||||
String _getSelectedDaysString() {
|
||||
List<String> selectedDays = [];
|
||||
for (int i = 0; i < _selections.length; i++) {
|
||||
if (_selections[i]) {
|
||||
selectedDays.add(_days[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _selections.length; i++)
|
||||
if (_selections[i]) selectedDays.add(_days[i]);
|
||||
return selectedDays.join(",");
|
||||
}
|
||||
|
||||
|
@ -40,14 +45,19 @@ class _DaysState extends State<Days> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: List.generate(7, (index) {
|
||||
return SwitchListTile(
|
||||
title: Text(_days[index]),
|
||||
value: _selections[index],
|
||||
onChanged: (value) => _updateSelections(index),
|
||||
);
|
||||
}),
|
||||
);
|
||||
return Column(children: [
|
||||
Text('Days', style: Theme.of(context).textTheme.headlineSmall),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: List.generate(7, (index) {
|
||||
return SwitchListTile(
|
||||
title: Text(_days[index]),
|
||||
value: _selections[index],
|
||||
onChanged: (value) => _updateSelections(index),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/material.dart' as material;
|
||||
import 'package:fmassive/database.dart';
|
||||
import 'package:fmassive/days.dart';
|
||||
import 'package:fmassive/exercises.dart';
|
||||
import 'package:fmassive/main.dart';
|
||||
import 'package:moor_flutter/moor_flutter.dart';
|
||||
|
||||
|
@ -15,28 +16,31 @@ class EditPlanPage extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _EditPlanPageState extends State<EditPlanPage> {
|
||||
final TextEditingController _daysController = TextEditingController();
|
||||
final TextEditingController _workoutsController = TextEditingController();
|
||||
late PlansCompanion plan;
|
||||
final daysNode = FocusNode();
|
||||
final workoutsNode = FocusNode();
|
||||
List<String?> names = [];
|
||||
|
||||
Future<List<String?>> getDistinctNames() async {
|
||||
final names = await (db.gymSets.selectOnly(distinct: true)
|
||||
..addColumns([db.gymSets.name]))
|
||||
.get();
|
||||
return names.map((name) => name.read(db.gymSets.name)).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
getDistinctNames().then((value) {
|
||||
setState(() {
|
||||
names = value;
|
||||
});
|
||||
});
|
||||
|
||||
plan = widget.plan;
|
||||
_daysController.text = plan.days.value;
|
||||
_workoutsController.text = plan.workouts.value;
|
||||
if (plan.id.present)
|
||||
workoutsNode.requestFocus();
|
||||
else
|
||||
daysNode.requestFocus();
|
||||
}
|
||||
|
||||
@override
|
||||
dispose() {
|
||||
daysNode.dispose();
|
||||
workoutsNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -59,38 +63,11 @@ class _EditPlanPageState extends State<EditPlanPage> {
|
|||
padding: const EdgeInsets.all(16.0),
|
||||
child: material.Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Days(onChanged: (days) {
|
||||
setState(() {
|
||||
days = days;
|
||||
});
|
||||
}),
|
||||
TextFormField(
|
||||
controller: _workoutsController,
|
||||
focusNode: workoutsNode,
|
||||
onTap: () {
|
||||
_workoutsController.selection = TextSelection(
|
||||
baseOffset: 0,
|
||||
extentOffset: _workoutsController.text.length);
|
||||
},
|
||||
decoration: const InputDecoration(labelText: 'Workouts'),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
plan = plan.copyWith(workouts: Value(value));
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
children: getChildren,
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () async {
|
||||
if (_daysController.text.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Please enter days')));
|
||||
daysNode.requestFocus();
|
||||
return;
|
||||
}
|
||||
if (plan.id.present)
|
||||
await db.update(db.plans).replace(plan);
|
||||
else
|
||||
|
@ -102,4 +79,32 @@ class _EditPlanPageState extends State<EditPlanPage> {
|
|||
),
|
||||
));
|
||||
}
|
||||
|
||||
List<Widget> get getChildren {
|
||||
return [
|
||||
Expanded(
|
||||
child: Days(
|
||||
onChanged: (days) {
|
||||
setState(() {
|
||||
plan = plan.copyWith(days: Value(days));
|
||||
});
|
||||
},
|
||||
days: plan.days.value,
|
||||
),
|
||||
),
|
||||
names.isNotEmpty
|
||||
? Expanded(
|
||||
child: Exercises(
|
||||
onChanged: (exercises) {
|
||||
setState(() {
|
||||
plan = plan.copyWith(exercises: Value(exercises));
|
||||
});
|
||||
},
|
||||
exercises: plan.exercises.value,
|
||||
names: names,
|
||||
),
|
||||
)
|
||||
: const CircularProgressIndicator(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
60
lib/exercises.dart
Normal file
60
lib/exercises.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class Exercises extends StatefulWidget {
|
||||
final ValueChanged<String> onChanged;
|
||||
final String? exercises;
|
||||
final List<String?> names;
|
||||
|
||||
const Exercises(
|
||||
{required this.onChanged,
|
||||
required this.exercises,
|
||||
super.key,
|
||||
required this.names});
|
||||
|
||||
@override
|
||||
createState() => _ExercisesState();
|
||||
}
|
||||
|
||||
class _ExercisesState extends State<Exercises> {
|
||||
late List<bool> _selections;
|
||||
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
final exercises = widget.exercises?.split(',');
|
||||
_selections =
|
||||
widget.names.map((name) => exercises?.contains(name) ?? false).toList();
|
||||
}
|
||||
|
||||
String _getExercises() {
|
||||
List<String> exercises = [];
|
||||
for (int i = 0; i < _selections.length; i++)
|
||||
if (_selections[i]) exercises.add(widget.names[i] ?? '');
|
||||
return exercises.join(",");
|
||||
}
|
||||
|
||||
void _updateSelections(int index) {
|
||||
setState(() {
|
||||
_selections[index] = !_selections[index];
|
||||
widget.onChanged(_getExercises());
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(children: [
|
||||
Text('Exercises', style: Theme.of(context).textTheme.headlineSmall),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: List.generate(widget.names.length, (index) {
|
||||
return SwitchListTile(
|
||||
title: Text(widget.names[index] ?? ''),
|
||||
value: _selections[index],
|
||||
onChanged: (value) => _updateSelections(index),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -3,5 +3,5 @@ import 'package:moor/moor.dart';
|
|||
class Plans extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get days => text()();
|
||||
TextColumn get workouts => text()();
|
||||
TextColumn get exercises => text().nullable()();
|
||||
}
|
||||
|
|
|
@ -73,8 +73,8 @@ class _PlansPageState extends State<_PlansPage> {
|
|||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text(plans[index].days.replaceAll(',', ', ')),
|
||||
subtitle:
|
||||
Text(plans[index].workouts.replaceAll(',', ', ')),
|
||||
subtitle: Text(
|
||||
plans[index].exercises?.replaceAll(',', ', ') ?? ''),
|
||||
onTap: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
|
@ -93,8 +93,8 @@ class _PlansPageState extends State<_PlansPage> {
|
|||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const EditPlanPage(
|
||||
plan:
|
||||
PlansCompanion(days: Value(''), workouts: Value(''))),
|
||||
plan: PlansCompanion(
|
||||
days: Value(''), exercises: Value(''))),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue
Block a user