From 4887826a36ba79f9218b8c13e1b98cb5ce5c9215 Mon Sep 17 00:00:00 2001 From: Kima Date: Thu, 28 Mar 2024 22:29:25 +0100 Subject: [PATCH] lot of things done, like custom lesson things --- refilc/lib/database/init.dart | 2 + refilc/lib/database/query.dart | 17 +- refilc/lib/database/store.dart | 8 +- refilc/lib/theme/theme.dart | 18 +- .../widgets/lesson/lesson_view.i18n.dart | 12 ++ .../widgets/lesson/lesson_viewable.dart | 194 +++++++++++++++++- .../lib/pages/timetable/timetable_page.dart | 18 ++ 7 files changed, 253 insertions(+), 16 deletions(-) diff --git a/refilc/lib/database/init.dart b/refilc/lib/database/init.dart index d294a56..d06a600 100644 --- a/refilc/lib/database/init.dart +++ b/refilc/lib/database/init.dart @@ -86,6 +86,7 @@ const userDataDB = DatabaseStruct("user_data", { "roundings": String, "grade_rarities": String, "linked_accounts": String, + "custom_lesson_desc": String, }); Future createTable(Database db, DatabaseStruct struct) => @@ -153,6 +154,7 @@ Future initDB(DatabaseProvider database) async { "roundings": "{}", "grade_rarities": "{}", "linked_accounts": "[]", + "custom_lesson_desc": "{}", }); } catch (error) { print("ERROR: migrateDB: $error"); diff --git a/refilc/lib/database/query.dart b/refilc/lib/database/query.dart index aef1725..e899e6d 100644 --- a/refilc/lib/database/query.dart +++ b/refilc/lib/database/query.dart @@ -214,11 +214,13 @@ class UserDatabaseQuery { return lessonCount; } - Future lastSeen({required String userId, required LastSeenCategory category}) async { + Future lastSeen( + {required String userId, required LastSeenCategory category}) async { List userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); if (userData.isEmpty) return DateTime(0); - int? lastSeenDate = userData.elementAt(0)["last_seen_${category.name}"] as int?; + int? lastSeenDate = + userData.elementAt(0)["last_seen_${category.name}"] as int?; if (lastSeenDate == null) return DateTime(0); DateTime lastSeen = DateTime.fromMillisecondsSinceEpoch(lastSeenDate); return lastSeen; @@ -348,4 +350,15 @@ class UserDatabaseQuery { .toList(); return accounts; } + + Future> getCustomLessonDescriptions( + {required String userId}) async { + List userData = + await db.query("user_data", where: "id = ?", whereArgs: [userId]); + if (userData.isEmpty) return {}; + String? descJson = userData.elementAt(0)["custom_lesson_desc"] as String?; + if (descJson == null) return {}; + return (jsonDecode(descJson) as Map) + .map((key, value) => MapEntry(key.toString(), value.toString())); + } } diff --git a/refilc/lib/database/store.dart b/refilc/lib/database/store.dart index 4b0f23f..6132780 100644 --- a/refilc/lib/database/store.dart +++ b/refilc/lib/database/store.dart @@ -136,7 +136,6 @@ class UserDatabaseStore { await db.update("user_data", {"last_seen_${category.name}": lastSeenDate}, where: "id = ?", whereArgs: [userId]); } - // renamed things Future storeRenamedSubjects(Map subjects, @@ -218,4 +217,11 @@ class UserDatabaseStore { await db.update("user_data", {"linked_accounts": accountsJson}, where: "id = ?", whereArgs: [userId]); } + + Future storeCustomLessonDescriptions(Map descs, + {required String userId}) async { + String descJson = jsonEncode(descs); + await db.update("user_data", {"custom_lesson_desc": descJson}, + where: "id = ?", whereArgs: [userId]); + } } diff --git a/refilc/lib/theme/theme.dart b/refilc/lib/theme/theme.dart index bc3d08d..92d252d 100644 --- a/refilc/lib/theme/theme.dart +++ b/refilc/lib/theme/theme.dart @@ -65,10 +65,11 @@ class AppTheme { ? settings.customHighlightColor : _paletteHighlightLight(palette)) ?? lightColors.highlight; - Color textColor = (accentColor == AccentColor.custom - ? settings.customTextColor - : _paletteTextLight(palette)) ?? - lightColors.text; + // Color textColor = (accentColor == AccentColor.custom + // ? settings.customTextColor + // : _paletteTextLight(palette)) ?? + // lightColors.text; + Color textColor = lightColors.text; Color newSecondary = (accentColor == AccentColor.adaptive || accentColor == AccentColor.custom || @@ -174,10 +175,11 @@ class AppTheme { ? settings.customHighlightColor : _paletteHighlightDark(palette)) ?? darkColors.highlight; - Color textColor = (accentColor == AccentColor.custom - ? settings.customTextColor - : _paletteTextDark(palette)) ?? - darkColors.text; + // Color textColor = (accentColor == AccentColor.custom + // ? settings.customTextColor + // : _paletteTextDark(palette)) ?? + // darkColors.text; + Color textColor = darkColors.text; Color newSecondary = (accentColor == AccentColor.adaptive || accentColor == AccentColor.custom || diff --git a/refilc_mobile_ui/lib/common/widgets/lesson/lesson_view.i18n.dart b/refilc_mobile_ui/lib/common/widgets/lesson/lesson_view.i18n.dart index 7cce274..28752ba 100644 --- a/refilc_mobile_ui/lib/common/widgets/lesson/lesson_view.i18n.dart +++ b/refilc_mobile_ui/lib/common/widgets/lesson/lesson_view.i18n.dart @@ -8,18 +8,30 @@ extension Localization on String { "Description": "Description", "Lesson Number": "Lesson Number", "Group": "Group", + "edit_lesson": "Edit Lesson", + "l_desc": "Description...", + "done": "Done", + "cancel": "Cancel", }, "hu_hu": { "Room": "Terem", "Description": "Leírás", "Lesson Number": "Éves óraszám", "Group": "Csoport", + "edit_lesson": "Óra szerkesztése", + "l_desc": "Leírás...", + "done": "Kész", + "cancel": "Mégse", }, "de_de": { "Room": "Raum", "Description": "Bezeichnung", "Lesson Number": "Ordinalzahl", "Group": "Gruppe", + "edit_lesson": "Lektion bearbeiten", + "l_desc": "Beschreibung...", + "done": "Erledigt", + "cancel": "Abbrechen", } }; diff --git a/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart b/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart index c7c8b55..acb9bcc 100644 --- a/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart +++ b/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart @@ -1,25 +1,209 @@ +import 'package:flutter_feather_icons/flutter_feather_icons.dart'; +import 'package:provider/provider.dart'; +import 'package:refilc/api/providers/database_provider.dart'; +import 'package:refilc/api/providers/user_provider.dart'; import 'package:refilc_kreta_api/models/lesson.dart'; +import 'package:refilc_mobile_ui/common/panel/panel_button.dart'; import 'package:refilc_mobile_ui/common/viewable.dart'; import 'package:refilc_mobile_ui/common/widgets/card_handle.dart'; import 'package:refilc/ui/widgets/lesson/lesson_tile.dart'; import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_view.dart'; import 'package:flutter/material.dart'; +import 'lesson_view.i18n.dart'; -class LessonViewable extends StatelessWidget { - const LessonViewable(this.lesson, {super.key, this.swapDesc = false}); +class LessonViewable extends StatefulWidget { + const LessonViewable(this.lesson, + {super.key, this.swapDesc = false, required this.customDesc}); final Lesson lesson; final bool swapDesc; + final String customDesc; + + @override + State createState() => LessonViewableState(); +} + +class LessonViewableState extends State { + final _descTxt = TextEditingController(); + + late UserProvider user; + late DatabaseProvider databaseProvider; @override Widget build(BuildContext context) { - final tile = LessonTile(lesson, swapDesc: swapDesc); + user = Provider.of(context); + databaseProvider = Provider.of(context); - if (lesson.subject.id == '' || tile.lesson.isEmpty) return tile; + if (widget.customDesc.replaceAll(' ', '') != '' && + widget.customDesc != widget.lesson.description) { + _descTxt.text = widget.customDesc; + } + + Lesson lsn = widget.lesson; + lsn.description = widget.customDesc; + + final tile = LessonTile(lsn, swapDesc: widget.swapDesc); + + if (lsn.subject.id == '' || tile.lesson.isEmpty) return tile; return Viewable( tile: tile, - view: CardHandle(child: LessonView(lesson)), + view: CardHandle(child: LessonView(lsn)), + actions: [ + PanelButton( + background: true, + title: Text( + "edit_lesson".i18n, + textAlign: TextAlign.center, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + onPressed: () { + Navigator.of(context, rootNavigator: true).pop(); + + showDialog( + context: context, + builder: (context) => StatefulBuilder(builder: (context, setS) { + return AlertDialog( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(14.0))), + title: Text("edit_lesson".i18n), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // description + TextField( + controller: _descTxt, + decoration: InputDecoration( + border: OutlineInputBorder( + borderSide: const BorderSide( + color: Colors.grey, width: 1.5), + borderRadius: BorderRadius.circular(12.0), + ), + focusedBorder: OutlineInputBorder( + borderSide: const BorderSide( + color: Colors.grey, width: 1.5), + borderRadius: BorderRadius.circular(12.0), + ), + contentPadding: + const EdgeInsets.symmetric(horizontal: 12.0), + hintText: 'l_desc'.i18n, + suffixIcon: IconButton( + icon: const Icon( + FeatherIcons.x, + color: Colors.grey, + size: 18.0, + ), + onPressed: () { + setState(() { + _descTxt.text = ''; + }); + }, + ), + ), + ), + // const SizedBox( + // height: 14.0, + // ), + // // class + // TextField( + // controller: _descTxt, + // onEditingComplete: () async { + // // SharedTheme? theme = await shareProvider.getThemeById( + // // context, + // // id: _paintId.text.replaceAll(' ', ''), + // // ); + + // // if (theme != null) { + // // // set theme variable + // // newThemeByID = theme; + + // // _paintId.clear(); + // // } else { + // // ScaffoldMessenger.of(context).showSnackBar( + // // CustomSnackBar( + // // content: Text("theme_not_found".i18n, + // // style: const TextStyle(color: Colors.white)), + // // backgroundColor: AppColors.of(context).red, + // // context: context, + // // ), + // // ); + // // } + // }, + // decoration: InputDecoration( + // border: OutlineInputBorder( + // borderSide: const BorderSide( + // color: Colors.grey, width: 1.5), + // borderRadius: BorderRadius.circular(12.0), + // ), + // focusedBorder: OutlineInputBorder( + // borderSide: const BorderSide( + // color: Colors.grey, width: 1.5), + // borderRadius: BorderRadius.circular(12.0), + // ), + // contentPadding: + // const EdgeInsets.symmetric(horizontal: 12.0), + // hintText: 'l_desc'.i18n, + // suffixIcon: IconButton( + // icon: const Icon( + // FeatherIcons.x, + // color: Colors.grey, + // size: 18.0, + // ), + // onPressed: () { + // setState(() { + // _descTxt.text = ''; + // }); + // }, + // ), + // ), + // ), + ], + ), + actions: [ + TextButton( + child: Text( + "cancel".i18n, + style: const TextStyle(fontWeight: FontWeight.w500), + ), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + TextButton( + child: Text( + "done".i18n, + style: const TextStyle(fontWeight: FontWeight.w500), + ), + onPressed: () async { + saveLesson(); + + Navigator.of(context).pop(); + setState(() {}); + }, + ), + ], + ); + }), + ); + }, + ), + ], ); } + + void saveLesson() async { + Map lessonDesc = await databaseProvider.userQuery + .getCustomLessonDescriptions(userId: user.id!); + + lessonDesc[widget.lesson.id] = _descTxt.text; + + if (_descTxt.text.replaceAll(' ', '') == '') { + lessonDesc.remove(widget.lesson.id); + } + + // ignore: use_build_context_synchronously + await databaseProvider.userStore + .storeCustomLessonDescriptions(lessonDesc, userId: user.id!); + } } diff --git a/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart b/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart index bbd5853..9fb15a0 100644 --- a/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart +++ b/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:animations/animations.dart'; import 'package:i18n_extension/i18n_extension.dart'; +import 'package:refilc/api/providers/database_provider.dart'; import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/models/settings.dart'; import 'package:refilc/providers/third_party_provider.dart'; @@ -70,6 +71,7 @@ class TimetablePageState extends State late TimetableProvider timetableProvider; late UpdateProvider updateProvider; late SettingsProvider settingsProvider; + late DatabaseProvider db; late String firstName; @@ -78,6 +80,8 @@ class TimetablePageState extends State late Widget empty; + Map customLessonDesc = {}; + int _getDayIndex(DateTime date) { int index = 0; if (_controller.days == null || (_controller.days?.isEmpty ?? true)) { @@ -163,6 +167,9 @@ class TimetablePageState extends State user = Provider.of(context, listen: false); user.addListener(_userListener); + // listen for lesson customization + db = Provider.of(context, listen: false); + // Register listening for app state changes to refresh the timetable WidgetsBinding.instance.addObserver(this); } @@ -187,6 +194,11 @@ class TimetablePageState extends State } } + void getCustom() async { + customLessonDesc = + await db.userQuery.getCustomLessonDescriptions(userId: user.id!); + } + @override Widget build(BuildContext context) { user = Provider.of(context); @@ -194,6 +206,8 @@ class TimetablePageState extends State updateProvider = Provider.of(context); settingsProvider = Provider.of(context); + getCustom(); + // First name List nameParts = user.displayName?.split(" ") ?? ["?"]; firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; @@ -667,6 +681,10 @@ class TimetablePageState extends State child: LessonViewable( lesson, swapDesc: swapDescDay, + customDesc: + customLessonDesc[ + lesson.id] ?? + lesson.description, ), ), ),