session crud #5

Merged
jshbrmn merged 22 commits from session-crud into main 2025-01-05 19:02:13 -08:00
15 changed files with 315 additions and 282 deletions
Showing only changes of commit 8e0ec614a0 - Show all commits

View File

@ -4,7 +4,8 @@ import 'package:sendtrain/database/database.dart';
part 'activities_dao.g.dart'; part 'activities_dao.g.dart';
@DriftAccessor(tables: [Activities]) @DriftAccessor(tables: [Activities])
class ActivitiesDao extends DatabaseAccessor<AppDatabase> with _$ActivitiesDaoMixin { class ActivitiesDao extends DatabaseAccessor<AppDatabase>
with _$ActivitiesDaoMixin {
ActivitiesDao(super.db); ActivitiesDao(super.db);
Future<List<Activity>> all() async { Future<List<Activity>> all() async {
@ -12,26 +13,71 @@ class ActivitiesDao extends DatabaseAccessor<AppDatabase> with _$ActivitiesDaoMi
} }
Future<Activity> find(int id) async { Future<Activity> 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 remove(Activity activity) => delete(activities).delete(activity);
Future<List<Activity>> sessionActivities(int id) async { Future<List<Activity>> activitiesFromSession(int id) async {
final result = select(db.sessionActivities).join( final result = select(db.sessionActivities).join(
[ [
innerJoin( innerJoin(
db.activities, db.activities,
db.activities.id db.activities.id.equalsExp(db.sessionActivities.activityId),
.equalsExp(db.sessionActivities.activityId),
), ),
], ],
)..where(db.sessionActivities.sessionId.equals(id)); )..where(db.sessionActivities.sessionId.equals(id));
final activities = (await result.get()) final activities =
.map((e) => e.readTable(db.activities)) (await result.get()).map((e) => e.readTable(db.activities)).toList();
.toList();
return activities; return activities;
} }
Stream<List<Activity>> 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<SessionActivity> _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;
// }
} }

View File

@ -0,0 +1,3 @@
import 'package:intl/intl.dart';
final DateFormat dateFormat = DateFormat('yyyy-MM-dd');

View File

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
import 'package:sendtrain/database/database.dart';
ImageProvider findMediaByType(List<MediaItem> media, String type) {
Iterable<MediaItem>? 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');
}
}

View File

@ -4,8 +4,12 @@ import 'package:sendtrain/daos/activities_dao.dart';
import 'package:sendtrain/daos/media_items_dao.dart'; import 'package:sendtrain/daos/media_items_dao.dart';
import 'package:sendtrain/database/database.dart'; import 'package:sendtrain/database/database.dart';
import 'package:sendtrain/extensions/string_extensions.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/models/activity_timer_model.dart';
import 'package:sendtrain/widgets/activities/activity_view.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 { class ActivityCard extends StatefulWidget {
final Activity activity; final Activity activity;
@ -43,49 +47,15 @@ class ActivityCardState extends State<ActivityCard> {
: Theme.of(context).colorScheme.surfaceContainerLow, : Theme.of(context).colorScheme.surfaceContainerLow,
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
child: InkWell( child: InkWell(
onTap: () => showGeneralDialog( onTap: () => showGenericDialog(
barrierColor: Colors.black.withOpacity(0.5), ActivityView(activity: widget.activity), context),
transitionDuration: const Duration(milliseconds: 220),
transitionBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
Animation<Offset> custom = Tween<Offset>(
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();
}),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
ListTile( ListTile(
// visualDensity: VisualDensity(horizontal: VisualDensity.maximumDensity), // visualDensity: VisualDensity(horizontal: VisualDensity.maximumDensity),
leading: Padding( leading: CardImage(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), image: findMediaByType(mediaItems, 'image')),
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)),
),
)),
title: Consumer<ActivityTimerModel>( title: Consumer<ActivityTimerModel>(
builder: (context, atm, child) { builder: (context, atm, child) {
if (atm.activity?.id == widget.activity.id) { if (atm.activity?.id == widget.activity.id) {
@ -112,95 +82,27 @@ class ActivityCardState extends State<ActivityCard> {
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
icon: Icon(Icons.close_rounded), icon: Icon(Icons.close_rounded),
onPressed: () { onPressed: () {
showAdaptiveDialog( showRemovalDialog(
context: context, 'Activity Removal',
builder: (BuildContext context) => 'Would you like to permanently remove this activity from the current session?',
AlertDialog( context,
title: const Text('Activity Removal'), ActivitiesDao(
content: const Text( Provider.of<AppDatabase>(
'Would you like to permanently remove this activity from the current session?'), context,
actions: <Widget>[ listen: false)),
TextButton( widget.activity)
onPressed: () => Navigator.pop( .then((result) {
context, 'Cancel'), setState(() {});
child: const Text('Cancel'), });
),
TextButton(
onPressed: () => {
ActivitiesDao(
Provider.of<AppDatabase>(
context,
listen: false))
.remove(widget.activity)
.then((result) {
setState(() {});
}),
Navigator.pop(context, 'OK')
},
child: const Text('OK'),
),
],
),
);
}, },
) )
]) ])),
// 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: <Widget>[
// TextButton(
// onPressed: () =>
// Navigator.pop(context, 'Cancel'),
// child: const Text('Cancel'),
// ),
// TextButton(
// onPressed: () =>
// Navigator.pop(context, 'OK'),
// child: const Text('OK'),
// ),
// ],
// ),
// );
// },
// ))
),
], ],
)), )),
); );
} else { } else {
return Container( return GenericProgressIndicator();
alignment: Alignment.center,
child: SizedBox(
height: 50.0,
width: 50.0,
child: CircularProgressIndicator(),
));
} }
}); });
} }
ImageProvider findMediaByType(List<MediaItem> media, String type) {
Iterable<MediaItem>? 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');
}
}
} }

View File

@ -1,8 +1,6 @@
import 'package:flutter/material.dart'; 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( return showGeneralDialog(
barrierColor: Colors.black.withOpacity(0.5), barrierColor: Colors.black.withOpacity(0.5),
transitionDuration: const Duration(milliseconds: 220), 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)) begin: const Offset(0.0, 1.0), end: const Offset(0.0, 0.0))
.animate(animation); .animate(animation);
return SlideTransition( return SlideTransition(
position: custom, position: custom, child: Dialog.fullscreen(child: object));
child: Dialog.fullscreen(child: SessionView(session: session)));
}, },
barrierDismissible: true, barrierDismissible: true,
barrierLabel: '', barrierLabel: '',

View File

@ -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),
);
}
}

View File

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
class CardImage extends StatelessWidget {
const CardImage({super.key, required this.image});
final ImageProvider<Object> 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)),
),
));
}
}

View File

@ -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(),
));
}
}

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:sendtrain/daos/sessions_dao.dart'; import 'package:sendtrain/daos/sessions_dao.dart';
import 'package:sendtrain/database/database.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:sendtrain/widgets/sessions/session_card.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
@ -95,13 +96,7 @@ class _SessionsScreenState extends State<SessionsScreen> {
], ],
); );
} else { } else {
return Container( return GenericProgressIndicator();
alignment: Alignment.center,
child: SizedBox(
height: 50.0,
width: 50.0,
child: CircularProgressIndicator(),
));
} }
}); });
} }

View File

@ -1,12 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/date_symbol_data_local.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:sendtrain/daos/media_items_dao.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/database/database.dart' hide ActivityAction;
import 'package:sendtrain/extensions/string_extensions.dart'; import 'package:sendtrain/widgets/generic/elements/generic_progress_indicator.dart';
import 'package:sendtrain/widgets/builders/dialogs.dart'; import 'package:sendtrain/widgets/sessions/session_card_full.dart';
import 'package:sendtrain/widgets/sessions/session_card_small.dart';
class SessionCard extends StatefulWidget { class SessionCard extends StatefulWidget {
final int type; final int type;
@ -24,11 +23,6 @@ class _SessionCardState extends State<SessionCard> {
final Session session = widget.session; final Session session = widget.session;
initializeDateFormatting('en'); 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<List<MediaItem>>( return FutureBuilder<List<MediaItem>>(
future: MediaItemsDao(Provider.of<AppDatabase>(context)) future: MediaItemsDao(Provider.of<AppDatabase>(context))
@ -38,126 +32,13 @@ class _SessionCardState extends State<SessionCard> {
List<MediaItem> mediaItems = snapshot.data!; List<MediaItem> mediaItems = snapshot.data!;
if (type == 0) { if (type == 0) {
return Card( return SessionCardFull(session: session, mediaItems: mediaItems);
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: <Widget>[
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<AppDatabase>(
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),
),
],
)),
);
} else { } else {
return Card( return SessionCardSmall(session: session, mediaItems: mediaItems);
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: <Widget>[
ListTile(
title: Text(
maxLines: 3,
session.title.toTitleCase(),
textAlign: TextAlign.center),
subtitle: Text(
maxLines: 1,
dateFormat
.format(session.date as DateTime),
textAlign: TextAlign.center),
),
])))));
} }
} else { } else {
return Container( return GenericProgressIndicator();
alignment: Alignment.center,
child: SizedBox(
height: 50.0,
width: 50.0,
child: CircularProgressIndicator(),
));
} }
}); });
} }
ImageProvider findMediaByType(List<MediaItem> media, String type) {
Iterable<MediaItem>? 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');
}
}
} }

View File

@ -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<MediaItem> mediaItems;
@override
State<SessionCardFull> createState() => _SessionCardFullState();
}
class _SessionCardFullState extends State<SessionCardFull> {
@override
Widget build(BuildContext context) {
final Session session = widget.session;
final List<MediaItem> 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: <Widget>[
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<AppDatabase>(context,
listen: false)),
session)
.then((result) {
setState(() {});
});
},
),
),
CardContent(content: session.content)
],
)),
);
}
}

View File

@ -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<MediaItem> mediaItems;
@override
State<SessionCardSmall> createState() => _SessionCardSmallState();
}
class _SessionCardSmallState extends State<SessionCardSmall> {
@override
Widget build(BuildContext context) {
final Session session = widget.session;
final List<MediaItem> 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: <Widget>[
ListTile(
title: Text(
maxLines: 3,
session.title.toTitleCase(),
textAlign: TextAlign.center),
subtitle: Text(
maxLines: 1,
dateFormat.format(session.date as DateTime),
textAlign: TextAlign.center),
),
])))));
}
}

View File

@ -9,6 +9,7 @@ import 'package:sendtrain/database/database.dart';
import 'package:sendtrain/widgets/builders/dialogs.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_search_input.dart';
import 'package:sendtrain/widgets/generic/elements/form_text_input.dart'; import 'package:sendtrain/widgets/generic/elements/form_text_input.dart';
import 'package:sendtrain/widgets/sessions/session_view.dart';
class SessionCreator extends StatefulWidget { class SessionCreator extends StatefulWidget {
const SessionCreator({super.key, this.data, this.session}); const SessionCreator({super.key, this.data, this.session});
@ -123,8 +124,8 @@ class _SessionCreatorState extends State<SessionCreator> {
createSession(_formKey.currentContext) createSession(_formKey.currentContext)
.then((id) => { .then((id) => {
SessionsDao(db).find(id).then( SessionsDao(db).find(id).then(
(session) => showSessionDialog( (session) => showGenericDialog(
session, SessionView(session: session),
_formKey _formKey
.currentContext!)), .currentContext!)),
Navigator.pop( Navigator.pop(

View File

@ -7,6 +7,7 @@ import 'package:provider/provider.dart';
import 'package:sendtrain/daos/activities_dao.dart'; import 'package:sendtrain/daos/activities_dao.dart';
import 'package:sendtrain/database/database.dart'; import 'package:sendtrain/database/database.dart';
import 'package:sendtrain/extensions/string_extensions.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_achievements.dart';
import 'package:sendtrain/widgets/sessions/session_view_activities.dart'; import 'package:sendtrain/widgets/sessions/session_view_activities.dart';
import 'package:sendtrain/widgets/sessions/session_view_media.dart'; import 'package:sendtrain/widgets/sessions/session_view_media.dart';
@ -28,12 +29,13 @@ class _SessionViewState extends State<SessionView> {
initializeDateFormatting('en'); initializeDateFormatting('en');
final DateFormat dateFormat = DateFormat('yyyy-MM-dd'); final DateFormat dateFormat = DateFormat('yyyy-MM-dd');
return FutureBuilder<List<Activity>>( return StreamBuilder<List<Activity>>(
future: ActivitiesDao(Provider.of<AppDatabase>(context)) stream: ActivitiesDao(Provider.of<AppDatabase>(context))
.sessionActivities(session.id), .watchSessionActivities(session.id),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
final activities = snapshot.data!; final activities = snapshot.data!;
return Scaffold( return Scaffold(
floatingActionButtonLocation: ExpandableFab.location, floatingActionButtonLocation: ExpandableFab.location,
floatingActionButton: ExpandableFab( floatingActionButton: ExpandableFab(
@ -100,13 +102,7 @@ class _SessionViewState extends State<SessionView> {
], ],
)); ));
} else { } else {
return Container( return GenericProgressIndicator();
alignment: Alignment.center,
child: SizedBox(
height: 50.0,
width: 50.0,
child: CircularProgressIndicator(),
));
} }
}); });
} }

View File

@ -2,21 +2,27 @@ import 'package:flutter/material.dart';
import 'package:sendtrain/database/database.dart'; import 'package:sendtrain/database/database.dart';
import 'package:sendtrain/widgets/activities/activity_card.dart'; import 'package:sendtrain/widgets/activities/activity_card.dart';
class SessionViewActivities extends StatelessWidget { class SessionViewActivities extends StatefulWidget {
const SessionViewActivities({super.key, required this.activities }); const SessionViewActivities({super.key, required this.activities });
final List<Activity> activities; final List<Activity> activities;
@override
State<SessionViewActivities> createState() => _SessionViewActivitiesState();
}
class _SessionViewActivitiesState extends State<SessionViewActivities> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Expanded( return Expanded(
child: ListView.builder( child: ListView.builder(
// shrinkWrap: true, // shrinkWrap: true,
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
itemCount: activities.length, itemCount: widget.activities.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return ActivityCard( return ActivityCard(
activity: activities[index]); activity: widget.activities[index]);
}, },
)); ));
} }