diff --git a/refilc/lib/api/providers/live_card_provider.dart b/refilc/lib/api/providers/live_card_provider.dart index 7ace094..6cf5c6e 100644 --- a/refilc/lib/api/providers/live_card_provider.dart +++ b/refilc/lib/api/providers/live_card_provider.dart @@ -1,8 +1,5 @@ // ignore_for_file: no_leading_underscores_for_local_identifiers -import 'dart:async'; -import 'dart:io'; - import 'package:refilc/api/providers/liveactivity/platform_channel.dart'; import 'package:refilc/helpers/subject.dart'; import 'package:refilc/models/settings.dart'; @@ -39,13 +36,11 @@ class LiveCardProvider extends ChangeNotifier { // LiveCardState currentState = LiveCardState.empty; - late Timer _timer; late final TimetableProvider _timetable; late final SettingsProvider _settings; late Duration _delay; - bool _hasCheckedTimetable = false; LiveCardProvider({ @@ -53,7 +48,6 @@ class LiveCardProvider extends ChangeNotifier { required SettingsProvider settings, }) : _timetable = timetable, _settings = settings { - _timer = Timer.periodic(const Duration(seconds: 1), (timer) => update()); _delay = settings.bellDelayEnabled ? Duration(seconds: settings.bellDelay) : Duration.zero; @@ -87,19 +81,24 @@ class LiveCardProvider extends ChangeNotifier { case LiveCardState.morning: return { "color": - '#${_settings.liveActivityColor.toString().substring(10, 16)}', + '#${_settings.liveActivityColor.toString().substring(10, 16)}', "icon": nextLesson != null ? SubjectIcon.resolveName(subject: nextLesson?.subject) : "book", "title": "Első órádig:", "subtitle": "", "description": "", - "startDate": storeFirstRunDate != null ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - (_delay.inMilliseconds)).toString(): "", + "startDate": storeFirstRunDate != null + ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - + (_delay.inMilliseconds)) + .toString() + : "", "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) + _delay.inMilliseconds) .toString(), "nextSubject": nextLesson != null - ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital() + ? nextLesson?.subject.renamedTo ?? + ShortSubject.resolve(subject: nextLesson?.subject).capital() : "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", }; @@ -107,19 +106,24 @@ class LiveCardProvider extends ChangeNotifier { case LiveCardState.afternoon: return { "color": - '#${_settings.liveActivityColor.toString().substring(10, 16)}', + '#${_settings.liveActivityColor.toString().substring(10, 16)}', "icon": nextLesson != null ? SubjectIcon.resolveName(subject: nextLesson?.subject) : "book", "title": "Első órádig:", "subtitle": "", "description": "", - "startDate": storeFirstRunDate != null ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - (_delay.inMilliseconds)).toString(): "", + "startDate": storeFirstRunDate != null + ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - + (_delay.inMilliseconds)) + .toString() + : "", "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) + _delay.inMilliseconds) .toString(), "nextSubject": nextLesson != null - ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital() + ? nextLesson?.subject.renamedTo ?? + ShortSubject.resolve(subject: nextLesson?.subject).capital() : "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", }; @@ -127,19 +131,24 @@ class LiveCardProvider extends ChangeNotifier { case LiveCardState.night: return { "color": - '#${_settings.liveActivityColor.toString().substring(10, 16)}', + '#${_settings.liveActivityColor.toString().substring(10, 16)}', "icon": nextLesson != null ? SubjectIcon.resolveName(subject: nextLesson?.subject) : "book", "title": "Első órádig:", "subtitle": "", "description": "", - "startDate": storeFirstRunDate != null ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - (_delay.inMilliseconds)).toString(): "", + "startDate": storeFirstRunDate != null + ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - + (_delay.inMilliseconds)) + .toString() + : "", "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) + _delay.inMilliseconds) .toString(), "nextSubject": nextLesson != null - ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital() + ? nextLesson?.subject.renamedTo ?? + ShortSubject.resolve(subject: nextLesson?.subject).capital() : "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", }; @@ -147,25 +156,28 @@ class LiveCardProvider extends ChangeNotifier { case LiveCardState.duringLesson: return { "color": - '#${_settings.liveActivityColor.toString().substring(10, 16)}', + '#${_settings.liveActivityColor.toString().substring(10, 16)}', "icon": currentLesson != null ? SubjectIcon.resolveName(subject: currentLesson?.subject) : "book", "index": - currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "", + currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "", "title": currentLesson != null - ? currentLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: currentLesson?.subject).capital() + ? currentLesson?.subject.renamedTo ?? + ShortSubject.resolve(subject: currentLesson?.subject) + .capital() : "", "subtitle": currentLesson?.room.replaceAll("_", " ") ?? "", "description": currentLesson?.description ?? "", "startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) + _delay.inMilliseconds) .toString(), "endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) + _delay.inMilliseconds) .toString(), "nextSubject": nextLesson != null - ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital() + ? nextLesson?.subject.renamedTo ?? + ShortSubject.resolve(subject: nextLesson?.subject).capital() : "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", }; @@ -181,21 +193,23 @@ class LiveCardProvider extends ChangeNotifier { return { "color": - '#${_settings.liveActivityColor.toString().substring(10, 16)}', + '#${_settings.liveActivityColor.toString().substring(10, 16)}', "icon": iconFloorMap[diff] ?? "cup.and.saucer", "title": "Szünet", "description": "go $diff".i18n.fill([ diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room ]), "startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) + _delay.inMilliseconds) .toString(), "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) + _delay.inMilliseconds) .toString(), "nextSubject": (nextLesson != null - ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital() - : "") + ? nextLesson?.subject.renamedTo ?? + ShortSubject.resolve(subject: nextLesson?.subject) + .capital() + : "") .capital(), "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "index": "", @@ -219,12 +233,12 @@ class LiveCardProvider extends ChangeNotifier { ? Duration(seconds: _settings.bellDelay) : Duration.zero; - DateTime now = _now().add(_delay); if ((currentState == LiveCardState.morning || - currentState == LiveCardState.afternoon || - currentState == LiveCardState.night) && storeFirstRunDate == null) { + currentState == LiveCardState.afternoon || + currentState == LiveCardState.night) && + storeFirstRunDate == null) { storeFirstRunDate = now; } @@ -232,9 +246,9 @@ class LiveCardProvider extends ChangeNotifier { // Filter label lessons #128 today = today .where((lesson) => - lesson.status?.name != "Elmaradt" && - lesson.subject.id != '' && - !lesson.isEmpty) + lesson.status?.name != "Elmaradt" && + lesson.subject.id != '' && + !lesson.isEmpty) .toList(); if (today.isNotEmpty) { @@ -242,7 +256,7 @@ class LiveCardProvider extends ChangeNotifier { today.sort((a, b) => a.start.compareTo(b.start)); final _lesson = today.firstWhere( - (l) => l.start.isBefore(now) && l.end.isAfter(now), + (l) => l.start.isBefore(now) && l.end.isAfter(now), orElse: () => Lesson.fromJson({})); if (_lesson.start.year != 0) { @@ -291,22 +305,21 @@ class LiveCardProvider extends ChangeNotifier { //LIVE ACTIVITIES //CREATE - if (!hasActivityStarted && nextLesson != null && nextLesson! - .start - .difference(now) - .inMinutes <= 60 && (currentState == LiveCardState.morning || - currentState == LiveCardState.afternoon || - currentState == LiveCardState.night)) { + if (!hasActivityStarted && + nextLesson != null && + nextLesson!.start.difference(now).inMinutes <= 60 && + (currentState == LiveCardState.morning || + currentState == LiveCardState.afternoon || + currentState == LiveCardState.night)) { debugPrint( "Az első óra előtt állunk, kevesebb mint egy órával. Létrehozás..."); PlatformChannel.createLiveActivity(toMap()); hasActivityStarted = true; - } - else if (!hasActivityStarted && ((currentState == LiveCardState.duringLesson && - currentLesson != null) || - currentState == LiveCardState.duringBreak)) { - debugPrint( - "Óra van, vagy szünet, de nincs LiveActivity. létrehozás..."); + } else if (!hasActivityStarted && + ((currentState == LiveCardState.duringLesson && + currentLesson != null) || + currentState == LiveCardState.duringBreak)) { + debugPrint("Óra van, vagy szünet, de nincs LiveActivity. létrehozás..."); PlatformChannel.createLiveActivity(toMap()); hasActivityStarted = true; } @@ -317,15 +330,18 @@ class LiveCardProvider extends ChangeNotifier { debugPrint("Valamelyik beállítás megváltozott. Frissítés..."); PlatformChannel.updateLiveActivity(toMap()); hasActivitySettingsChanged = false; - } - else if (nextLesson != null || currentLesson != null) { + } else if (nextLesson != null || currentLesson != null) { bool afterPrevLessonEnd = prevLesson != null && - now.subtract(const Duration(seconds: 1)).isBefore( - prevLesson!.end) && now.isAfter(prevLesson!.end); + now + .subtract(const Duration(seconds: 1)) + .isBefore(prevLesson!.end) && + now.isAfter(prevLesson!.end); bool afterCurrentLessonStart = currentLesson != null && - now.subtract(const Duration(seconds: 1)).isBefore( - currentLesson!.start) && now.isAfter(currentLesson!.start); + now + .subtract(const Duration(seconds: 1)) + .isBefore(currentLesson!.start) && + now.isAfter(currentLesson!.start); if (afterPrevLessonEnd || afterCurrentLessonStart) { debugPrint( "Óra kezdete/vége után 1 másodperccel vagyunk. Frissítés..."); @@ -335,7 +351,9 @@ class LiveCardProvider extends ChangeNotifier { } //END - if (hasActivityStarted && !hasDayEnd && nextLesson == null && + if (hasActivityStarted && + !hasDayEnd && + nextLesson == null && now.isAfter(prevLesson!.end)) { debugPrint("Az utolsó óra véget ért. Befejezés..."); PlatformChannel.endLiveActivity(); @@ -355,4 +373,4 @@ class LiveCardProvider extends ChangeNotifier { List _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? []) .where((l) => _sameDate(l.date, _now())) .toList(); -} \ No newline at end of file +} diff --git a/refilc/lib/api/providers/self_note_provider.dart b/refilc/lib/api/providers/self_note_provider.dart index b19816c..3a095b7 100644 --- a/refilc/lib/api/providers/self_note_provider.dart +++ b/refilc/lib/api/providers/self_note_provider.dart @@ -24,6 +24,10 @@ class SelfNoteProvider with ChangeNotifier { Future restore() async { String? userId = Provider.of(_context, listen: false).id; + // await Provider.of(_context, listen: false) + // .userStore + // .storeSelfNotes([], userId: userId!); + // load self notes from db if (userId != null) { var dbNotes = await Provider.of(_context, listen: false) diff --git a/refilc/lib/models/self_note.dart b/refilc/lib/models/self_note.dart index 609f6ff..bd86a1d 100644 --- a/refilc/lib/models/self_note.dart +++ b/refilc/lib/models/self_note.dart @@ -1,13 +1,18 @@ +enum NoteType { text, image } + class SelfNote { String id; String? title; String content; + NoteType noteType; + Map? json; SelfNote({ required this.id, this.title, required this.content, + required this.noteType, this.json, }); @@ -16,6 +21,7 @@ class SelfNote { id: json['id'], title: json['title'], content: json['content'], + noteType: json['note_type'] == 'image' ? NoteType.image : NoteType.text, json: json, ); } @@ -24,5 +30,6 @@ class SelfNote { 'id': id, 'title': title, 'content': content, + 'note_type': noteType == NoteType.image ? 'image' : 'text', }; } diff --git a/refilc/lib/theme/theme.dart b/refilc/lib/theme/theme.dart index 8b4594b..e1a9215 100644 --- a/refilc/lib/theme/theme.dart +++ b/refilc/lib/theme/theme.dart @@ -1,7 +1,6 @@ import 'package:refilc/models/settings.dart'; import 'package:refilc/theme/colors/accent.dart'; import 'package:refilc/theme/colors/colors.dart'; -import 'package:refilc/theme/colors/new_colors.dart'; import 'package:refilc/theme/colors/utils.dart'; import 'package:refilc/theme/observer.dart'; import 'package:flutter/material.dart'; diff --git a/refilc/lib/ui/widgets/lesson/lesson_tile.dart b/refilc/lib/ui/widgets/lesson/lesson_tile.dart index de1cde1..f2041da 100644 --- a/refilc/lib/ui/widgets/lesson/lesson_tile.dart +++ b/refilc/lib/ui/widgets/lesson/lesson_tile.dart @@ -1,5 +1,4 @@ import 'package:refilc/models/settings.dart'; -import 'package:refilc/theme/colors/new_colors.dart'; import 'package:refilc_kreta_api/providers/exam_provider.dart'; import 'package:refilc_kreta_api/providers/homework_provider.dart'; import 'package:refilc/theme/colors/colors.dart'; diff --git a/refilc/lib/utils/reverse_search.dart b/refilc/lib/utils/reverse_search.dart index f2b3301..3dcae9a 100644 --- a/refilc/lib/utils/reverse_search.dart +++ b/refilc/lib/utils/reverse_search.dart @@ -1,8 +1,6 @@ import 'dart:developer'; -import 'package:googleapis/privateca/v1.dart'; import 'package:refilc_kreta_api/models/absence.dart'; -import 'package:refilc_kreta_api/models/category.dart'; import 'package:refilc_kreta_api/models/lesson.dart'; import 'package:refilc_kreta_api/models/subject.dart'; import 'package:refilc_kreta_api/models/week.dart'; 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 8b4f391..70f7787 100644 --- a/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart +++ b/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart @@ -1,4 +1,3 @@ -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_svg/svg.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; @@ -7,22 +6,11 @@ import 'package:refilc/api/providers/user_provider.dart'; import 'package:refilc/helpers/subject.dart'; import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/utils.dart'; -import 'package:refilc/utils/reverse_search.dart'; import 'package:refilc_kreta_api/models/lesson.dart'; import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart'; -import 'package:refilc_mobile_ui/common/custom_snack_bar.dart'; -import 'package:refilc_mobile_ui/common/panel/panel_button.dart'; import 'package:refilc_mobile_ui/common/round_border_icon.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 'package:refilc_mobile_ui/pages/grades/grades_page.dart'; -import 'package:refilc_plus/models/premium_scopes.dart'; -import 'package:refilc_plus/providers/plus_provider.dart'; -import 'package:refilc_plus/ui/mobile/plus/upsell.dart'; -import 'lesson_view.i18n.dart'; class LessonViewable extends StatefulWidget { const LessonViewable( diff --git a/refilc_mobile_ui/lib/pages/grades/grades_page.dart b/refilc_mobile_ui/lib/pages/grades/grades_page.dart index 3d18708..6f8d084 100644 --- a/refilc_mobile_ui/lib/pages/grades/grades_page.dart +++ b/refilc_mobile_ui/lib/pages/grades/grades_page.dart @@ -33,7 +33,6 @@ import 'package:refilc_mobile_ui/pages/grades/fail_warning.dart'; import 'package:refilc_mobile_ui/pages/grades/grades_count.dart'; import 'package:refilc_mobile_ui/pages/grades/graph.dart'; import 'package:refilc_mobile_ui/pages/grades/grade_subject_view.dart'; -import 'package:refilc_mobile_ui/pages/timetable/timetable_page.dart'; import 'package:refilc_mobile_ui/screens/navigation/navigation_route_handler.dart'; import 'package:refilc_mobile_ui/screens/navigation/navigation_screen.dart'; import 'package:refilc_plus/models/premium_scopes.dart'; @@ -640,27 +639,6 @@ class GradesPageState extends State { } void showQuickSettings(BuildContext context) { - // _sheetController = _scaffoldKey.currentState?.showBottomSheet( - // (context) => RoundedBottomSheet( - // borderRadius: 14.0, - // child: BottomSheetMenu(items: [ - // SwitchListTile( - // title: Text('show_lesson_num'.i18n), - // value: - // Provider.of(context).qTimetableLessonNum, - // onChanged: (v) { - // Provider.of(context, listen: false) - // .update(qTimetableLessonNum: v); - // }) - // ])), - // backgroundColor: const Color(0x00000000), - // elevation: 12.0, - // ); - - // _sheetController!.closed.then((value) { - // // Show fab and grades - // if (mounted) {} - // }); showRoundedModalBottomSheet( context, backgroundColor: Theme.of(context).scaffoldBackgroundColor, diff --git a/refilc_mobile_ui/lib/pages/grades/graph.dart b/refilc_mobile_ui/lib/pages/grades/graph.dart index 8f22f65..ed8e2e8 100644 --- a/refilc_mobile_ui/lib/pages/grades/graph.dart +++ b/refilc_mobile_ui/lib/pages/grades/graph.dart @@ -161,6 +161,11 @@ class GradeGraphState extends State { final x = halfYearGrade.writeDate.month + (halfYearGrade.writeDate.day / 31) + ((halfYearGrade.writeDate.year - data.last.writeDate.year) * 12); + + List dataBeforeMidYr = data + .where((e) => e.writeDate.isBefore(halfYearGrade.writeDate)) + .toList(); + if (x <= maxX) { extraLinesV.add( VerticalLine( @@ -170,7 +175,9 @@ class GradeGraphState extends State { label: VerticalLineLabel( labelResolver: (_) => " ${"mid".i18n} ​", // <- zwsp for padding show: true, - alignment: Alignment.topLeft, + alignment: dataBeforeMidYr.length < 2 + ? Alignment.topRight + : Alignment.topLeft, style: TextStyle( backgroundColor: Theme.of(context).colorScheme.background, color: AppColors.of(context).text, @@ -218,11 +225,12 @@ class GradeGraphState extends State { horizontalLines: extraLinesH), lineBarsData: [ LineChartBarData( - preventCurveOverShooting: true, + preventCurveOverShooting: false, spots: subjectSpots, isCurved: true, colors: averageColors.reversed.toList(), - barWidth: 8, + barWidth: 6, + curveSmoothness: 0.2, isStrokeCapRound: true, dotData: FlDotData(show: false), belowBarData: BarAreaData( @@ -339,11 +347,13 @@ class GradeGraphState extends State { ghostData.isNotEmpty ? ghostData : data; tData.sort((a, b) => a.writeDate.compareTo(b.writeDate)); - return tData.first.writeDate - .add(const Duration(days: 120)) - .isBefore(tData.last.writeDate) - ? 2.0 - : 1.0; + return ghostData.isNotEmpty + ? 3.0 + : tData.first.writeDate + .add(const Duration(days: 120)) + .isBefore(tData.last.writeDate) + ? 2.0 + : 2.5; }(), checkToShowTitle: (double minValue, double maxValue, diff --git a/refilc_mobile_ui/lib/pages/home/live_card/live_card.dart b/refilc_mobile_ui/lib/pages/home/live_card/live_card.dart index 1d36bd2..922070a 100644 --- a/refilc_mobile_ui/lib/pages/home/live_card/live_card.dart +++ b/refilc_mobile_ui/lib/pages/home/live_card/live_card.dart @@ -6,17 +6,9 @@ import 'package:refilc/helpers/subject.dart'; import 'package:refilc/models/settings.dart'; import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/ui/widgets/lesson/lesson_tile.dart'; -import 'package:refilc_kreta_api/models/category.dart'; -import 'package:refilc_kreta_api/models/lesson.dart'; -import 'package:refilc_kreta_api/models/subject.dart'; -import 'package:refilc_kreta_api/models/teacher.dart'; import 'package:refilc_mobile_ui/common/panel/panel.dart'; import 'package:refilc_mobile_ui/common/progress_bar.dart'; import 'package:refilc_mobile_ui/common/round_border_icon.dart'; -// import 'package:refilc_kreta_api/models/category.dart'; -// import 'package:refilc_kreta_api/models/lesson.dart'; -// import 'package:refilc_kreta_api/models/subject.dart'; -// import 'package:refilc_kreta_api/models/teacher.dart'; import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart'; import 'package:refilc_mobile_ui/pages/home/live_card/heads_up_countdown.dart'; import 'package:refilc_mobile_ui/pages/home/live_card/segmented_countdown.dart'; @@ -94,7 +86,7 @@ class LiveCardStateA extends State { name: 'name', );*/ - liveCard.nextLesson = liveCard.currentLesson; + // liveCard.nextLesson = liveCard.currentLesson; // final dt = DateTime(2024, 3, 22, 17, 12, 1, 1, 1); diff --git a/refilc_mobile_ui/lib/pages/notes/notes_page.dart b/refilc_mobile_ui/lib/pages/notes/notes_page.dart index 61ff85c..b9550b0 100644 --- a/refilc_mobile_ui/lib/pages/notes/notes_page.dart +++ b/refilc_mobile_ui/lib/pages/notes/notes_page.dart @@ -1,5 +1,6 @@ // ignore_for_file: no_leading_underscores_for_local_identifiers, use_build_context_synchronously +import 'dart:convert'; import 'dart:math'; import 'package:flutter/cupertino.dart'; @@ -7,6 +8,8 @@ import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:refilc/api/providers/database_provider.dart'; import 'package:refilc/api/providers/self_note_provider.dart'; import 'package:refilc/api/providers/update_provider.dart'; +import 'package:refilc/models/self_note.dart'; +import 'package:refilc/models/settings.dart'; import 'package:refilc/utils/format.dart'; import 'package:refilc_kreta_api/models/absence.dart'; import 'package:refilc_kreta_api/models/homework.dart'; @@ -14,6 +17,8 @@ import 'package:refilc_kreta_api/models/subject.dart'; import 'package:refilc/api/providers/user_provider.dart'; import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc_kreta_api/providers/homework_provider.dart'; +import 'package:refilc_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu.dart'; +import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart'; import 'package:refilc_mobile_ui/common/empty.dart'; import 'package:refilc_mobile_ui/common/panel/panel.dart'; import 'package:refilc_mobile_ui/common/profile_image/profile_button.dart'; @@ -23,6 +28,7 @@ import 'package:refilc_mobile_ui/common/widgets/tick_tile.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:refilc_mobile_ui/pages/notes/submenu/add_note_screen.dart'; +import 'package:refilc_mobile_ui/pages/notes/submenu/create_image_note.dart'; import 'package:refilc_mobile_ui/pages/notes/submenu/note_view_screen.dart'; import 'package:refilc_mobile_ui/pages/notes/submenu/self_note_tile.dart'; import 'package:refilc_plus/models/premium_scopes.dart'; @@ -114,13 +120,37 @@ class NotesPageState extends State with TickerProviderStateMixin { if (selfNoteProvider.notes.isNotEmpty) { selfNoteTiles.addAll(selfNoteProvider.notes.reversed.map( - (e) => SelfNoteTile( - title: e.title ?? e.content.split(' ')[0], - content: e.content, - onTap: () => Navigator.of(context, rootNavigator: true).push( - CupertinoPageRoute( - builder: (context) => NoteViewScreen(note: e))), - ), + (e) => e.noteType == NoteType.text + ? SelfNoteTile( + title: e.title ?? e.content.split(' ')[0], + content: e.content, + onTap: () => Navigator.of(context, rootNavigator: true).push( + CupertinoPageRoute( + builder: (context) => NoteViewScreen(note: e))), + ) + : Container( + height: MediaQuery.of(context).size.width / 2.42, + width: MediaQuery.of(context).size.width / 2.42, + decoration: BoxDecoration( + boxShadow: [ + if (Provider.of(context, listen: false) + .shadowEffect) + BoxShadow( + offset: const Offset(0, 21), + blurRadius: 23.0, + color: Theme.of(context).shadowColor, + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(16.0), + child: Image.memory( + const Base64Decoder().convert(e.content), + fit: BoxFit.cover, + gaplessPlayback: true, + ), + ), + ), )); } @@ -235,9 +265,7 @@ class NotesPageState extends State with TickerProviderStateMixin { feature: PremiumFeature.selfNotes); } - Navigator.of(context, rootNavigator: true).push( - CupertinoPageRoute( - builder: (context) => const AddNoteScreen())); + showCreationModal(context); }, child: Icon( FeatherIcons.plus, @@ -312,4 +340,77 @@ class NotesPageState extends State with TickerProviderStateMixin { ), ); } + + void showCreationModal(BuildContext context) { + // _sheetController = _scaffoldKey.currentState?.showBottomSheet( + // (context) => RoundedBottomSheet( + // borderRadius: 14.0, + // child: BottomSheetMenu(items: [ + // SwitchListTile( + // title: Text('show_lesson_num'.i18n), + // value: + // Provider.of(context).qTimetableLessonNum, + // onChanged: (v) { + // Provider.of(context, listen: false) + // .update(qTimetableLessonNum: v); + // }) + // ])), + // backgroundColor: const Color(0x00000000), + // elevation: 12.0, + // ); + + // _sheetController!.closed.then((value) { + // // Show fab and grades + // if (mounted) {} + // }); + showRoundedModalBottomSheet( + context, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + child: BottomSheetMenu(items: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.0), + color: Theme.of(context).colorScheme.background), + child: ListTile( + title: Row( + children: [ + const Icon(Icons.sticky_note_2_outlined), + const SizedBox( + width: 10.0, + ), + Text('new_note'.i18n), + ], + ), + onTap: () => Navigator.of(context, rootNavigator: true).push( + CupertinoPageRoute( + builder: (context) => const AddNoteScreen())), + ), + ), + const SizedBox( + height: 10.0, + ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.0), + color: Theme.of(context).colorScheme.background), + child: ListTile( + title: Row( + children: [ + const Icon(Icons.photo_library_outlined), + const SizedBox( + width: 10.0, + ), + Text('new_image'.i18n), + ], + ), + onTap: () { + showDialog( + context: context, + builder: (context) => ImageNoteEditor(user.user!)); + }, + ), + ), + ]), + ); + } } diff --git a/refilc_mobile_ui/lib/pages/notes/notes_page.i18n.dart b/refilc_mobile_ui/lib/pages/notes/notes_page.i18n.dart index 7924e35..f452a9e 100644 --- a/refilc_mobile_ui/lib/pages/notes/notes_page.i18n.dart +++ b/refilc_mobile_ui/lib/pages/notes/notes_page.i18n.dart @@ -13,6 +13,7 @@ extension ScreensLocalization on String { "hint": "Note content...", "hint_t": "Note title...", "your_notes": "Your Notes", + "new_image": "New Image", }, "hu_hu": { "notes": "Füzet", @@ -24,6 +25,7 @@ extension ScreensLocalization on String { "hint": "Jegyzet tartalma...", "hint_t": "Jegyzet címe...", "your_notes": "Jegyzeteid", + "new_image": "Új kép", }, "de_de": { "notes": "Broschüre", @@ -35,6 +37,7 @@ extension ScreensLocalization on String { "hint": "Inhalt beachten...", "hint_t": "Titel notieren...", "your_notes": "Deine Noten", + "new_image": "Neues Bild", }, }; diff --git a/refilc_mobile_ui/lib/pages/notes/submenu/add_note_screen.dart b/refilc_mobile_ui/lib/pages/notes/submenu/add_note_screen.dart index 4cbe5cf..30c9bb3 100644 --- a/refilc_mobile_ui/lib/pages/notes/submenu/add_note_screen.dart +++ b/refilc_mobile_ui/lib/pages/notes/submenu/add_note_screen.dart @@ -153,7 +153,8 @@ class AddNoteScreenState extends State { 'title': _titleController.text.replaceAll(' ', '') == '' ? null : _titleController.text, - 'content': _contentController.text + 'content': _contentController.text, + 'note_type': 'text', })); } else { var i = @@ -165,6 +166,7 @@ class AddNoteScreenState extends State { ? null : _titleController.text, 'content': _contentController.text, + 'note_type': 'text', }); } diff --git a/refilc_mobile_ui/lib/pages/notes/submenu/create_image_note.dart b/refilc_mobile_ui/lib/pages/notes/submenu/create_image_note.dart new file mode 100644 index 0000000..c81faf7 --- /dev/null +++ b/refilc_mobile_ui/lib/pages/notes/submenu/create_image_note.dart @@ -0,0 +1,214 @@ +// ignore_for_file: use_build_context_synchronously + +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:image_crop/image_crop.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:provider/provider.dart'; +import 'package:refilc/api/providers/database_provider.dart'; +import 'package:refilc/api/providers/self_note_provider.dart'; +import 'package:refilc/models/self_note.dart'; +import 'package:refilc/models/user.dart'; +import 'package:uuid/uuid.dart'; +import 'notes_screen.i18n.dart'; + +// ignore: must_be_immutable +class ImageNoteEditor extends StatefulWidget { + late User u; + + ImageNoteEditor(this.u, {super.key}); + + @override + State createState() => _ImageNoteEditorState(); +} + +class _ImageNoteEditorState extends State { + final cropKey = GlobalKey(); + File? _file; + File? _sample; + File? _lastCropped; + + File? image; + Future pickImage() async { + try { + final image = await ImagePicker().pickImage(source: ImageSource.gallery); + if (image == null) return; + File imageFile = File(image.path); + + final sample = await ImageCrop.sampleImage( + file: imageFile, + preferredSize: context.size!.longestSide.ceil(), + ); + + _sample?.delete(); + _file?.delete(); + + setState(() { + _sample = sample; + _file = imageFile; + }); + } on PlatformException catch (e) { + log('Failed to pick image: $e'); + } + } + + Widget cropImageWidget() { + return SizedBox( + height: 300, + child: Crop.file( + _sample!, + key: cropKey, + aspectRatio: 1.0, + ), + ); + } + + Widget openImageWidget() { + return InkWell( + customBorder: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14.0), + ), + onTap: () => pickImage(), + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(14.0), + ), + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 32.0, horizontal: 8.0), + child: Column( + children: [ + Text( + "click_here".i18n, + style: const TextStyle( + fontSize: 22.0, + fontWeight: FontWeight.w600, + ), + ), + Text( + "select_image".i18n, + style: const TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.w500, + ), + ) + ], + ), + ), + ); + } + + Future _cropImage() async { + final scale = cropKey.currentState!.scale; + final area = cropKey.currentState!.area; + if (area == null || _file == null) { + return; + } + + final sample = await ImageCrop.sampleImage( + file: _file!, + preferredSize: (2000 / scale).round(), + ); + + final file = await ImageCrop.cropImage( + file: sample, + area: area, + ); + + sample.delete(); + + _lastCropped?.delete(); + _lastCropped = file; + + List imageBytes = await _lastCropped!.readAsBytes(); + String base64Image = base64Encode(imageBytes); + + List selfNotes = + await Provider.of(context, listen: false) + .userQuery + .getSelfNotes(userId: widget.u.id); + + selfNotes.add(SelfNote.fromJson({ + 'id': const Uuid().v4(), + 'content': base64Image, + 'note_type': 'image' + })); + + await Provider.of(context, listen: false) + .userStore + .storeSelfNotes(selfNotes, userId: widget.u.id); + + Provider.of(context, listen: false).restore(); + + debugPrint('$file'); + } + + @override + void dispose() { + super.dispose(); + _file?.delete(); + _sample?.delete(); + _lastCropped?.delete(); + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(14.0))), + contentPadding: const EdgeInsets.only(top: 10.0), + title: Text("new_image".i18n), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: + const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), + child: _sample == null ? openImageWidget() : cropImageWidget(), + ), + // if (widget.u.picture != "") + // TextButton( + // child: Text( + // "remove_profile_picture".i18n, + // style: const TextStyle( + // fontWeight: FontWeight.w500, color: Colors.red), + // ), + // onPressed: () { + // widget.u.picture = ""; + // Provider.of(context, listen: false) + // .store + // .storeUser(widget.u); + // Provider.of(context, listen: false).refresh(); + // Navigator.of(context).pop(true); + // }, + // ), + ], + ), + actions: [ + TextButton( + child: Text( + "cancel".i18n, + style: const TextStyle(fontWeight: FontWeight.w500), + ), + onPressed: () { + Navigator.of(context).maybePop(); + }, + ), + TextButton( + child: Text( + "next".i18n, + style: const TextStyle(fontWeight: FontWeight.w500), + ), + onPressed: () async { + await _cropImage(); + Navigator.of(context).pop(true); + }, + ), + ], + ); + } +} diff --git a/refilc_mobile_ui/lib/pages/notes/submenu/notes_screen.i18n.dart b/refilc_mobile_ui/lib/pages/notes/submenu/notes_screen.i18n.dart index 02c848b..bbe6033 100644 --- a/refilc_mobile_ui/lib/pages/notes/submenu/notes_screen.i18n.dart +++ b/refilc_mobile_ui/lib/pages/notes/submenu/notes_screen.i18n.dart @@ -13,6 +13,11 @@ extension SettingsLocalization on String { "hint": "Note content...", "hint_t": "Note title...", "your_notes": "Your Notes", + "next": "Next", + "cancel": "Cancel", + "click_here": "Click here", + "select_image": "to select an image", + "new_image": "New Image", }, "hu_hu": { "notes": "Füzet", @@ -24,6 +29,11 @@ extension SettingsLocalization on String { "hint": "Jegyzet tartalma...", "hint_t": "Jegyzet címe...", "your_notes": "Jegyzeteid", + "next": "Tovább", + "cancel": "Mégse", + "click_here": "Kattints ide", + "select_image": "kép kiválasztásához", + "new_image": "Új kép", }, "de_de": { "notes": "Broschüre", @@ -35,6 +45,11 @@ extension SettingsLocalization on String { "hint": "Inhalt beachten...", "hint_t": "Titel notieren...", "your_notes": "Deine Noten", + "next": "Weiter", + "cancel": "Abbrechen", + "click_here": "Klicken Sie hier", + "select_image": "um ein Bild auszuwählen", + "new_image": "Neues Bild", }, }; diff --git a/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart b/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart index f31fbb4..e77376b 100644 --- a/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart +++ b/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart @@ -14,7 +14,6 @@ import 'package:refilc/api/providers/user_provider.dart'; import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc_kreta_api/models/lesson.dart'; import 'package:refilc_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu.dart'; -import 'package:refilc_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu_item.dart'; import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart'; import 'package:refilc_mobile_ui/common/dot.dart'; import 'package:refilc_mobile_ui/common/empty.dart'; @@ -73,8 +72,6 @@ class TimetablePageState extends State with TickerProviderStateMixin, WidgetsBindingObserver { final GlobalKey _scaffoldKey = GlobalKey(); - PersistentBottomSheetController? _sheetController; - late UserProvider user; late TimetableProvider timetableProvider; late UpdateProvider updateProvider;