setting up timer and action management

This commit is contained in:
Joshua Burman 2024-12-01 21:23:12 -05:00
parent 9ffa0d178c
commit 29479e8aba
4 changed files with 257 additions and 118 deletions

View File

@ -1,7 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sendtrain/models/activity_model.dart'; import 'package:sendtrain/models/activity_model.dart';
import 'package:sendtrain/widgets/activity_action_view.dart';
class ActivityTimerModel with ChangeNotifier { class ActivityTimerModel with ChangeNotifier {
late int _activityId; late int _activityId;
@ -12,49 +14,135 @@ class ActivityTimerModel with ChangeNotifier {
late int _totalReps; late int _totalReps;
late String _currentState; late String _currentState;
late Timer? _periodicTimer; late Timer? _periodicTimer;
late ActivityModel _activity;
// int _viewCount = 0;
bool _active = false; bool _active = false;
int _currentAction = 0;
int get tickCount => _tickCount; int get tickCount => _tickCount;
int get currentSet => _currentSet; int get currentSet => _currentSet;
int get currentRep => _currentRep; int get currentRep => _currentRep;
int get currentAction => _currentAction;
int get totalSets => _totalSets; int get totalSets => _totalSets;
int get totalReps => _totalReps; int get totalReps => _totalReps;
bool get active => _active; bool get active => _active;
void setAction(int actionNum, int setNum, String state) {
_currentAction = actionNum;
_currentSet = setNum;
_currentState = state;
stopTimer();
if (_currentState == "rest") {
startTimer();
}
notifyListeners();
}
void incrementAction() {
_currentAction++;
if (_currentState == "rest") {
_currentState = "rep";
_currentSet++;
stopTimer();
} else {
_currentState = "rest";
startTimer();
}
notifyListeners();
}
void setupTimer(ActivityModel activity) { void setupTimer(ActivityModel activity) {
_activity = activity;
_activityId = activity.id; _activityId = activity.id;
_currentSet = 0; _currentSet = 0;
_currentRep = 0; _currentRep = 0;
_totalSets = activity.actions[0].activityActionSet.total; _totalSets = activity.actions[0].activityActionSet.total;
_totalReps = activity.actions[0].activityActionSet.reps.amounts[0]; _totalReps = activity.actions[0].activityActionSet.reps.amounts[0];
_tickCount = activity.actions[0].activityActionSet.rest ~/ 10000; _tickCount = activity.actions[0].activityActionSet.rest ~/ 10000;
_currentState = "rep";
// ActivityActionView av = actionViews[_viewCount];
// av.
} }
void startTimer(ActivityModel activity) { void pauseTimer() {
_active = false;
notifyListeners();
}
void stopTimer() {
_active = false;
_periodicTimer?.cancel();
notifyListeners();
}
void startTimer() {
if (_currentState == 'rep') {
// do nothing for now
} else {
_active = true; _active = true;
_tickCount = _activity.actions[0].activityActionSet.rest ~/ 10000;
_periodicTimer = Timer.periodic(const Duration(seconds: 1), (Timer timer) { _periodicTimer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
if (_tickCount == 0) { if (_tickCount == 0) {
if (_currentRep + 1 == incrementAction();
activity.actions[0].activityActionSet.reps.amounts[_currentSet]) {
_currentSet++;
if (_currentSet == activity.actions[0].activityActionSet.total) { // if (_currentRep + 1 ==
timer.cancel(); // _activity.actions[0].activityActionSet.reps.amounts[_currentSet]) {
_active = false; // _currentSet++;
setupTimer(activity); // if (_currentSet == _activity.actions[0].activityActionSet.total) {
} // timer.cancel();
_currentRep = 0; // _active = false;
_totalReps = // setupTimer(_activity);
activity.actions[0].activityActionSet.reps.amounts[_currentSet]; // }
_tickCount = activity.actions[0].activityActionSet.rest ~/ 10000; // _currentRep = 0;
} else { // _totalReps =
_currentRep++; // _activity.actions[0].activityActionSet.reps.amounts[_currentSet];
} // _tickCount = _activity.actions[0].activityActionSet.rest ~/ 10000;
// } else {
// _currentRep++;
// }
} else { } else {
if (_active) {
_tickCount--; _tickCount--;
} }
}
notifyListeners(); notifyListeners();
}); });
} }
}
// void startTimer(ActivityModel activity) {
// _active = true;
// _periodicTimer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
// if (_tickCount == 0) {
// if (_currentRep + 1 ==
// activity.actions[0].activityActionSet.reps.amounts[_currentSet]) {
// _currentSet++;
// if (_currentSet == activity.actions[0].activityActionSet.total) {
// timer.cancel();
// _active = false;
// setupTimer(activity);
// }
// _currentRep = 0;
// _totalReps =
// activity.actions[0].activityActionSet.reps.amounts[_currentSet];
// _tickCount = activity.actions[0].activityActionSet.rest ~/ 10000;
// } else {
// _currentRep++;
// }
// } else {
// _tickCount--;
// }
// notifyListeners();
// });
// }
} }

View File

@ -1,21 +1,47 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:sendtrain/classes/activity_action.dart'; import 'package:sendtrain/classes/activity_action.dart';
import 'package:sendtrain/models/activity_timer_model.dart';
import 'package:sendtrain/widgets/action_card.dart'; import 'package:sendtrain/widgets/action_card.dart';
class ActivityActionView extends StatefulWidget { class ActivityActionView extends StatefulWidget {
ActivityActionView({super.key, required this.action}); ActivityActionView({super.key, required this.action});
ActivityAction action; ActivityAction action;
// ActivityTimerModel activityTimerModel;
// get incrementActivity => ActivityActionViewState().incrementActivity();
@override @override
State<ActivityActionView> createState() => _ActivityActionViewState(); State<ActivityActionView> createState() => ActivityActionViewState();
// void incrementActivity() => _ActivityActionViewState().incrementActivity();
} }
class _ActivityActionViewState extends State<ActivityActionView> { class ActivityActionViewState extends State<ActivityActionView> {
int _index = 0;
int _currentAction = 0;
// int _actionCount = 0;
// int _currentState = "Active"
// void incrementActivity(int actionNum) {
// setState(() {
// atm.setAction(actionNum);
// });
// }
// void setActivity(int currentAction) {
// setState(() {
// widget.atm.setAction(currentAction);
// });
// }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
int actionCount = 0;
ActivityTimerModel atm = Provider.of<ActivityTimerModel>(context, listen: true);
return Expanded( return Expanded(
child: ListView.builder( child: ListView.builder(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
@ -23,34 +49,61 @@ class _ActivityActionViewState extends State<ActivityActionView> {
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
String title = widget.action.title; String title = widget.action.title;
Set actionSet = widget.action.activityActionSet; Set actionSet = widget.action.activityActionSet;
Reps setReps = widget.action.activityActionSet.reps; Reps setReps = actionSet.reps;
int setRest = actionSet.rest ~/ 1000;
List<Card> contents = []; List<Card> contents = [];
int currentAction = actionCount;
// contents.add(Card(child: Text('Set ${index + 1}')));
for (int repCount = 0; repCount < setReps.amounts[index]; repCount++) {
contents.add(Card( contents.add(Card(
child: Padding( elevation: 0.5,
padding: const EdgeInsets.fromLTRB(15, 15, 15, 15), // surfaceTintColor: actionCount == _index ? Colors.white : ,
child: Column( clipBehavior: Clip.antiAlias,
children: [ child: GestureDetector(
Row(children: [Text('Exercise: ${widget.action.title}')]), onTap: () {
Row(children: [Text('Type: ${actionSet.type}')]), log('we tappn');
Row(children: [ setState(() {
Text( atm.setAction(currentAction, index, "rep");
'Set: ${index + 1} / ${widget.action.activityActionSet.total}') });
]), },
Row(children: [ child: Row(children: [
Text('Rep: ${repCount + 1} / ${setReps.amounts[index]}') Consumer<ActivityTimerModel>(builder: (context, atm, child) {
]), return Ink(
Row(children: [Text('Tempo: ${setReps.tempo[index]}')]), padding: const EdgeInsets.all(15),
Row(children: [ color: currentAction == atm.currentAction
Text('Weight: ${setReps.weights[index]}') ? const Color.fromARGB(255, 49, 154, 52)
]), : const Color(0xff3A5FB6),
Row(children: [Text('Rest: ${setReps.rest}')]) child: Text('Set: ${index + 1} '));
], }),
)))); Expanded(
} child: Text(
textAlign: TextAlign.center,
'$title: ${setReps.amounts[index]} reps'))
]))));
actionCount++;
contents.add(Card(
clipBehavior: Clip.antiAlias,
child: GestureDetector(
onTap: () {
setState(() {
atm.setAction(currentAction + 1, index, "rest");
});
},
child: Row(children: [
Consumer<ActivityTimerModel>(builder: (context, atm, child) {
return Ink(
padding: const EdgeInsets.all(15),
color: currentAction + 1 == atm.currentAction
? const Color.fromARGB(255, 49, 154, 52)
: const Color(0xff3A5FB6),
child: Text('Set: ${index + 1} '));
}),
Expanded(
child: Text(
textAlign: TextAlign.center,
'Rest: $setRest seconds'))
]))));
actionCount++;
return Column(children: contents); return Column(children: contents);
}, },

View File

@ -9,7 +9,6 @@ import 'package:sendtrain/widgets/media_card.dart';
class ActivityView extends StatefulWidget { class ActivityView extends StatefulWidget {
ActivityView({super.key, required this.activity}); ActivityView({super.key, required this.activity});
ActivityModel activity; ActivityModel activity;
@override @override
@ -20,14 +19,16 @@ class _ActivityViewState extends State<ActivityView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
ActivityModel activity = widget.activity; ActivityModel activity = widget.activity;
ActivityTimerModel atm =
ActivityTimerModel atm = Provider.of<ActivityTimerModel>(context, listen: false); Provider.of<ActivityTimerModel>(context, listen: false);
// ActivityActionView activityActionView =
// ActivityActionView(action: activity.actions[0]);
if (atm.active == false) { if (atm.active == false) {
atm.setupTimer(activity); atm.setupTimer(activity);
} }
var content = [ return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
AppBar( AppBar(
// surfaceTintColor: ThemeData.dark(useMaterial3: true).colorScheme.primary, // surfaceTintColor: ThemeData.dark(useMaterial3: true).colorScheme.primary,
// backgroundColor: ThemeData.dark(useMaterial3: true).colorScheme.primaryContainer, // backgroundColor: ThemeData.dark(useMaterial3: true).colorScheme.primaryContainer,
@ -55,17 +56,12 @@ class _ActivityViewState extends State<ActivityView> {
child: Text( child: Text(
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
'Actions:')) 'Actions:')),
]; ActivityActionView(action: activity.actions[0]),
Container(
for (var action in activity.actions) {
content.add(ActivityActionView(action: action));
}
// add bottom bar to manage activity
content.add(Container(
height: MediaQuery.sizeOf(context).height * .07, height: MediaQuery.sizeOf(context).height * .07,
color: ThemeData.dark(useMaterial3: true).colorScheme.primaryContainer, color:
ThemeData.dark(useMaterial3: true).colorScheme.primaryContainer,
child: Row(children: [ child: Row(children: [
Expanded( Expanded(
flex: 1, flex: 1,
@ -73,12 +69,15 @@ class _ActivityViewState extends State<ActivityView> {
IconButton( IconButton(
iconSize: 30, iconSize: 30,
icon: const Icon(Icons.play_arrow_rounded), icon: const Icon(Icons.play_arrow_rounded),
onPressed: () => onPressed: () => {
atm.startTimer(activity)), atm.startTimer()
}),
IconButton( IconButton(
iconSize: 36, iconSize: 36,
icon: const Icon(Icons.skip_next_rounded), icon: const Icon(Icons.skip_next_rounded),
onPressed: () {}) onPressed: () {
atm.incrementAction();
})
])), ])),
Expanded( Expanded(
flex: 1, flex: 1,
@ -101,9 +100,8 @@ class _ActivityViewState extends State<ActivityView> {
textAlign: TextAlign.right, textAlign: TextAlign.right,
'Set: ${atm.currentSet + 1}/${atm.totalSets}\nRep: ${atm.currentRep + 1}/${atm.totalReps}'); 'Set: ${atm.currentSet + 1}/${atm.totalSets}\nRep: ${atm.currentRep + 1}/${atm.totalReps}');
}))), }))),
]))); ]))
return Column( ]);
crossAxisAlignment: CrossAxisAlignment.start, children: content);
} }
} }

View File

@ -39,8 +39,8 @@ class SessionCard extends StatelessWidget {
actions: [ actions: [
ActivityAction( ActivityAction(
id: 1, id: 1,
title: 'test action', title: '1, 3, 5',
description: 'test description', description: 'Move between the first, third, and fifth rungs, alternating hands. Rest and alternate sides, to start',
media: [ media: [
Media( Media(
id: 1, id: 1,
@ -76,8 +76,8 @@ class SessionCard extends StatelessWidget {
actions: [ actions: [
ActivityAction( ActivityAction(
id: 1, id: 1,
title: 'test action', title: 'Attempt Climb',
description: 'test description', description: 'Attempt your selected climb, if you fall off early in the climb, attempt again. 1 repitition equals roughly doing all the moves, not necessarily in 1 attempt.',
media: [ media: [
Media( Media(
id: 1, id: 1,
@ -92,15 +92,15 @@ class SessionCard extends StatelessWidget {
description: 'How to project climbs') description: 'How to project climbs')
], ],
activityActionSet: Set( activityActionSet: Set(
type: 'drop_set', type: 'standard',
total: 3, total: 10,
rest: 300000, rest: 300000,
reps: Reps( reps: Reps(
type: 'count', type: 'count',
tempo: [2, 3, 5], tempo: [],
amounts: [5, 3, 2], amounts: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
weights: [50, 70, 80], weights: [],
rest: 20000))), rest: 0))),
], ],
resources: ['https://www.youtube.com/watch?v=dyAvbUvY_PU']), resources: ['https://www.youtube.com/watch?v=dyAvbUvY_PU']),
ActivityModel( ActivityModel(
@ -113,8 +113,8 @@ class SessionCard extends StatelessWidget {
actions: [ actions: [
ActivityAction( ActivityAction(
id: 1, id: 1,
title: 'test action', title: 'Pull Ups',
description: 'test description', description: 'Select your desired weight to add, and pull up. Be sure to fully drop into extension at start, and make sure chin is above bar for a complete rep. Do not kip during the movement.',
media: [ media: [
Media( Media(
id: 1, id: 1,
@ -130,14 +130,14 @@ class SessionCard extends StatelessWidget {
], ],
activityActionSet: Set( activityActionSet: Set(
type: 'drop_set', type: 'drop_set',
total: 3, total: 5,
rest: 300000, rest: 300000,
reps: Reps( reps: Reps(
type: 'count', type: 'count',
tempo: [2, 3, 5], tempo: [],
amounts: [5, 3, 2], amounts: [3, 5, 5, 3, 6],
weights: [50, 70, 80], weights: [80, 80, 80, 80, 80],
rest: 20000))), rest: 0))),
], ],
resources: ['https://www.youtube.com/watch?v=dyAvbUvY_PU']), resources: ['https://www.youtube.com/watch?v=dyAvbUvY_PU']),
], ],