From d6e62024d7cf0661f12d4db325107eb4a496f6b7 Mon Sep 17 00:00:00 2001 From: Joshua Burman Date: Sun, 8 Dec 2024 14:14:10 -0500 Subject: [PATCH] added dash for local db, ui prep work --- lib/models/activity_timer_model.dart | 20 ++- lib/widgets/activity_card.dart | 45 +++++-- lib/widgets/activity_view.dart | 195 +++++++++++++++------------ lib/widgets/session_card.dart | 6 +- lib/widgets/session_view.dart | 104 ++++++++------ pubspec.yaml | 2 + 6 files changed, 235 insertions(+), 137 deletions(-) diff --git a/lib/models/activity_timer_model.dart b/lib/models/activity_timer_model.dart index 46fbdee..8159ed8 100644 --- a/lib/models/activity_timer_model.dart +++ b/lib/models/activity_timer_model.dart @@ -13,6 +13,7 @@ class ActivityTimerModel with ChangeNotifier { Timer? _periodicTimer; double _progress = 0; ItemScrollController? _isc; + int _totalTime = 0; int get actionCount => _actionCounter; int get currentActionNum => _currentActionNum; @@ -24,6 +25,7 @@ class ActivityTimerModel with ChangeNotifier { Timer? get periodicTimer => _periodicTimer; bool get isActive => _isActive(); double get progress => _progress; + int get totalTime => _totalTime; void setup(ActivityModel activity) { if (_activity == null || activity.id != _activity?.id) { @@ -35,11 +37,26 @@ class ActivityTimerModel with ChangeNotifier { _currentActionNum = 0; _currentSetNum = 0; setActionCount(); + getTotalTime(); } moveToIndex(_currentSetNum); } + void getTotalTime() { + int time = 0; + for(int setIndex = 0; _sets.length > setIndex; setIndex++) { + for (int actionIndex = 0; _sets[setIndex].length > actionIndex; actionIndex++) { + var action = _sets[setIndex][actionIndex]; + if (action['type'] == 'seconds') { + time = time + action['amount'] as int; + } + } + } + + _totalTime = time; + } + void reset() { _progress = 0; _currentActionNum = 0; @@ -89,6 +106,7 @@ class ActivityTimerModel with ChangeNotifier { case 'seconds': if (_actionCounter > 0) { _actionCounter--; + _totalTime--; } else { nextAction(_currentActionNum + 1); setActionCount(); @@ -110,8 +128,8 @@ class ActivityTimerModel with ChangeNotifier { void setAction(int setNum, int actionNum, String type) { _currentActionNum = actionNum; _currentSetNum = setNum; - moveToIndex(_currentSetNum); notifyListeners(); + moveToIndex(_currentSetNum); } void nextAction(int nextActionIndex) { diff --git a/lib/widgets/activity_card.dart b/lib/widgets/activity_card.dart index af38eba..776be35 100644 --- a/lib/widgets/activity_card.dart +++ b/lib/widgets/activity_card.dart @@ -1,20 +1,39 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:sendtrain/classes/media.dart'; import 'package:sendtrain/models/activity_model.dart'; +import 'package:sendtrain/models/activity_timer_model.dart'; import 'package:sendtrain/widgets/activity_view.dart'; -class ActivityCard extends StatelessWidget { +class ActivityCard extends StatefulWidget { + final ActivityModel activity; + const ActivityCard({super.key, required this.activity}); - final ActivityModel activity; + @override + State createState() => ActivityCardState(); +} + +class ActivityCardState extends State { + String formattedTime(int timeInSecond) { + int sec = timeInSecond % 60; + int min = (timeInSecond / 60).floor(); + String minute = min.toString().length <= 1 ? "0$min" : "$min"; + String second = sec.toString().length <= 1 ? "0$sec" : "$sec"; + return "$minute:$second"; + } @override Widget build(BuildContext context) { + final ActivityTimerModel atm = + Provider.of(context, listen: false); + return Card( - color: const Color(0xff3A5FB6), + color: atm.activity?.id == widget.activity.id + ? Theme.of(context).colorScheme.primaryContainer + : Theme.of(context).colorScheme.surfaceContainerLow, clipBehavior: Clip.hardEdge, child: InkWell( - splashColor: Colors.deepPurple, onTap: () => showGeneralDialog( barrierColor: Colors.black.withOpacity(0.5), transitionDuration: const Duration(milliseconds: 220), @@ -29,7 +48,7 @@ class ActivityCard extends StatelessWidget { return SlideTransition( position: custom, child: Dialog.fullscreen( - child: ActivityView(activity: activity))); + child: ActivityView(activity: widget.activity))); }, barrierDismissible: true, barrierLabel: '', @@ -49,14 +68,24 @@ class ActivityCard extends StatelessWidget { image: DecorationImage( fit: BoxFit.cover, image: findMediaByType( - activity.actions[0].media, 'image')), + widget.activity.actions[0].media, 'image')), // color: Colors.blue, borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)), ), )), - title: Text(maxLines: 1, activity.title), - subtitle: Text(maxLines: 2, activity.description), + title: Consumer( + builder: (context, atm, child) { + if (atm.activity?.id == widget.activity.id) { + return Text( + maxLines: 1, + "${widget.activity.title} (${formattedTime(atm.totalTime)})"); + } else { + return Text(maxLines: 1, widget.activity.title); + } + }, + ), + subtitle: Text(maxLines: 2, widget.activity.description), ), ], )), diff --git a/lib/widgets/activity_view.dart b/lib/widgets/activity_view.dart index 72820b1..7aa1dc5 100644 --- a/lib/widgets/activity_view.dart +++ b/lib/widgets/activity_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:provider/provider.dart'; import 'package:sendtrain/classes/activity_action.dart'; import 'package:sendtrain/classes/media.dart'; @@ -24,94 +25,122 @@ class _ActivityViewState extends State { atm.setup(activity); - return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - AppBar( - centerTitle: true, - title: const Text('Activity', style: TextStyle(fontSize: 15)), - ), - Padding( - padding: - const EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 10), - child: Text( - maxLines: 1, - style: const TextStyle(fontSize: 25, fontWeight: FontWeight.bold), - activity.title)), - ActivityViewCategories(categories: activity.categories), - Padding( - padding: - const EdgeInsets.only(top: 0, bottom: 20, left: 15, right: 15), - child: Text( - textAlign: TextAlign.left, - style: const TextStyle(fontSize: 15), - activity.description)), - ActivityViewMedia(activity: activity), - const Padding( - padding: EdgeInsets.fromLTRB(15, 30, 0, 10), - child: Text( - textAlign: TextAlign.left, - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - 'Actions')), - Padding( - padding: const EdgeInsets.only(left: 10, right: 10), - child: Card( - clipBehavior: Clip.antiAlias, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(10), - topRight: Radius.circular(10)), + return Scaffold( + floatingActionButtonLocation: ExpandableFab.location, + floatingActionButton: ExpandableFab( + distance: 70, + type: ExpandableFabType.up, + overlayStyle: ExpandableFabOverlayStyle( + color: Colors.black.withOpacity(0.5), + blur: 10, + ), + children: [ + FloatingActionButton.extended( + icon: const Icon(Icons.history_outlined), + label: Text('Restart'), + onPressed: () {}, ), - color: Theme.of(context).colorScheme.onPrimary, - child: Row(children: [ - Ink( - width: 70, - color: Theme.of(context).colorScheme.primaryContainer, - child: Consumer( - builder: (context, atm, child) { - return IconButton( - alignment: AlignmentDirectional.center, - icon: atm.isActive - ? const Icon(Icons.pause_rounded) - : const Icon(Icons.play_arrow_rounded), - onPressed: () => - {atm.isActive ? atm.pause() : atm.start()}); - }, - )), - Expanded( - flex: 1, - child: Stack(alignment: Alignment.center, children: [ - Container( - alignment: Alignment.center, + FloatingActionButton.extended( + icon: const Icon(Icons.done_all_outlined), + label: Text('Done'), + onPressed: () {}, + ), + FloatingActionButton.extended( + icon: const Icon(Icons.edit_outlined), + label: Text('Edit'), + onPressed: () {}, + ), + ]), + body: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + AppBar( + centerTitle: true, + title: const Text('Activity', style: TextStyle(fontSize: 15)), + ), + Padding( + padding: const EdgeInsets.only( + left: 15, right: 20, top: 15, bottom: 10), + child: Text( + maxLines: 1, + style: const TextStyle( + fontSize: 25, fontWeight: FontWeight.bold), + activity.title)), + ActivityViewCategories(categories: activity.categories), + Padding( + padding: const EdgeInsets.only( + top: 0, bottom: 20, left: 15, right: 15), + child: Text( + textAlign: TextAlign.left, + style: const TextStyle(fontSize: 15), + activity.description)), + ActivityViewMedia(activity: activity), + const Padding( + padding: EdgeInsets.fromLTRB(15, 30, 0, 10), + child: Text( + textAlign: TextAlign.left, + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + 'Actions')), + Padding( + padding: const EdgeInsets.only(left: 10, right: 10), + child: Card( + clipBehavior: Clip.antiAlias, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(10)), + ), + color: Theme.of(context).colorScheme.onPrimary, + child: Row(children: [ + Ink( + width: 70, + color: Theme.of(context).colorScheme.primaryContainer, child: Consumer( builder: (context, atm, child) { - return Text( - style: const TextStyle(fontSize: 20), - textAlign: TextAlign.center, - '${atm.actionCount} ${atm.currentAction['type']}'); + return IconButton( + alignment: AlignmentDirectional.center, + icon: atm.isActive + ? const Icon(Icons.pause_rounded) + : const Icon(Icons.play_arrow_rounded), + onPressed: () => + {atm.isActive ? atm.pause() : atm.start()}); }, - ), - ), - Container( - alignment: Alignment.centerRight, - padding: EdgeInsets.only(right: 10), - child: Consumer( + )), + Expanded( + flex: 1, + child: Stack(alignment: Alignment.center, children: [ + Container( + alignment: Alignment.center, + child: Consumer( builder: (context, atm, child) { - return Text( - style: const TextStyle(fontSize: 12), - textAlign: TextAlign.right, - '${atm.currentAction['actionID'] + 1} of ${atm.totalActions()}'); - })), - ])), - ]))), - Padding( - padding: EdgeInsets.only(left: 14, right: 14), - child: Consumer(builder: (context, atm, child) { - return LinearProgressIndicator( - value: atm.progress, - semanticsLabel: 'Activity Progress', - ); - })), - ActivityActionView(action: activity.actions[0]), - ]); + return Text( + style: const TextStyle(fontSize: 20), + textAlign: TextAlign.center, + '${atm.actionCount} ${atm.currentAction['type']}'); + }, + ), + ), + Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.only(right: 10), + child: Consumer( + builder: (context, atm, child) { + return Text( + style: const TextStyle(fontSize: 12), + textAlign: TextAlign.right, + '${atm.currentAction['actionID'] + 1} of ${atm.totalActions()}'); + })), + ])), + ]))), + Padding( + padding: EdgeInsets.only(left: 14, right: 14), + child: + Consumer(builder: (context, atm, child) { + return LinearProgressIndicator( + value: atm.progress, + semanticsLabel: 'Activity Progress', + ); + })), + ActivityActionView(action: activity.actions[0]), + ])); } } diff --git a/lib/widgets/session_card.dart b/lib/widgets/session_card.dart index fd030dd..cd4eb0c 100644 --- a/lib/widgets/session_card.dart +++ b/lib/widgets/session_card.dart @@ -18,8 +18,8 @@ class SessionCard extends StatelessWidget { final DateFormat dateFormat = DateFormat('yyyy-MM-dd'); Color color = (state == 0) - ? const Color(0xff3A5FB6) - : ThemeData.dark(useMaterial3: true).colorScheme.surfaceBright; + ? Theme.of(context).colorScheme.primaryContainer + : Theme.of(context).colorScheme.surfaceContainerLow; // place holder until we can retrieve real data final data = SessionModel( @@ -228,7 +228,7 @@ class SessionCard extends StatelessWidget { ); } else { return Card( - color: const Color.fromARGB(125, 0, 0, 0), + color: color, child: InkWell( // overlayColor: MaterialStateColor(Colors.deepPurple as int), splashColor: Colors.deepPurple, diff --git a/lib/widgets/session_view.dart b/lib/widgets/session_view.dart index fa6002a..6965a18 100644 --- a/lib/widgets/session_view.dart +++ b/lib/widgets/session_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:intl/intl.dart'; import 'package:intl/date_symbol_data_local.dart'; @@ -18,48 +19,67 @@ class SessionView extends StatelessWidget { initializeDateFormatting('en'); final DateFormat dateFormat = DateFormat('yyyy-MM-dd'); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AppBar( - centerTitle: true, - title: Text('Session @ ${dateFormat.format(data.date)}', - style: const TextStyle(fontSize: 15)), - ), - Padding( - padding: - const EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 10), - child: Text( - maxLines: 1, - style: - const TextStyle(fontSize: 25, fontWeight: FontWeight.bold), - data.title)), - SessionViewAchievements(achievements: data.achievements), - Padding( - padding: const EdgeInsets.only(left: 15, right: 15), - child: Text( - style: const TextStyle(fontSize: 15), - data.content)), - const Padding( - padding: EdgeInsets.fromLTRB(15, 30, 0, 10), - child: Text( - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - 'Media:')), - SessionViewMedia(media: data.media), - const Padding( - padding: EdgeInsets.fromLTRB(15, 30, 0, 10), - child: Text( - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - 'Activites:')), - SessionViewActivities(activities: data.activities), - // TextButton( - // onPressed: () { - // Navigator.pop(context); - // }, - // child: const Text('Close'), - // ), - ], - ); + return Scaffold( + floatingActionButtonLocation: ExpandableFab.location, + floatingActionButton: ExpandableFab( + distance: 70, + type: ExpandableFabType.up, + overlayStyle: ExpandableFabOverlayStyle( + color: Colors.black.withOpacity(0.5), + blur: 10, + ), + children: [ + FloatingActionButton.extended( + icon: const Icon(Icons.history_outlined), + label: Text('Restart'), + onPressed: () {}, + ), + FloatingActionButton.extended( + icon: const Icon(Icons.done_all_outlined), + label: Text('Done'), + onPressed: () {}, + ), + FloatingActionButton.extended( + icon: const Icon(Icons.edit_outlined), + label: Text('Edit'), + onPressed: () {}, + ), + ]), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppBar( + centerTitle: true, + title: Text('Session @ ${dateFormat.format(data.date)}', + style: const TextStyle(fontSize: 15)), + ), + Padding( + padding: const EdgeInsets.only( + left: 15, right: 20, top: 15, bottom: 10), + child: Text( + maxLines: 1, + style: const TextStyle( + fontSize: 25, fontWeight: FontWeight.bold), + data.title)), + SessionViewAchievements(achievements: data.achievements), + Padding( + padding: const EdgeInsets.only(left: 15, right: 15), + child: + Text(style: const TextStyle(fontSize: 15), data.content)), + const Padding( + padding: EdgeInsets.fromLTRB(15, 30, 0, 10), + child: Text( + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + 'Media:')), + SessionViewMedia(media: data.media), + const Padding( + padding: EdgeInsets.fromLTRB(15, 30, 0, 10), + child: Text( + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + 'Activites:')), + SessionViewActivities(activities: data.activities), + ], + )); } } diff --git a/pubspec.yaml b/pubspec.yaml index f1206c7..292cf1e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,8 @@ dependencies: json_annotation: ^4.9.0 provider: ^6.1.2 scrollable_positioned_list: ^0.3.8 + drift: ^2.22.1 + flutter_expandable_fab: ^2.3.0 flutter_launcher_name: name: "SendTrain"