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 = true; _active = false;
_periodicTimer = Timer.periodic(const Duration(seconds: 1), (Timer timer) { notifyListeners();
if (_tickCount == 0) { }
if (_currentRep + 1 ==
activity.actions[0].activityActionSet.reps.amounts[_currentSet]) { void stopTimer() {
_currentSet++; _active = false;
if (_currentSet == activity.actions[0].activityActionSet.total) { _periodicTimer?.cancel();
timer.cancel(); notifyListeners();
_active = false; }
setupTimer(activity);
} void startTimer() {
_currentRep = 0; if (_currentState == 'rep') {
_totalReps = // do nothing for now
activity.actions[0].activityActionSet.reps.amounts[_currentSet]; } else {
_tickCount = activity.actions[0].activityActionSet.rest ~/ 10000;
_active = true;
_tickCount = _activity.actions[0].activityActionSet.rest ~/ 10000;
_periodicTimer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
if (_tickCount == 0) {
incrementAction();
// 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 { } else {
_currentRep++; if (_active) {
_tickCount--;
}
} }
} else {
_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}'))); contents.add(Card(
elevation: 0.5,
// surfaceTintColor: actionCount == _index ? Colors.white : ,
clipBehavior: Clip.antiAlias,
child: GestureDetector(
onTap: () {
log('we tappn');
setState(() {
atm.setAction(currentAction, index, "rep");
});
},
child: Row(children: [
Consumer<ActivityTimerModel>(builder: (context, atm, child) {
return Ink(
padding: const EdgeInsets.all(15),
color: currentAction == atm.currentAction
? const Color.fromARGB(255, 49, 154, 52)
: const Color(0xff3A5FB6),
child: Text('Set: ${index + 1} '));
}),
Expanded(
child: Text(
textAlign: TextAlign.center,
'$title: ${setReps.amounts[index]} reps'))
]))));
actionCount++;
for (int repCount = 0; repCount < setReps.amounts[index]; repCount++) { contents.add(Card(
contents.add(Card( clipBehavior: Clip.antiAlias,
child: Padding( child: GestureDetector(
padding: const EdgeInsets.fromLTRB(15, 15, 15, 15), onTap: () {
child: Column( setState(() {
children: [ atm.setAction(currentAction + 1, index, "rest");
Row(children: [Text('Exercise: ${widget.action.title}')]), });
Row(children: [Text('Type: ${actionSet.type}')]), },
Row(children: [ child: Row(children: [
Text( Consumer<ActivityTimerModel>(builder: (context, atm, child) {
'Set: ${index + 1} / ${widget.action.activityActionSet.total}') return Ink(
]), padding: const EdgeInsets.all(15),
Row(children: [ color: currentAction + 1 == atm.currentAction
Text('Rep: ${repCount + 1} / ${setReps.amounts[index]}') ? const Color.fromARGB(255, 49, 154, 52)
]), : const Color(0xff3A5FB6),
Row(children: [Text('Tempo: ${setReps.tempo[index]}')]), child: Text('Set: ${index + 1} '));
Row(children: [ }),
Text('Weight: ${setReps.weights[index]}') Expanded(
]), child: Text(
Row(children: [Text('Rest: ${setReps.rest}')]) 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,55 +56,52 @@ 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) { height: MediaQuery.sizeOf(context).height * .07,
content.add(ActivityActionView(action: action)); color:
} ThemeData.dark(useMaterial3: true).colorScheme.primaryContainer,
child: Row(children: [
// add bottom bar to manage activity Expanded(
content.add(Container( flex: 1,
height: MediaQuery.sizeOf(context).height * .07, child: Flex(direction: Axis.horizontal, children: [
color: ThemeData.dark(useMaterial3: true).colorScheme.primaryContainer, IconButton(
child: Row(children: [ iconSize: 30,
Expanded( icon: const Icon(Icons.play_arrow_rounded),
flex: 1, onPressed: () => {
child: Flex(direction: Axis.horizontal, children: [ atm.startTimer()
IconButton( }),
iconSize: 30, IconButton(
icon: const Icon(Icons.play_arrow_rounded), iconSize: 36,
onPressed: () => icon: const Icon(Icons.skip_next_rounded),
atm.startTimer(activity)), onPressed: () {
IconButton( atm.incrementAction();
iconSize: 36, })
icon: const Icon(Icons.skip_next_rounded), ])),
onPressed: () {}) Expanded(
])), flex: 1,
Expanded( child: Consumer<ActivityTimerModel>(
flex: 1, builder: (context, atm, child) {
child: Consumer<ActivityTimerModel>(
builder: (context, atm, child) {
return Text(
style: const TextStyle(fontSize: 25),
textAlign: TextAlign.center,
'${atm.tickCount}');
},
)),
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: Consumer<ActivityTimerModel>(
builder: (context, atm, child) {
return Text( return Text(
style: const TextStyle(fontSize: 15), style: const TextStyle(fontSize: 25),
textAlign: TextAlign.right, textAlign: TextAlign.center,
'Set: ${atm.currentSet + 1}/${atm.totalSets}\nRep: ${atm.currentRep + 1}/${atm.totalReps}'); '${atm.tickCount}');
}))), },
]))); )),
return Column( Expanded(
crossAxisAlignment: CrossAxisAlignment.start, children: content); flex: 1,
child: Padding(
padding: const EdgeInsets.only(right: 10),
child: Consumer<ActivityTimerModel>(
builder: (context, atm, child) {
return Text(
style: const TextStyle(fontSize: 15),
textAlign: TextAlign.right,
'Set: ${atm.currentSet + 1}/${atm.totalSets}\nRep: ${atm.currentRep + 1}/${atm.totalReps}');
}))),
]))
]);
} }
} }

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']),
], ],