diff --git a/lib/daos/activities_dao.dart b/lib/daos/activities_dao.dart index ac41670..95ac6ba 100644 --- a/lib/daos/activities_dao.dart +++ b/lib/daos/activities_dao.dart @@ -4,7 +4,8 @@ import 'package:sendtrain/database/database.dart'; part 'activities_dao.g.dart'; @DriftAccessor(tables: [Activities]) -class ActivitiesDao extends DatabaseAccessor with _$ActivitiesDaoMixin { +class ActivitiesDao extends DatabaseAccessor + with _$ActivitiesDaoMixin { ActivitiesDao(super.db); Future> all() async { @@ -12,26 +13,71 @@ class ActivitiesDao extends DatabaseAccessor with _$ActivitiesDaoMi } Future find(int id) async { - return await (select(activities)..where((activity) => activity.id.equals(id) )).getSingle(); + return await (select(activities) + ..where((activity) => activity.id.equals(id))) + .getSingle(); } Future remove(Activity activity) => delete(activities).delete(activity); - Future> sessionActivities(int id) async { - final result = select(db.sessionActivities).join( + Future> activitiesFromSession(int id) async { + final result = select(db.sessionActivities).join( [ innerJoin( db.activities, - db.activities.id - .equalsExp(db.sessionActivities.activityId), + db.activities.id.equalsExp(db.sessionActivities.activityId), ), ], )..where(db.sessionActivities.sessionId.equals(id)); - final activities = (await result.get()) - .map((e) => e.readTable(db.activities)) - .toList(); + final activities = + (await result.get()).map((e) => e.readTable(db.activities)).toList(); return activities; } -} \ No newline at end of file + + Stream> watchSessionActivities(int id) { + final query = select(db.sessionActivities).join( + [ + innerJoin( + db.activities, + db.activities.id.equalsExp(db.sessionActivities.activityId), + ), + ], + )..where(db.sessionActivities.sessionId.equals(id)); + + return query.watch().map((rows){ + final activities = + (rows).map((e) => e.readTable(db.activities)).toList(); + + return activities; + }); + } + + // MultiSelectable _selectableSessionActivities(int id) { + // // return select(db.sessionActivities)..limit(1, offset: 1); + // // final query = select(db.sessionActivities).join( + // // [ + // // innerJoin( + // // db.activities, + // // db.activities.id.equalsExp(db.sessionActivities.activityId), + // // ), + // // ], + // // )..where(db.sessionActivities.sessionId.equals(id)); + + // // return query; + + // final query = select(db.sessionActivities)..where((row) => row.sessionId.equals(id)); + + // query.join( + // [ + // innerJoin( + // db.activities, + // db.activities.id.equalsExp(db.sessionActivities.activityId), + // ), + // ], + // ); + + // return query; + // } +} diff --git a/lib/helpers/date_helpers.dart b/lib/helpers/date_helpers.dart new file mode 100644 index 0000000..8bea8b0 --- /dev/null +++ b/lib/helpers/date_helpers.dart @@ -0,0 +1,3 @@ +import 'package:intl/intl.dart'; + +final DateFormat dateFormat = DateFormat('yyyy-MM-dd'); \ No newline at end of file diff --git a/lib/helpers/media_helpers.dart b/lib/helpers/media_helpers.dart new file mode 100644 index 0000000..c6bcf4b --- /dev/null +++ b/lib/helpers/media_helpers.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:sendtrain/database/database.dart'; + +ImageProvider findMediaByType(List media, String type) { + Iterable? found = media.where((m) => m.type == MediaType.image); + + if (found.isNotEmpty) { + return NetworkImage(found.first.reference); + } else { + // Element is not found + return const AssetImage('assets/images/placeholder.jpg'); + } + } \ No newline at end of file diff --git a/lib/widgets/activities/activity_card.dart b/lib/widgets/activities/activity_card.dart index 9669645..1eef5fe 100644 --- a/lib/widgets/activities/activity_card.dart +++ b/lib/widgets/activities/activity_card.dart @@ -4,8 +4,12 @@ import 'package:sendtrain/daos/activities_dao.dart'; import 'package:sendtrain/daos/media_items_dao.dart'; import 'package:sendtrain/database/database.dart'; import 'package:sendtrain/extensions/string_extensions.dart'; +import 'package:sendtrain/helpers/media_helpers.dart'; import 'package:sendtrain/models/activity_timer_model.dart'; import 'package:sendtrain/widgets/activities/activity_view.dart'; +import 'package:sendtrain/widgets/builders/dialogs.dart'; +import 'package:sendtrain/widgets/generic/elements/card_image.dart'; +import 'package:sendtrain/widgets/generic/elements/generic_progress_indicator.dart'; class ActivityCard extends StatefulWidget { final Activity activity; @@ -43,49 +47,15 @@ class ActivityCardState extends State { : Theme.of(context).colorScheme.surfaceContainerLow, clipBehavior: Clip.hardEdge, child: InkWell( - onTap: () => showGeneralDialog( - barrierColor: Colors.black.withOpacity(0.5), - transitionDuration: const Duration(milliseconds: 220), - transitionBuilder: (BuildContext context, - Animation animation, - Animation secondaryAnimation, - Widget child) { - Animation custom = Tween( - begin: const Offset(0.0, 1.0), - end: const Offset(0.0, 0.0)) - .animate(animation); - return SlideTransition( - position: custom, - child: Dialog.fullscreen( - child: - ActivityView(activity: widget.activity))); - }, - barrierDismissible: true, - barrierLabel: '', - context: context, - pageBuilder: (context, animation1, animation2) { - return Container(); - }), + onTap: () => showGenericDialog( + ActivityView(activity: widget.activity), context), child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( // visualDensity: VisualDensity(horizontal: VisualDensity.maximumDensity), - leading: Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), - child: Container( - // padding: EdgeInsets.only(top: 5, bottom: 5), - width: 60, - decoration: BoxDecoration( - image: DecorationImage( - fit: BoxFit.fill, - image: - findMediaByType(mediaItems, 'image')), - // color: Colors.blue, - borderRadius: const BorderRadius.all( - Radius.elliptical(8, 8)), - ), - )), + leading: CardImage( + image: findMediaByType(mediaItems, 'image')), title: Consumer( builder: (context, atm, child) { if (atm.activity?.id == widget.activity.id) { @@ -112,95 +82,27 @@ class ActivityCardState extends State { visualDensity: VisualDensity.compact, icon: Icon(Icons.close_rounded), onPressed: () { - showAdaptiveDialog( - context: context, - builder: (BuildContext context) => - AlertDialog( - title: const Text('Activity Removal'), - content: const Text( - 'Would you like to permanently remove this activity from the current session?'), - actions: [ - TextButton( - onPressed: () => Navigator.pop( - context, 'Cancel'), - child: const Text('Cancel'), - ), - TextButton( - onPressed: () => { - ActivitiesDao( - Provider.of( - context, - listen: false)) - .remove(widget.activity) - .then((result) { - setState(() {}); - }), - Navigator.pop(context, 'OK') - }, - child: const Text('OK'), - ), - ], - ), - ); + showRemovalDialog( + 'Activity Removal', + 'Would you like to permanently remove this activity from the current session?', + context, + ActivitiesDao( + Provider.of( + context, + listen: false)), + widget.activity) + .then((result) { + setState(() {}); + }); }, ) - ]) - // trailing: FittedBox( - // alignment: Alignment.topCenter, - // fit: BoxFit.fitHeight, - // child: IconButton( - // padding: EdgeInsets.all(0), - // alignment: Alignment.topCenter, - // // visualDensity: VisualDensity.compact, - // icon: Icon(Icons.close_rounded), - // onPressed: () { - // showAdaptiveDialog( - // context: context, - // builder: (BuildContext context) => - // AlertDialog( - // title: const Text('Activity Removal'), - // content: const Text( - // 'Would you like to permanently remove this activity from the current session?'), - // actions: [ - // TextButton( - // onPressed: () => - // Navigator.pop(context, 'Cancel'), - // child: const Text('Cancel'), - // ), - // TextButton( - // onPressed: () => - // Navigator.pop(context, 'OK'), - // child: const Text('OK'), - // ), - // ], - // ), - // ); - // }, - // )) - ), + ])), ], )), ); } else { - return Container( - alignment: Alignment.center, - child: SizedBox( - height: 50.0, - width: 50.0, - child: CircularProgressIndicator(), - )); + return GenericProgressIndicator(); } }); } - - ImageProvider findMediaByType(List media, String type) { - Iterable? found = media.where((m) => m.type == MediaType.image); - - if (found.isNotEmpty) { - return NetworkImage(found.first.reference); - } else { - // Element is not found - return const AssetImage('assets/images/placeholder.jpg'); - } - } } diff --git a/lib/widgets/builders/dialogs.dart b/lib/widgets/builders/dialogs.dart index 91bfadd..d2b3bc9 100644 --- a/lib/widgets/builders/dialogs.dart +++ b/lib/widgets/builders/dialogs.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:sendtrain/database/database.dart'; -import 'package:sendtrain/widgets/sessions/session_view.dart'; -Future showSessionDialog(Session session, BuildContext parentContext) { +Future showGenericDialog(dynamic object, BuildContext parentContext) { return showGeneralDialog( barrierColor: Colors.black.withOpacity(0.5), transitionDuration: const Duration(milliseconds: 220), @@ -12,8 +10,7 @@ Future showSessionDialog(Session session, BuildContext parentContext) { begin: const Offset(0.0, 1.0), end: const Offset(0.0, 0.0)) .animate(animation); return SlideTransition( - position: custom, - child: Dialog.fullscreen(child: SessionView(session: session))); + position: custom, child: Dialog.fullscreen(child: object)); }, barrierDismissible: true, barrierLabel: '', diff --git a/lib/widgets/generic/elements/card_content.dart b/lib/widgets/generic/elements/card_content.dart new file mode 100644 index 0000000..806d051 --- /dev/null +++ b/lib/widgets/generic/elements/card_content.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class CardContent extends StatelessWidget { + const CardContent({super.key, required this.content}); + + final String content; + + @override + Widget build(BuildContext context) { + return ListTile( + contentPadding: const EdgeInsets.fromLTRB(15, 0, 15, 15), + title: Text( + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontWeight: FontWeight.w300), + content), + ); + } +} diff --git a/lib/widgets/generic/elements/card_image.dart b/lib/widgets/generic/elements/card_image.dart new file mode 100644 index 0000000..1b050c7 --- /dev/null +++ b/lib/widgets/generic/elements/card_image.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class CardImage extends StatelessWidget { + const CardImage({super.key, required this.image}); + + final ImageProvider image; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), + child: Container( + width: 60, + decoration: BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + image: image, + // color: Colors.blue, + ), + borderRadius: BorderRadius.all(Radius.elliptical(8, 8)), + ), + )); + } +} diff --git a/lib/widgets/generic/elements/generic_progress_indicator.dart b/lib/widgets/generic/elements/generic_progress_indicator.dart new file mode 100644 index 0000000..0c4502b --- /dev/null +++ b/lib/widgets/generic/elements/generic_progress_indicator.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +class GenericProgressIndicator extends StatelessWidget { + const GenericProgressIndicator({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.center, + child: SizedBox( + height: 50.0, + width: 50.0, + child: CircularProgressIndicator(), + )); + } +} diff --git a/lib/widgets/screens/sessions_screen.dart b/lib/widgets/screens/sessions_screen.dart index 65624f1..25d4cf0 100644 --- a/lib/widgets/screens/sessions_screen.dart +++ b/lib/widgets/screens/sessions_screen.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:sendtrain/daos/sessions_dao.dart'; import 'package:sendtrain/database/database.dart'; +import 'package:sendtrain/widgets/generic/elements/generic_progress_indicator.dart'; import 'package:sendtrain/widgets/sessions/session_card.dart'; import 'package:collection/collection.dart'; @@ -95,13 +96,7 @@ class _SessionsScreenState extends State { ], ); } else { - return Container( - alignment: Alignment.center, - child: SizedBox( - height: 50.0, - width: 50.0, - child: CircularProgressIndicator(), - )); + return GenericProgressIndicator(); } }); } diff --git a/lib/widgets/sessions/session_card.dart b/lib/widgets/sessions/session_card.dart index 14f5c60..ca86728 100644 --- a/lib/widgets/sessions/session_card.dart +++ b/lib/widgets/sessions/session_card.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:provider/provider.dart'; import 'package:sendtrain/daos/media_items_dao.dart'; -import 'package:sendtrain/daos/sessions_dao.dart'; import 'package:sendtrain/database/database.dart' hide ActivityAction; -import 'package:sendtrain/extensions/string_extensions.dart'; -import 'package:sendtrain/widgets/builders/dialogs.dart'; +import 'package:sendtrain/widgets/generic/elements/generic_progress_indicator.dart'; +import 'package:sendtrain/widgets/sessions/session_card_full.dart'; +import 'package:sendtrain/widgets/sessions/session_card_small.dart'; class SessionCard extends StatefulWidget { final int type; @@ -24,11 +23,6 @@ class _SessionCardState extends State { final Session session = widget.session; initializeDateFormatting('en'); - final DateFormat dateFormat = DateFormat('yyyy-MM-dd'); - - Color color = (session.status == SessionStatus.started) - ? Theme.of(context).colorScheme.primaryContainer - : Theme.of(context).colorScheme.surfaceContainerLow; return FutureBuilder>( future: MediaItemsDao(Provider.of(context)) @@ -38,126 +32,13 @@ class _SessionCardState extends State { List mediaItems = snapshot.data!; if (type == 0) { - return Card( - color: color, - margin: const EdgeInsets.fromLTRB(15, 15, 15, 0), - clipBehavior: Clip.hardEdge, - child: InkWell( - splashColor: Colors.deepPurple, - onTap: () => showSessionDialog(session, context), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - contentPadding: EdgeInsets.only(left: 15), - leading: Padding( - padding: const EdgeInsets.fromLTRB(0, 8, 0, 0), - child: Container( - width: 60, - decoration: BoxDecoration( - image: DecorationImage( - fit: BoxFit.cover, - image: - findMediaByType(mediaItems, 'image')), - // color: Colors.blue, - borderRadius: BorderRadius.all( - Radius.elliptical(10, 10)), - ), - )), - title: Text(maxLines: 1, session.title.toTitleCase()), - subtitle: Text( - maxLines: 1, - dateFormat.format(session.date as DateTime)), - trailing: IconButton( - padding: EdgeInsets.all(0), - alignment: Alignment.topCenter, - icon: Icon(Icons.close_rounded), - onPressed: () { - showRemovalDialog( - 'Session Removal', - 'Would you like to permanently remove this session?', - context, - SessionsDao(Provider.of( - context, - listen: false)), - session) - .then((result) { - setState(() {}); - }); - }, - ), - ), - ListTile( - contentPadding: - const EdgeInsets.fromLTRB(15, 0, 15, 15), - title: Text( - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: - const TextStyle(fontWeight: FontWeight.w300), - session.content), - ), - ], - )), - ); + return SessionCardFull(session: session, mediaItems: mediaItems); } else { - return Card( - color: color, - child: InkWell( - // overlayColor: MaterialStateColor(Colors.deepPurple as int), - splashColor: Colors.deepPurple, - borderRadius: - const BorderRadius.all(Radius.elliptical(10, 10)), - onTap: () => showSessionDialog(session, context), - child: Container( - decoration: BoxDecoration( - // color: const Color.fromARGB(47, 0, 0, 0), - borderRadius: BorderRadius.circular(10), - image: DecorationImage( - colorFilter: ColorFilter.mode( - Color.fromARGB(220, 41, 39, 39), - BlendMode.hardLight), - image: findMediaByType(mediaItems, 'image'), - fit: BoxFit.cover), - ), - child: Align( - alignment: Alignment.center, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - title: Text( - maxLines: 3, - session.title.toTitleCase(), - textAlign: TextAlign.center), - subtitle: Text( - maxLines: 1, - dateFormat - .format(session.date as DateTime), - textAlign: TextAlign.center), - ), - ]))))); + return SessionCardSmall(session: session, mediaItems: mediaItems); } } else { - return Container( - alignment: Alignment.center, - child: SizedBox( - height: 50.0, - width: 50.0, - child: CircularProgressIndicator(), - )); + return GenericProgressIndicator(); } }); } - - ImageProvider findMediaByType(List media, String type) { - Iterable? found = media.where((m) => m.type == MediaType.image); - - if (found.isNotEmpty) { - return NetworkImage(found.first.reference); - } else { - // Element is not found - return const AssetImage('assets/images/placeholder.jpg'); - } - } } diff --git a/lib/widgets/sessions/session_card_full.dart b/lib/widgets/sessions/session_card_full.dart new file mode 100644 index 0000000..a35e614 --- /dev/null +++ b/lib/widgets/sessions/session_card_full.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:sendtrain/daos/sessions_dao.dart'; +import 'package:sendtrain/database/database.dart'; +import 'package:sendtrain/extensions/string_extensions.dart'; +import 'package:sendtrain/helpers/date_helpers.dart'; +import 'package:sendtrain/helpers/media_helpers.dart'; +import 'package:sendtrain/widgets/builders/dialogs.dart'; +import 'package:sendtrain/widgets/generic/elements/card_content.dart'; +import 'package:sendtrain/widgets/generic/elements/card_image.dart'; +import 'package:sendtrain/widgets/sessions/session_view.dart'; + +class SessionCardFull extends StatefulWidget { + const SessionCardFull( + {super.key, required this.session, required this.mediaItems}); + + final Session session; + final List mediaItems; + + @override + State createState() => _SessionCardFullState(); +} + +class _SessionCardFullState extends State { + @override + Widget build(BuildContext context) { + final Session session = widget.session; + final List mediaItems = widget.mediaItems; + + return Card( + color: (session.status == SessionStatus.started) + ? Theme.of(context).colorScheme.primaryContainer + : Theme.of(context).colorScheme.surfaceContainerLow, + margin: const EdgeInsets.fromLTRB(15, 15, 15, 0), + clipBehavior: Clip.hardEdge, + child: InkWell( + splashColor: Colors.deepPurple, + onTap: () => + showGenericDialog(SessionView(session: session), context), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + contentPadding: EdgeInsets.only(left: 8), + leading: CardImage(image: findMediaByType(mediaItems, 'image')), + title: Text(maxLines: 1, session.title.toTitleCase()), + subtitle: Text( + maxLines: 1, dateFormat.format(session.date as DateTime)), + trailing: IconButton( + padding: EdgeInsets.all(0), + alignment: Alignment.topCenter, + icon: Icon(Icons.close_rounded), + onPressed: () { + showRemovalDialog( + 'Session Removal', + 'Would you like to permanently remove this session?', + context, + SessionsDao(Provider.of(context, + listen: false)), + session) + .then((result) { + setState(() {}); + }); + }, + ), + ), + CardContent(content: session.content) + ], + )), + ); + } +} diff --git a/lib/widgets/sessions/session_card_small.dart b/lib/widgets/sessions/session_card_small.dart new file mode 100644 index 0000000..447f691 --- /dev/null +++ b/lib/widgets/sessions/session_card_small.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:sendtrain/database/database.dart'; +import 'package:sendtrain/extensions/string_extensions.dart'; +import 'package:sendtrain/helpers/date_helpers.dart'; +import 'package:sendtrain/helpers/media_helpers.dart'; +import 'package:sendtrain/widgets/builders/dialogs.dart'; +import 'package:sendtrain/widgets/sessions/session_view.dart'; + +class SessionCardSmall extends StatefulWidget { + const SessionCardSmall( + {super.key, required this.session, required this.mediaItems}); + + final Session session; + final List mediaItems; + + @override + State createState() => _SessionCardSmallState(); +} + +class _SessionCardSmallState extends State { + @override + Widget build(BuildContext context) { + final Session session = widget.session; + final List mediaItems = widget.mediaItems; + + return Card( + color: (session.status == SessionStatus.started) + ? Theme.of(context).colorScheme.primaryContainer + : Theme.of(context).colorScheme.surfaceContainerLow, + child: InkWell( + // overlayColor: MaterialStateColor(Colors.deepPurple as int), + splashColor: Colors.deepPurple, + borderRadius: const BorderRadius.all(Radius.elliptical(10, 10)), + onTap: () => showGenericDialog(SessionView(session: session), context), + child: Container( + decoration: BoxDecoration( + // color: const Color.fromARGB(47, 0, 0, 0), + borderRadius: BorderRadius.circular(10), + image: DecorationImage( + colorFilter: ColorFilter.mode( + Color.fromARGB(220, 41, 39, 39), BlendMode.hardLight), + image: findMediaByType(mediaItems, 'image'), + fit: BoxFit.cover), + ), + child: Align( + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + title: Text( + maxLines: 3, + session.title.toTitleCase(), + textAlign: TextAlign.center), + subtitle: Text( + maxLines: 1, + dateFormat.format(session.date as DateTime), + textAlign: TextAlign.center), + ), + ]))))); + } +} diff --git a/lib/widgets/sessions/session_creator.dart b/lib/widgets/sessions/session_creator.dart index eb8fc61..f5ea4ea 100644 --- a/lib/widgets/sessions/session_creator.dart +++ b/lib/widgets/sessions/session_creator.dart @@ -9,6 +9,7 @@ import 'package:sendtrain/database/database.dart'; import 'package:sendtrain/widgets/builders/dialogs.dart'; import 'package:sendtrain/widgets/generic/elements/form_search_input.dart'; import 'package:sendtrain/widgets/generic/elements/form_text_input.dart'; +import 'package:sendtrain/widgets/sessions/session_view.dart'; class SessionCreator extends StatefulWidget { const SessionCreator({super.key, this.data, this.session}); @@ -123,8 +124,8 @@ class _SessionCreatorState extends State { createSession(_formKey.currentContext) .then((id) => { SessionsDao(db).find(id).then( - (session) => showSessionDialog( - session, + (session) => showGenericDialog( + SessionView(session: session), _formKey .currentContext!)), Navigator.pop( diff --git a/lib/widgets/sessions/session_view.dart b/lib/widgets/sessions/session_view.dart index 8c1c285..4e88728 100644 --- a/lib/widgets/sessions/session_view.dart +++ b/lib/widgets/sessions/session_view.dart @@ -7,6 +7,7 @@ import 'package:provider/provider.dart'; import 'package:sendtrain/daos/activities_dao.dart'; import 'package:sendtrain/database/database.dart'; import 'package:sendtrain/extensions/string_extensions.dart'; +import 'package:sendtrain/widgets/generic/elements/generic_progress_indicator.dart'; import 'package:sendtrain/widgets/sessions/session_view_achievements.dart'; import 'package:sendtrain/widgets/sessions/session_view_activities.dart'; import 'package:sendtrain/widgets/sessions/session_view_media.dart'; @@ -28,12 +29,13 @@ class _SessionViewState extends State { initializeDateFormatting('en'); final DateFormat dateFormat = DateFormat('yyyy-MM-dd'); - return FutureBuilder>( - future: ActivitiesDao(Provider.of(context)) - .sessionActivities(session.id), + return StreamBuilder>( + stream: ActivitiesDao(Provider.of(context)) + .watchSessionActivities(session.id), builder: (context, snapshot) { if (snapshot.hasData) { final activities = snapshot.data!; + return Scaffold( floatingActionButtonLocation: ExpandableFab.location, floatingActionButton: ExpandableFab( @@ -100,13 +102,7 @@ class _SessionViewState extends State { ], )); } else { - return Container( - alignment: Alignment.center, - child: SizedBox( - height: 50.0, - width: 50.0, - child: CircularProgressIndicator(), - )); + return GenericProgressIndicator(); } }); } diff --git a/lib/widgets/sessions/session_view_activities.dart b/lib/widgets/sessions/session_view_activities.dart index 8a673b9..274f991 100644 --- a/lib/widgets/sessions/session_view_activities.dart +++ b/lib/widgets/sessions/session_view_activities.dart @@ -2,21 +2,27 @@ import 'package:flutter/material.dart'; import 'package:sendtrain/database/database.dart'; import 'package:sendtrain/widgets/activities/activity_card.dart'; -class SessionViewActivities extends StatelessWidget { +class SessionViewActivities extends StatefulWidget { const SessionViewActivities({super.key, required this.activities }); final List activities; + @override + State createState() => _SessionViewActivitiesState(); +} + +class _SessionViewActivitiesState extends State { + @override Widget build(BuildContext context) { return Expanded( child: ListView.builder( // shrinkWrap: true, padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), - itemCount: activities.length, + itemCount: widget.activities.length, itemBuilder: (BuildContext context, int index) { return ActivityCard( - activity: activities[index]); + activity: widget.activities[index]); }, )); }