diff --git a/lib/classes/activity_action.dart b/lib/classes/activity_action.dart index 8c1ece1..79caba1 100644 --- a/lib/classes/activity_action.dart +++ b/lib/classes/activity_action.dart @@ -14,6 +14,64 @@ class ActivityAction { required this.activityActionSet, this.media, }); + + List>> items() { + List>> sets = []; + Reps reps = activityActionSet.reps; + + for (int i = 0; i < activityActionSet.total; i++) { + List> actions = []; + int? weight = _setWeight(i); + + actions.add({ + 'name': title, + 'type': reps.type, + 'amount': reps.amounts[i], + 'weight': weight, + }); + + if (activityActionSet.type == 'alternating') { + if (reps.rest != null) { + actions.add({ + 'name': 'Rest', + 'type': 'seconds', + 'amount': reps.amounts[i], + }); + } + + actions.add({ + 'name': title, + 'type': reps.type, + 'amount': reps.amounts[i], + 'weights': weight, + }); + } + + actions.add({ + 'name': 'Rest', + 'type': 'seconds', + 'amount': activityActionSet.rest ~/ 1000, + }); + + sets.add(actions); + + // for (int j = 0; i < activityActionSet.reps.amounts; j++) {} + } + + return sets; + } + + int? _setWeight(setNum) { + Reps reps = activityActionSet.reps; + + if (reps.weights.length == activityActionSet.total) { + return reps.weights[setNum]; + } else if (reps.weights.length == 1) { + return reps.weights[0]; + } + + return null; + } } class Set { @@ -34,14 +92,14 @@ class Reps { String type; List tempo; List amounts; - List weights; - int rest; + List weights = []; + int? rest; Reps({ required this.type, required this.tempo, required this.amounts, required this.weights, - required this.rest, + this.rest, }); } diff --git a/lib/models/activity_timer_model.dart b/lib/models/activity_timer_model.dart index 5fe34b8..e2a8753 100644 --- a/lib/models/activity_timer_model.dart +++ b/lib/models/activity_timer_model.dart @@ -1,103 +1,171 @@ import 'dart:async'; +import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:sendtrain/models/activity_model.dart'; class ActivityTimerModel with ChangeNotifier { - int _tickCount = 0; - int _currentAction = 0; + int _actionCount = 0; ActivityModel? _activity; + List _actions = []; + int _currentActionNum = 0; + int _currentSetNum = 0; Timer? _periodicTimer; - List _actionMap = []; - int get tickCount => _tickCount; - int get currentAction => _currentAction; + int get actionCount => _actionCount; + int get currentActionNum => _currentActionNum; + int get currentSetNum => _currentSetNum; ActivityModel? get activity => _activity; + List get actions => _actions; Timer? get periodicTimer => _periodicTimer; - String get actionType => _actionMap[_currentAction]; - String get setType => _activity != null - ? _activity!.actions[0].activityActionSet.reps.type - : 'n/a'; - String? get repType => actionState(); + String get currentActionType => _actions[_currentSetNum][_currentActionNum]['type']; + void get pause => _periodicTimer!.cancel(); void setup(ActivityModel activity) { - // if there isn't an activity yet - // or we're coming from another activity - // setup new timer - if (_activity == null || activity.id != _activity?.id) { - _periodicTimer?.cancel(); - _activity = activity; - _currentAction = 0; - _actionMap = []; - // for now we just do alternating rest/sets - // in the future, we'll make this more modifiable - int totalActions = activity.actions[0].activityActionSet.total; - // log(activity.actions[0].activityActionSet.type); - // if (activity.actions[0].activityActionSet.type == 'alternating') { - // totalActions = totalActions * 4; - // log('were in $totalActions'); - // } - - for (int i = 0; i < totalActions; i++) { - _actionMap.addAll(['Set', 'Rest']); - } - getValue(); - } - } - - String actionState() { - if (actionType == 'Set') { - return setType == 'seconds' ? 'Seconds' : 'Repititions'; - } - - return 'Seconds'; - } - - void getValue() { - if (_actionMap[_currentAction] == "Rest") { - _tickCount = _activity!.actions[0].activityActionSet.rest ~/ 1000; - } else { - _tickCount = _activity!.actions[0].activityActionSet.reps.amounts[0]; - } - } - - void pause() { - _periodicTimer?.cancel(); - notifyListeners(); - } - - void setAction(int actionNum, String type) { - // always pause if we're manually taversing - if (type == 'manual' && setType == 'seconds') { - pause(); - } - _currentAction = actionNum; - getValue(); - notifyListeners(); - } - - void nextAction(String type) { - _currentAction + 1 >= _actionMap.length - ? pause() - : setAction(_currentAction + 1, type); + _activity = activity; + _actions = activity.actions[0].items(); + _currentActionNum = 0; + _currentSetNum = 0; + setActionCount(); } bool isActive() { return (_periodicTimer != null && _periodicTimer!.isActive) ? true : false; } - void start() { - if (_activity != null) { - _periodicTimer?.cancel(); - _periodicTimer = - Timer.periodic(const Duration(seconds: 1), (Timer timer) { - if (_tickCount <= 0) { - nextAction('automatic'); - } else if (actionState() != 'Repititions') { - _tickCount--; - } - notifyListeners(); - }); + bool isCurrentItem(int setNum, int actionNum) { + if (setNum == _currentSetNum && actionNum == _currentActionNum) { + return true; } + + return false; } + + int totalActions() { + int count = 0; + for(int i = 0; i < _actions.length; i++) { + count = count + _actions[i].length as int; + } + + return count; + } + + void setActionCount() { + _actionCount = _actions[_currentSetNum][_currentActionNum]['amount']; + } + + void start() { + _periodicTimer = Timer.periodic(const Duration(seconds: 1), (Timer timer) { + _actionCount--; + notifyListeners(); + }); + } + + void setAction(int setNum, int actionNum, String type) { + _currentActionNum = actionNum; + _currentSetNum = setNum; + notifyListeners(); + } + + // void nextAction(String type) { + // setAction(_currentActionNum + 1, _getSet(), type); + // } + + // int _actionCount = 0; + // int _currentAction = 0; + // ActivityModel? _activity; + // Timer? _periodicTimer; + // List _actionMap = []; + + // int get actionCount => _actionCount; + // int get currentAction => _currentAction; + // ActivityModel? get activity => _activity; + // Timer? get periodicTimer => _periodicTimer; + // String get actionType => _actionMap[_currentAction]; + // String get setType => _activity != null + // ? _activity!.actions[0].activityActionSet.reps.type + // : 'n/a'; + // String? get repType => actionState(); + // List get sets => _activity!.actions[0].items(); + + // void setup(ActivityModel activity) { + // // if there isn't an activity yet + // // or we're coming from another activity + // // setup new timer + // if (_activity == null || activity.id != _activity?.id) { + // _periodicTimer?.cancel(); + // _activity = activity; + // _currentAction = 0; + // _actionMap = []; + // // for now we just do alternating rest/sets + // // in the future, we'll make this more modifiable + // int totalActions = activity.actions[0].activityActionSet.total; + // // log(activity.actions[0].activityActionSet.type); + // // if (activity.actions[0].activityActionSet.type == 'alternating') { + // // totalActions = totalActions * 4; + // // log('were in $totalActions'); + // // } + + // for (int i = 0; i < totalActions; i++) { + // _actionMap.addAll(['Set', 'Rest']); + // } + // getValue(); + // } + // } + + // String actionState() { + // if (actionType == 'Set') { + // return setType == 'seconds' ? 'Seconds' : 'Repititions'; + // } + + // return 'Seconds'; + // } + + // void getValue() { + // if (_actionMap[_currentAction] == "Rest") { + // _actionCount = _activity!.actions[0].activityActionSet.rest ~/ 1000; + // } else { + // _actionCount = _activity!.actions[0].activityActionSet.reps.amounts[0]; + // } + // } + + // void pause() { + // _periodicTimer?.cancel(); + // notifyListeners(); + // } + + // void setAction(int actionNum, String type) { + // // always pause if we're manually taversing + // if (type == 'manual' && setType == 'seconds') { + // pause(); + // } + // _currentAction = actionNum; + // getValue(); + // notifyListeners(); + // } + + // void nextAction(String type) { + // _currentAction + 1 >= _actionMap.length + // ? pause() + // : setAction(_currentAction + 1, type); + // } + + // bool isActive() { + // return (_periodicTimer != null && _periodicTimer!.isActive) ? true : false; + // } + + // void start() { + // if (_activity != null) { + // _periodicTimer?.cancel(); + // _periodicTimer = + // Timer.periodic(const Duration(seconds: 1), (Timer timer) { + // if (_actionCount <= 0) { + // nextAction('automatic'); + // } else if (actionState() != 'Repititions') { + // _actionCount--; + // } + // notifyListeners(); + // }); + // } + // } } diff --git a/lib/widgets/activity_action_view.dart b/lib/widgets/activity_action_view.dart index 429a557..0174283 100644 --- a/lib/widgets/activity_action_view.dart +++ b/lib/widgets/activity_action_view.dart @@ -21,74 +21,107 @@ class ActivityActionViewState extends State { int actionCount = 0; ActivityTimerModel atm = Provider.of(context, listen: true); + List>> sets = atm.activity!.actions[0].items(); return Expanded( child: ListView.builder( - padding: const EdgeInsets.fromLTRB(10, 0, 20, 0), + padding: const EdgeInsets.fromLTRB(10, 0, 10, 20), itemCount: widget.action.activityActionSet.total, - itemBuilder: (BuildContext context, int index) { + itemBuilder: (BuildContext context, int setNum) { String title = widget.action.title; Set actionSet = widget.action.activityActionSet; Reps setReps = actionSet.reps; int setRest = actionSet.rest ~/ 1000; - int currentAction = actionCount; + int currentAction = 0; List content = []; - actionCount = actionCount + 2; - content.addAll([ - GestureDetector( + List> set = sets[setNum]; + // log('${sets.length}'); + // log('${set.length}'); + for (int actionNum = 0; actionNum < set.length; actionNum++) { + Map setItem = set[actionNum]; + + content.add(GestureDetector( onTap: () { - setState(() { - atm.setAction(currentAction, 'manual'); - }); + atm.setAction(setNum, actionNum, 'manual'); + atm.setActionCount(); }, child: Row(children: [ - Consumer(builder: (context, atm, child) { - return Ink( - width: 100, - padding: const EdgeInsets.all(15), - color: currentAction == atm.currentAction - ? Theme.of(context).colorScheme.primaryContainer - : Theme.of(context).colorScheme.onPrimary, - child: Text('Set ${index + 1} ')); - }), + Ink( + // width: 90, + padding: const EdgeInsets.all(15), + color: atm.isCurrentItem(setNum, actionNum) + ? Theme.of(context).colorScheme.primaryContainer + : Theme.of(context).colorScheme.onPrimary, + child: + Text(textAlign: TextAlign.right, 'Set ${setNum + 1} ')), Expanded( child: Ink( padding: const EdgeInsets.all(15), - color: currentAction == atm.currentAction + color: atm.isCurrentItem(setNum, actionNum) ? Theme.of(context).colorScheme.surfaceBright : Theme.of(context).colorScheme.surfaceContainerLow, child: Text( textAlign: TextAlign.center, - '$title: ${setReps.amounts[index]} ${atm.setType}'))) - ])), - GestureDetector( - onTap: () { - setState(() { - atm.setAction(currentAction + 1, 'manual'); - }); - }, - child: Row(children: [ - Consumer(builder: (context, atm, child) { - return Ink( - width: 100, - padding: const EdgeInsets.all(15), - color: currentAction + 1 == atm.currentAction - ? Theme.of(context).colorScheme.primaryContainer - : Theme.of(context).colorScheme.onPrimary, - child: Text('Rest ${index + 1}')); - }), - Expanded( - child: Ink( - padding: const EdgeInsets.all(15), - color: currentAction + 1 == atm.currentAction - ? Theme.of(context).colorScheme.surfaceBright - : Theme.of(context).colorScheme.surfaceContainerLow, - child: Text( - textAlign: TextAlign.center, - 'Rest: $setRest seconds'))) - ])), - ]); + '${setItem['name']}: ${setItem['amount']} ${setItem['type']}'))) + ]))); + } + + // actionCount = actionCount + 2; + // content.addAll([ + // GestureDetector( + // onTap: () { + // setState(() { + // atm.setAction(currentAction, 'manual'); + // }); + // }, + // child: Row(children: [ + // Consumer(builder: (context, atm, child) { + // return Ink( + // width: 90, + // padding: const EdgeInsets.all(15), + // color: currentAction == atm.currentAction + // ? Theme.of(context).colorScheme.primaryContainer + // : Theme.of(context).colorScheme.onPrimary, + // child: Text(textAlign: TextAlign.right,'Set ${index + 1} ')); + // }), + // Expanded( + // child: Ink( + // padding: const EdgeInsets.all(15), + // color: currentAction == atm.currentAction + // ? Theme.of(context).colorScheme.surfaceBright + // : Theme.of(context).colorScheme.surfaceContainerLow, + // child: Text( + // textAlign: TextAlign.center, + // '$title: ${setReps.amounts[index]} ${atm.setType}'))) + // ])), + // GestureDetector( + // onTap: () { + // setState(() { + // atm.setAction(currentAction + 1, 'manual'); + // }); + // }, + // child: Row(children: [ + // Consumer(builder: (context, atm, child) { + // return Ink( + // width: 90, + // padding: const EdgeInsets.all(15), + // color: currentAction + 1 == atm.currentAction + // ? Theme.of(context).colorScheme.primaryContainer + // : Theme.of(context).colorScheme.onPrimary, + // child: Text(textAlign: TextAlign.right,'Rest ${index + 1}')); + // }), + // Expanded( + // child: Ink( + // padding: const EdgeInsets.all(15), + // color: currentAction + 1 == atm.currentAction + // ? Theme.of(context).colorScheme.surfaceBright + // : Theme.of(context).colorScheme.surfaceContainerLow, + // child: Text( + // textAlign: TextAlign.center, + // 'Rest: $setRest seconds'))) + // ])), + // ]); // if (actionSet.type == 'alternating') { // actionCount = actionCount + 2; @@ -150,9 +183,29 @@ class ActivityActionViewState extends State { // ]); // } - return Card( - clipBehavior: Clip.antiAlias, child: Column(children: content)); - + if (setNum == 0) { + return Card( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(0), + topRight: Radius.circular(0), + bottomLeft: Radius.circular(10), + bottomRight: Radius.circular(10)), + ), + clipBehavior: Clip.antiAlias, + child: Column(children: content)); + } else { + return Card( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(10), + bottomLeft: Radius.circular(10), + bottomRight: Radius.circular(10)), + ), + clipBehavior: Clip.antiAlias, + child: Column(children: content)); + } // return Column(children: contents); }, )); diff --git a/lib/widgets/activity_view.dart b/lib/widgets/activity_view.dart index 18ec70d..0e048c7 100644 --- a/lib/widgets/activity_view.dart +++ b/lib/widgets/activity_view.dart @@ -53,10 +53,13 @@ class _ActivityViewState extends State { textAlign: TextAlign.left, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), 'Actions:')), - ActivityActionView(action: activity.actions[0]), - Container( - height: MediaQuery.sizeOf(context).height * .07, - color: Theme.of(context).colorScheme.primaryContainer, + Padding( + padding: const EdgeInsets.only(left: 10, right: 10), + child: Card( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only(topLeft: Radius.circular(10), topRight: Radius.circular(10)), + ), + color: Theme.of(context).colorScheme.onPrimary, child: Row(children: [ // LinearProgressIndicator( // value: 0.5, @@ -69,19 +72,19 @@ class _ActivityViewState extends State { child: Flex(direction: Axis.horizontal, children: [ Consumer(builder: (context, atm, child) { return IconButton( - iconSize: 30, + // iconSize: 30, icon: atm.isActive() ? const Icon(Icons.pause_rounded) : const Icon(Icons.play_arrow_rounded), onPressed: () => - {atm.isActive() ? atm.pause() : atm.start()}); + {atm.isActive() ? atm.pause : atm.start()}); }), - IconButton( - iconSize: 36, - icon: const Icon(Icons.skip_next_rounded), - onPressed: () { - atm.nextAction('manual'); - }) + // IconButton( + // // iconSize: 36, + // icon: const Icon(Icons.skip_next_rounded), + // onPressed: () { + // atm.nextAction('manual'); + // }) ])), Expanded( flex: 1, @@ -90,7 +93,7 @@ class _ActivityViewState extends State { return Text( style: const TextStyle(fontSize: 20), textAlign: TextAlign.center, - '${atm.tickCount} ${atm.actionState()}'); + '${atm.actionCount} ${atm.currentActionType}'); }, )), Expanded( @@ -102,10 +105,63 @@ class _ActivityViewState extends State { return Text( style: const TextStyle(fontSize: 20), textAlign: TextAlign.right, - '${atm.currentAction + 1}: ${atm.actionType}'); + '${atm.currentActionNum + 1} / ${atm.totalActions()}'); // 'Set: ${atm.currentSet + 1}/${atm.totalSets}\nRep: ${atm.currentRep + 1}/${atm.totalReps}'); }))), - ])) + ]))), + ActivityActionView(action: activity.actions[0]), + // Container( + // height: MediaQuery.sizeOf(context).height * .07, + // color: Theme.of(context).colorScheme.primaryContainer, + // child: Row(children: [ + // // LinearProgressIndicator( + // // value: 0.5, + // // minHeight: 100, + // // color: Theme.of(context).colorScheme.error, + // // semanticsLabel: 'Linear progress indicator', + // // ), + // Expanded( + // flex: 1, + // child: Flex(direction: Axis.horizontal, children: [ + // Consumer(builder: (context, atm, child) { + // return IconButton( + // iconSize: 30, + // icon: atm.isActive() + // ? const Icon(Icons.pause_rounded) + // : const Icon(Icons.play_arrow_rounded), + // onPressed: () => + // {atm.isActive() ? atm.pause() : atm.start()}); + // }), + // IconButton( + // iconSize: 36, + // icon: const Icon(Icons.skip_next_rounded), + // onPressed: () { + // atm.nextAction('manual'); + // }) + // ])), + // Expanded( + // flex: 1, + // child: Consumer( + // builder: (context, atm, child) { + // return Text( + // style: const TextStyle(fontSize: 20), + // textAlign: TextAlign.center, + // '${atm.actionCount} ${atm.actionState()}'); + // }, + // )), + // Expanded( + // flex: 1, + // child: Padding( + // padding: const EdgeInsets.only(right: 15), + // child: Consumer( + // builder: (context, atm, child) { + // return Text( + // style: const TextStyle(fontSize: 20), + // textAlign: TextAlign.right, + // '${atm.currentAction + 1}: ${atm.actionType}'); + // // 'Set: ${atm.currentSet + 1}/${atm.totalSets}\nRep: ${atm.currentRep + 1}/${atm.totalReps}'); + // }))), + // ])) ]); } }