small refactor, better dao thigns

This commit is contained in:
Joshua Burman 2024-12-21 17:51:24 -05:00
parent 3153bf13f9
commit 1234a300e1
9 changed files with 152 additions and 182 deletions

View File

@ -11,8 +11,8 @@ class ActivitiesDao extends DatabaseAccessor<AppDatabase> with _$ActivitiesDaoMi
return await select(activities).get();
}
Future<List<Activity>> find(int id) async {
return await (select(activities)..where((activity) => activity.id.equals(id) )).get();
Future<Activity> find(int id) async {
return await (select(activities)..where((activity) => activity.id.equals(id) )).getSingle();
}
Future<List<Activity>> sessionActivities(int id) async {

View File

@ -11,11 +11,31 @@ class MediaItemsDao extends DatabaseAccessor<AppDatabase> with _$MediaItemsDaoMi
return await select(mediaItems).get();
}
Future<List<MediaItem>> find(int id) async {
return await (select(mediaItems)..where((mediaItem) => mediaItem.id.equals(id) )).get();
Future<MediaItem> find(int id) async {
return await (select(mediaItems)..where((mediaItem) => mediaItem.id.equals(id) )).getSingle();
}
Future<List<MediaItem>> mediaItemsFromSession(Session session) async {
Future<List<MediaItem>> fromActivity(Activity activity) async {
final result = select(db.objectMediaItems).join(
[
innerJoin(
db.mediaItems,
db.mediaItems.id.equalsExp(db.objectMediaItems.mediaId),
),
],
)
..where(
db.objectMediaItems.objectType.equals(ObjectType.activities.name))
..where(db.objectMediaItems.objectId.equals(activity.id));
final mediaItems = (await result.get())
.map((e) => e.readTable(db.mediaItems))
.toList();
return mediaItems;
}
Future<List<MediaItem>> fromSession(Session session) async {
final result = select(db.objectMediaItems).join(
[
innerJoin(

View File

@ -11,11 +11,11 @@ class SessionActivitiesDao extends DatabaseAccessor<AppDatabase> with _$SessionA
return await select(sessionActivities).get();
}
Future<List<SessionActivity>> find(int id) async {
return await (select(sessionActivities)..where((sessionActivity) => sessionActivity.id.equals(id) )).get();
Future<SessionActivity> find(int id) async {
return await (select(sessionActivities)..where((sessionActivity) => sessionActivity.id.equals(id) )).getSingle();
}
Future<List<SessionActivity>> sessionActivitiesBySessionId(int id) async {
Future<List<SessionActivity>> fromSessionId(int id) async {
final result = db.managers.sessionActivities
.filter((sessionActivity) => sessionActivity.sessionId.id(id));

View File

@ -11,7 +11,7 @@ class SessionsDao extends DatabaseAccessor<AppDatabase> with _$SessionsDaoMixin
return await select(sessions).get();
}
Future<List<Session>> find(int id) async {
return await (select(sessions)..where((session) => session.id.equals(id) )).get();
Future<Session> find(int id) async {
return await (select(sessions)..where((session) => session.id.equals(id) )).getSingle();
}
}

View File

@ -30,12 +30,13 @@ class ActivityTimerModel with ChangeNotifier {
double get progress => _progress;
int get totalTime => _totalTime;
void setup(ActivityModel activityModel) {
void setup(ActivityModel activityModel, Activity activity) {
if (_activityModel == null || activityModel.id != _activityModel?.id) {
_periodicTimer?.cancel();
_progress = 0;
_isc = null;
_activityModel = activityModel;
_activity = activity;
_sets = activityModel.actions[0].items();
_currentActionNum = 0;
_currentSetNum = 0;

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:sendtrain/classes/media.dart';
import 'package:sendtrain/daos/media_items_dao.dart';
import 'package:sendtrain/database/database.dart';
import 'package:sendtrain/models/activity_model.dart';
import 'package:sendtrain/models/activity_timer_model.dart';
@ -30,97 +30,113 @@ class ActivityCardState extends State<ActivityCard> {
final ActivityTimerModel atm =
Provider.of<ActivityTimerModel>(context, listen: false);
return Card(
color: atm.activity?.id == widget.activity.id
? Theme.of(context).colorScheme.primaryContainer
: 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<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(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
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.cover,
image: findMediaByType(
widget.activity.actions[0].media, 'image')),
// color: Colors.blue,
borderRadius:
const BorderRadius.all(Radius.elliptical(10, 10)),
),
)),
title: Consumer<ActivityTimerModel>(
builder: (context, atm, child) {
if (atm.activity?.id == widget.activity.id) {
return Text(
maxLines: 1,
"${widget.data.title} (${formattedTime(atm.totalTime)})");
} else {
return Text(maxLines: 1, widget.data.title);
}
},
),
subtitle: Text(maxLines: 2, widget.data.description),
trailing: IconButton(
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'),
),
],
),
);
},
return FutureBuilder<List<MediaItem>>(
future: MediaItemsDao(Provider.of<AppDatabase>(context))
.fromActivity(widget.data),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<MediaItem> mediaItems = snapshot.data!;
return Card(
color: atm.activity?.id == widget.activity.id
? Theme.of(context).colorScheme.primaryContainer
: 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<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(
activityModel: widget.activity,
activity: widget.data)));
},
barrierDismissible: true,
barrierLabel: '',
context: context,
pageBuilder: (context, animation1, animation2) {
return Container();
}),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
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.cover,
image:
findMediaByType(mediaItems, 'image')),
// color: Colors.blue,
borderRadius: const BorderRadius.all(
Radius.elliptical(10, 10)),
),
)),
title: Consumer<ActivityTimerModel>(
builder: (context, atm, child) {
if (atm.activity?.id == widget.activity.id) {
return Text(
maxLines: 1,
"${widget.data.title} (${formattedTime(atm.totalTime)})");
} else {
return Text(maxLines: 1, widget.data.title);
}
},
),
subtitle: Text(maxLines: 2, widget.data.description),
trailing: IconButton(
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 {
return CircularProgressIndicator();
}
});
}
ImageProvider findMediaByType(List<Media>? media, String type) {
var found = media?.where((m) => m.type == 'image');
ImageProvider findMediaByType(List<MediaItem> media, String type) {
Iterable<MediaItem>? found = media.where((m) => m.type == MediaType.image);
if (found != null) {
if (found.isNotEmpty) {
return NetworkImage(found.first.reference);
} else {
// Element is not found

View File

@ -1,16 +1,18 @@
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';
import 'package:sendtrain/database/database.dart';
import 'package:sendtrain/models/activity_model.dart';
import 'package:sendtrain/models/activity_timer_model.dart';
import 'package:sendtrain/widgets/activity_action_view.dart';
import 'package:sendtrain/widgets/media_card.dart';
import 'package:sendtrain/widgets/activity_view_categories.dart';
import 'package:sendtrain/widgets/activity_view_media.dart';
class ActivityView extends StatefulWidget {
const ActivityView({super.key, required this.activity});
final ActivityModel activity;
const ActivityView(
{super.key, required this.activityModel, required this.activity});
final ActivityModel activityModel;
final Activity activity;
@override
State<ActivityView> createState() => _ActivityViewState();
@ -19,11 +21,12 @@ class ActivityView extends StatefulWidget {
class _ActivityViewState extends State<ActivityView> {
@override
Widget build(BuildContext context) {
ActivityModel activity = widget.activity;
final ActivityModel activityModel = widget.activityModel;
final Activity activity = widget.activity;
ActivityTimerModel atm =
Provider.of<ActivityTimerModel>(context, listen: false);
atm.setup(activity);
atm.setup(activityModel, activity);
return Scaffold(
floatingActionButtonLocation: ExpandableFab.location,
@ -63,15 +66,15 @@ class _ActivityViewState extends State<ActivityView> {
maxLines: 1,
style: const TextStyle(
fontSize: 25, fontWeight: FontWeight.bold),
activity.title)),
ActivityViewCategories(categories: activity.categories),
activityModel.title)),
ActivityViewCategories(categories: activityModel.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)),
activityModel.description)),
ActivityViewMedia(activity: activity),
const Padding(
padding: EdgeInsets.fromLTRB(15, 30, 0, 10),
@ -139,77 +142,7 @@ class _ActivityViewState extends State<ActivityView> {
semanticsLabel: 'Activity Progress',
);
})),
ActivityActionView(action: activity.actions[0]),
ActivityActionView(action: activityModel.actions[0]),
]));
}
}
class ActivityViewCategories extends StatelessWidget {
const ActivityViewCategories({super.key, this.categories});
final List<String>? categories;
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: SizedBox(
height: 40,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
itemCount: categories?.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(right: 5),
child: ActionChip(
visualDensity: VisualDensity.compact,
avatar: const Icon(Icons.check_circle_outline),
label: Text(maxLines: 1, '${categories?[index]}'),
onPressed: () {},
));
},
))),
],
);
}
}
class ActivityViewMedia extends StatelessWidget {
const ActivityViewMedia({super.key, this.activity});
final ActivityModel? activity;
@override
Widget build(BuildContext context) {
List<Media> media = [];
for (ActivityAction action in activity!.actions) {
if (action.media!.isNotEmpty) {
media.addAll(action.media as Iterable<Media>);
}
}
return Text("media!");
// List<Widget> mediaCards =
// List.generate(media.length, (i) => MediaCard(media: media[i]));
// return Column(
// children: [
// SizedBox(
// width: double.infinity,
// height: 100,
// child: GridView.count(
// padding: const EdgeInsets.fromLTRB(15, 0, 0, 0),
// scrollDirection: Axis.horizontal,
// crossAxisSpacing: 5,
// mainAxisSpacing: 5,
// crossAxisCount: 1,
// children: mediaCards))
// ],
// );
}
}

View File

@ -27,7 +27,7 @@ class SessionViewAchievements extends StatelessWidget {
Widget build(BuildContext context) {
return FutureBuilder<List<SessionActivity>>(
future: SessionActivitiesDao(Provider.of<AppDatabase>(context))
.sessionActivitiesBySessionId(session.id),
.fromSessionId(session.id),
builder: (context, snapshot) {
if (snapshot.hasData) {
final sessionActivities = snapshot.data!;

View File

@ -13,7 +13,7 @@ class SessionViewMedia extends StatelessWidget {
Widget build(BuildContext context) {
return FutureBuilder<List<MediaItem>>(
future: MediaItemsDao(Provider.of<AppDatabase>(context))
.mediaItemsFromSession(session),
.fromSession(session),
builder: (context, snapshot) {
if (snapshot.hasData) {
final mediaItems = snapshot.data!;