further refactoring, conversion to stream
This commit is contained in:
parent
fa374a5bc2
commit
8e0ec614a0
@ -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;
|
||||||
|
// }
|
||||||
}
|
}
|
3
lib/helpers/date_helpers.dart
Normal file
3
lib/helpers/date_helpers.dart
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
final DateFormat dateFormat = DateFormat('yyyy-MM-dd');
|
13
lib/helpers/media_helpers.dart
Normal file
13
lib/helpers/media_helpers.dart
Normal 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');
|
||||||
|
}
|
||||||
|
}
|
@ -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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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: '',
|
||||||
|
19
lib/widgets/generic/elements/card_content.dart
Normal file
19
lib/widgets/generic/elements/card_content.dart
Normal 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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
24
lib/widgets/generic/elements/card_image.dart
Normal file
24
lib/widgets/generic/elements/card_image.dart
Normal 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)),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
16
lib/widgets/generic/elements/generic_progress_indicator.dart
Normal file
16
lib/widgets/generic/elements/generic_progress_indicator.dart
Normal 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(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -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(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
72
lib/widgets/sessions/session_card_full.dart
Normal file
72
lib/widgets/sessions/session_card_full.dart
Normal 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)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
62
lib/widgets/sessions/session_card_small.dart
Normal file
62
lib/widgets/sessions/session_card_small.dart
Normal 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),
|
||||||
|
),
|
||||||
|
])))));
|
||||||
|
}
|
||||||
|
}
|
@ -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(
|
||||||
|
@ -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(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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]);
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user