diff --git a/lib/daos/sessions_dao.dart b/lib/daos/sessions_dao.dart index d74273f..fccce8c 100644 --- a/lib/daos/sessions_dao.dart +++ b/lib/daos/sessions_dao.dart @@ -7,21 +7,12 @@ part 'sessions_dao.g.dart'; class SessionsDao extends DatabaseAccessor with _$SessionsDaoMixin { SessionsDao(super.db); - Future> all() async { - return await select(sessions).get(); - } - - // Future> remove - - // Future> all() => select(sessions).get(); - // Stream> watch() => select(sessions).watch(); - // Future insert(Session session) => into(sessions).insert(session); + Future find(int id) => (select(sessions)..where((session) => session.id.equals(id) )).getSingle(); + Future> all() => select(sessions).get(); + Stream> watch() => select(sessions).watch(); + Future createOrUpdate(SessionsCompanion session) => into(sessions).insertOnConflictUpdate(session); // Future replace(Session session) => update(sessions).replace(session); Future remove(Session session) => delete(sessions).delete(session); - Future find(int id) async { - return await (select(sessions)..where((session) => session.id.equals(id) )).getSingle(); - } - } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index bd25344..98150a1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,6 +6,7 @@ import 'package:sendtrain/screens/activities_screen.dart'; import 'package:sendtrain/screens/sessions_screen.dart'; // ignore: unused_import import 'package:sendtrain/database/seed.dart'; +import 'package:sendtrain/widgets/session_creator.dart'; class SendTrain extends StatelessWidget { const SendTrain({super.key}); @@ -83,7 +84,12 @@ class _AppState extends State { ]), floatingActionButton: FloatingActionButton.extended( onPressed: () { - // Add your onPressed code here! + showAdaptiveDialog( + barrierColor: Colors.black.withOpacity(0.5), + builder: (BuildContext context) => SessionCreator(), + barrierDismissible: true, + barrierLabel: '', + context: context); }, label: const Text('New Session'), icon: const Icon(Icons.add_chart), diff --git a/lib/screens/sessions_screen.dart b/lib/screens/sessions_screen.dart index 1499b85..81dec32 100644 --- a/lib/screens/sessions_screen.dart +++ b/lib/screens/sessions_screen.dart @@ -1,4 +1,5 @@ // import 'package:drift/drift.dart' hide Column; +import 'package:drift/drift.dart' hide Column; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:sendtrain/daos/sessions_dao.dart'; @@ -6,24 +7,30 @@ import 'package:sendtrain/database/database.dart'; import '../widgets/session_card.dart'; import 'package:collection/collection.dart'; -class SessionsScreen extends StatelessWidget { +class SessionsScreen extends StatefulWidget { const SessionsScreen({super.key}); + @override + State createState() => _SessionsScreenState(); +} + +class _SessionsScreenState extends State { Widget getSessionCard(session) { if (session != null) { return SessionCard(session: session); } else { return Padding( - padding: EdgeInsets.all(15), - child: Icon(Icons.do_not_disturb_alt_outlined) - ); + padding: EdgeInsets.all(15), + child: Icon(Icons.do_not_disturb_alt_outlined)); } } @override Widget build(BuildContext context) { - return FutureBuilder>( - future: SessionsDao(Provider.of(context)).all(), + SessionsDao dao = SessionsDao(Provider.of(context)); + + return StreamBuilder>( + stream: dao.watch(), builder: (context, snapshot) { if (snapshot.hasData && snapshot.data!.isNotEmpty) { final sessions = snapshot.data!; @@ -35,8 +42,20 @@ class SessionsScreen extends StatelessWidget { final current = sessions.firstWhereOrNull( (session) => session.status == SessionStatus.started); + if (current == null && upcoming != null) { + dao.createOrUpdate(SessionsCompanion( + id: Value(upcoming.id), + title: Value(upcoming.title), + content: Value(upcoming.content), + status: Value(SessionStatus.started), + address: Value(upcoming.address), + date: Value(upcoming.date) + )); + } + List previousSessions = List.generate(pending.length, (i) => SessionCard(type: 1, session: pending.elementAt(i))); + Widget upcomingSession = getSessionCard(upcoming); Widget currentSession = getSessionCard(current); diff --git a/lib/widgets/session_card.dart b/lib/widgets/session_card.dart index 8cd32f1..61d3137 100644 --- a/lib/widgets/session_card.dart +++ b/lib/widgets/session_card.dart @@ -8,13 +8,21 @@ import 'package:sendtrain/database/database.dart' hide ActivityAction; import 'package:sendtrain/extensions/string_extensions.dart'; import 'package:sendtrain/widgets/session_view.dart'; -class SessionCard extends StatelessWidget { +class SessionCard extends StatefulWidget { final int type; final Session session; const SessionCard({super.key, this.type = 0, required this.session}); + @override + State createState() => _SessionCardState(); +} + +class _SessionCardState extends State { @override Widget build(BuildContext context) { + final int type = widget.type; + final Session session = widget.session; + initializeDateFormatting('en'); final DateFormat dateFormat = DateFormat('yyyy-MM-dd'); @@ -102,12 +110,13 @@ class SessionCard extends StatelessWidget { TextButton( onPressed: () => { SessionsDao(Provider.of( - context, listen: false)) - .remove(session).then((result) { - // ignore: invalid_use_of_protected_member - (context as Element).reassemble(); - }), - Navigator.pop(context, 'OK') + context, + listen: false)) + .remove(session) + .then((result) { + setState(() {}); + }), + Navigator.pop(context, 'OK') }, child: const Text('OK'), ), diff --git a/lib/widgets/session_creator.dart b/lib/widgets/session_creator.dart new file mode 100644 index 0000000..e6842a6 --- /dev/null +++ b/lib/widgets/session_creator.dart @@ -0,0 +1,187 @@ +import 'package:drift/drift.dart' hide Column; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:sendtrain/daos/sessions_dao.dart'; +import 'package:sendtrain/database/database.dart'; +import 'package:sendtrain/widgets/session_view.dart'; + +class SessionCreator extends StatefulWidget { + const SessionCreator({super.key, this.data, this.session}); + + final Session? session; + final Map? data; + + @override + State createState() => _SessionCreatorState(); +} + +class _SessionCreatorState extends State { + final GlobalKey _formKey = GlobalKey(); + + final Map sessionCreateController = { + 'name': TextEditingController(), + 'content': TextEditingController(), + 'status': TextEditingController(), + 'date': TextEditingController(), + }; + + Future createSession(context) { + return SessionsDao(Provider.of(context, listen: false)) + .createOrUpdate(SessionsCompanion( + title: Value(sessionCreateController['name']!.text), + content: Value(sessionCreateController['content']!.text), + status: Value(SessionStatus.pending), + date: + Value(DateTime.parse(sessionCreateController['date']!.text)))); + } + + @override + Widget build(BuildContext context) { + sessionCreateController['date']!.text = + DateFormat('yyyy-MM-dd').format(DateTime.now()); + + return SimpleDialog( + title: Text('Create Session', textAlign: TextAlign.center), + titlePadding: EdgeInsets.only(top: 17.5, bottom: 10), + contentPadding: EdgeInsets.only(left: 30, right: 30, bottom: 15), + children: [ + Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 10, bottom: 10), + child: TextFormField( + controller: sessionCreateController['name'], + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Enter session name', + ), + validator: (String? value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + + if (value.length <= 3 || value.length > 42) { + return 'Please enter between 3 and 42 characters'; + } + return null; + }, + )), + Padding( + padding: EdgeInsets.only(top: 10, bottom: 10), + child: TextFormField( + controller: sessionCreateController['content'], + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Enter session description', + ), + validator: (String? value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + + if (value.length <= 3 || value.length > 256) { + return 'Please enter between 3 and 256 characters'; + } + return null; + }, + )), + Padding( + padding: EdgeInsets.only(top: 7.5, bottom: 7.5), + child: TextFormField( + readOnly: true, + decoration: const InputDecoration( + border: OutlineInputBorder(), + hintText: 'Enter a date for the session', + ), + controller: sessionCreateController['date'], + onTap: () { + showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime.now() + .subtract(Duration(days: 365)), + lastDate: + DateTime.now().add(Duration(days: 365))) + .then((date) { + sessionCreateController['date']?.text = + DateFormat('yyyy-MM-dd').format(date!); + }); + })), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () => { + if (_formKey.currentState!.validate()) + { + createSession(_formKey.currentContext) + .then((id) => { + SessionsDao( + Provider.of( + context, + listen: false)) + .find(id) + .then( + (session) => + showGeneralDialog( + barrierColor: Colors + .black + .withOpacity(0.5), + transitionDuration: + const Duration( + milliseconds: + 220), + transitionBuilder: + (BuildContext + context, + Animation< + double> + animation, + Animation< + double> + secondaryAnimation, + Widget + child) { + Animation 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: SessionView( + session: + session))); + }, + barrierDismissible: + true, + barrierLabel: '', + context: context, + pageBuilder: (context, + animation1, + animation2) { + return Container(); + }).whenComplete(() => Navigator.pop(context, 'Submit')), + ) + }) + } + }, + child: Text('Submit')) + ]) + ], + )) + ]); + } +} diff --git a/lib/widgets/session_view.dart b/lib/widgets/session_view.dart index 296e2a1..f1bce4d 100644 --- a/lib/widgets/session_view.dart +++ b/lib/widgets/session_view.dart @@ -3,27 +3,34 @@ import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:intl/intl.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:provider/provider.dart'; -import 'package:sendtrain/daos/activities_dao.dart'; -import 'package:sendtrain/daos/sessions_dao.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/session_view_achievements.dart'; import 'package:sendtrain/widgets/session_view_activities.dart'; import 'package:sendtrain/widgets/session_view_media.dart'; -class SessionView extends StatelessWidget { +class SessionView extends StatefulWidget { const SessionView({super.key, required this.session}); final Session session; + @override + State createState() => _SessionViewState(); +} + +class _SessionViewState extends State { @override Widget build(BuildContext context) { + final Session session = widget.session; + initializeDateFormatting('en'); final DateFormat dateFormat = DateFormat('yyyy-MM-dd'); return FutureBuilder>( - future: ActivitiesDao(Provider.of(context)).sessionActivities(session.id), + future: ActivitiesDao(Provider.of(context)) + .sessionActivities(session.id), builder: (context, snapshot) { if (snapshot.hasData) { final activities = snapshot.data!; @@ -89,8 +96,7 @@ class SessionView extends StatelessWidget { style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold), 'Activites:')), - SessionViewActivities( - activities: activities), + SessionViewActivities(activities: activities), ], )); } else {