diff --git a/refilc/lib/models/settings.dart b/refilc/lib/models/settings.dart index 9cea67f..72d23f1 100644 --- a/refilc/lib/models/settings.dart +++ b/refilc/lib/models/settings.dart @@ -485,9 +485,9 @@ class SettingsProvider extends ChangeNotifier { navShadow: true, newColors: true, uwuMode: false, - qTimetableLessonNum: false, - qTimetableSubTiles: false, - qSubjectsSubTiles: false, + qTimetableLessonNum: true, + qTimetableSubTiles: true, + qSubjectsSubTiles: true, ); } @@ -694,7 +694,7 @@ class SettingsProvider extends ChangeNotifier { if (bellDelay != null && bellDelay != _bellDelay) _bellDelay = bellDelay; if (bellDelayEnabled != null && bellDelayEnabled != _bellDelayEnabled) { _bellDelayEnabled = bellDelayEnabled; - if(Platform.isIOS){ + if (Platform.isIOS) { LiveCardProvider.hasActivitySettingsChanged = true; } } diff --git a/refilc/lib/theme/colors/accent.dart b/refilc/lib/theme/colors/accent.dart index 152046a..df27bc0 100644 --- a/refilc/lib/theme/colors/accent.dart +++ b/refilc/lib/theme/colors/accent.dart @@ -31,3 +31,66 @@ Map accentColorMap = { AccentColor.adaptive: const Color(0xFF3D7BF4), AccentColor.custom: const Color(0xFF3D7BF4), }; + +// new v5 things +Map lightPrimary = { + AccentColor.filc: const Color(0xFF050B15), +}; +Map lightSecondary = { + AccentColor.filc: const Color(0xFF3F444F), +}; +Map lightTeritary = { + AccentColor.filc: const Color(0xFF1C469A), +}; +Map lightIcon = { + AccentColor.filc: const Color(0xFF0A2456), +}; +Map lightAccent = { + AccentColor.filc: const Color(0xFF487DE6), +}; +Map lightBgDarkened = { + AccentColor.filc: const Color(0xFFB9C8E5), +}; +Map lightBtnSecStrk = { + AccentColor.filc: const Color(0xFFCEDBF5), +}; +Map lightBg = { + AccentColor.filc: const Color(0xFFDAE4F7), +}; +Map lightCard = { + AccentColor.filc: const Color(0xFFEDF3FF), +}; +Map lightBtnSec = { + AccentColor.filc: const Color(0xFFFBFCFF), +}; + +Map darkPrimary = { + AccentColor.filc: const Color(0xFFEBF1FD), +}; +Map darkSecondary = { + AccentColor.filc: const Color(0xFFCFD8E9), +}; +Map darkTeritary = { + AccentColor.filc: const Color(0xFFAEC8FC), +}; +Map darkIcon = { + AccentColor.filc: const Color(0xFFBAD1FF), +}; +Map darkAccent = { + AccentColor.filc: const Color(0xFF487DE6), +}; +Map darkBgDarkened = { + AccentColor.filc: const Color(0xFF010205), +}; +Map darkBtnSecStrk = { + AccentColor.filc: const Color(0xFF1C2230), +}; +Map darkBg = { + AccentColor.filc: const Color(0xFF070A0E), +}; +Map darkCard = { + AccentColor.filc: const Color(0xFF0F131B), +}; +Map darkBtnSec = { + AccentColor.filc: const Color(0xFF131822), +}; diff --git a/refilc/lib/theme/colors/new_colors.dart b/refilc/lib/theme/colors/new_colors.dart new file mode 100644 index 0000000..aa7f080 --- /dev/null +++ b/refilc/lib/theme/colors/new_colors.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; + +class NewColors extends ThemeExtension { + const NewColors({ + required this.accent, + required this.primary, + required this.secondary, + required this.teritary, + required this.icon, + required this.darkenBg, + required this.btnSecStrk, + required this.background, + required this.card, + required this.btnSec, + }); + + final Color? accent; + final Color? primary; + final Color? secondary; + final Color? teritary; + final Color? icon; + final Color? darkenBg; + final Color? btnSecStrk; + final Color? background; + final Color? card; + final Color? btnSec; + + @override + NewColors copyWith({ + Color? accent, + Color? primary, + Color? secondary, + Color? teritary, + Color? icon, + Color? darkenBg, + Color? btnSecStrk, + Color? background, + Color? card, + Color? btnSec, + }) { + return NewColors( + accent: accent ?? this.accent, + primary: primary ?? this.primary, + secondary: secondary ?? this.secondary, + teritary: teritary ?? this.teritary, + icon: icon ?? this.icon, + darkenBg: darkenBg ?? this.darkenBg, + btnSecStrk: btnSecStrk ?? this.btnSecStrk, + background: background ?? this.background, + card: card ?? this.card, + btnSec: btnSec ?? this.btnSec, + ); + } + + @override + NewColors lerp(NewColors? other, double t) { + if (other is! NewColors) { + return this; + } + return NewColors( + accent: Color.lerp(accent, other.accent, t), + primary: Color.lerp(primary, other.primary, t), + secondary: Color.lerp(secondary, other.secondary, t), + teritary: Color.lerp(teritary, other.teritary, t), + icon: Color.lerp(icon, other.icon, t), + darkenBg: Color.lerp(darkenBg, other.darkenBg, t), + btnSecStrk: Color.lerp(btnSecStrk, other.btnSecStrk, t), + background: Color.lerp(background, other.background, t), + card: Color.lerp(card, other.card, t), + btnSec: Color.lerp(btnSec, other.btnSec, t), + ); + } +} diff --git a/refilc/lib/theme/theme.dart b/refilc/lib/theme/theme.dart index 1acae12..8b4594b 100644 --- a/refilc/lib/theme/theme.dart +++ b/refilc/lib/theme/theme.dart @@ -1,6 +1,7 @@ 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'; @@ -87,6 +88,20 @@ class AppTheme { amount: 0.4); // white mode: same tertiary as secondary return ThemeData( + // extensions: [ + // NewColors( + // accent: lightAccent[accentColor]!, + // primary: lightPrimary[accentColor]!, + // secondary: lightSecondary[accentColor]!, + // teritary: lightTeritary[accentColor]!, + // icon: lightIcon[accentColor]!, + // darkenBg: lightBgDarkened[accentColor]!, + // btnSecStrk: lightBtnSecStrk[accentColor]!, + // background: lightBg[accentColor]!, + // card: lightCard[accentColor]!, + // btnSec: lightBtnSec[accentColor]!, + // ), + // ], brightness: Brightness.light, useMaterial3: true, fontFamily: _defaultFontFamily, @@ -198,6 +213,20 @@ class AppTheme { amount: 0.1); // dark mode: tertiary is way darker than secondary return ThemeData( + // extensions: [ + // NewColors( + // accent: darkAccent[accentColor]!, + // primary: darkPrimary[accentColor]!, + // secondary: darkSecondary[accentColor]!, + // teritary: darkTeritary[accentColor]!, + // icon: darkIcon[accentColor]!, + // darkenBg: darkBgDarkened[accentColor]!, + // btnSecStrk: darkBtnSecStrk[accentColor]!, + // background: darkBg[accentColor]!, + // card: darkCard[accentColor]!, + // btnSec: darkBtnSec[accentColor]!, + // ), + // ], brightness: Brightness.dark, useMaterial3: true, fontFamily: _defaultFontFamily, diff --git a/refilc/lib/ui/widgets/lesson/lesson_tile.dart b/refilc/lib/ui/widgets/lesson/lesson_tile.dart index f2041da..de1cde1 100644 --- a/refilc/lib/ui/widgets/lesson/lesson_tile.dart +++ b/refilc/lib/ui/widgets/lesson/lesson_tile.dart @@ -1,4 +1,5 @@ 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 35e3425..f2b3301 100644 --- a/refilc/lib/utils/reverse_search.dart +++ b/refilc/lib/utils/reverse_search.dart @@ -1,8 +1,12 @@ 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'; +import 'package:refilc_kreta_api/providers/grade_provider.dart'; import 'package:refilc_kreta_api/providers/timetable_provider.dart'; import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; @@ -41,4 +45,23 @@ class ReverseSearch { // difference.inDays is not reliable static bool _sameDate(DateTime a, DateTime b) => (a.year == b.year && a.month == b.month && a.day == b.day); + + static Future getSubjectByLesson( + Lesson lesson, BuildContext context) async { + final gradeProvider = Provider.of(context, listen: false); + + try { + await gradeProvider.fetch(); + } catch (e) { + log("[ERROR] getSubjectByLesson: $e"); + } + + try { + return gradeProvider.grades.map((e) => e.subject).firstWhere( + (s) => s.id == lesson.subject.id, + ); + } catch (e) { + return null; + } + } } diff --git a/refilc_mobile_ui/lib/common/bottom_sheet_menu/rounded_bottom_sheet.dart b/refilc_mobile_ui/lib/common/bottom_sheet_menu/rounded_bottom_sheet.dart index 7bb4977..9a64aa2 100644 --- a/refilc_mobile_ui/lib/common/bottom_sheet_menu/rounded_bottom_sheet.dart +++ b/refilc_mobile_ui/lib/common/bottom_sheet_menu/rounded_bottom_sheet.dart @@ -8,19 +8,21 @@ class RoundedBottomSheet extends StatelessWidget { this.borderRadius = 16.0, this.shrink = true, this.showHandle = true, + this.backgroundColor, }); final Widget? child; final double borderRadius; final bool shrink; final bool showHandle; + final Color? backgroundColor; @override Widget build(BuildContext context) { return AnimatedContainer( duration: const Duration(milliseconds: 500), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, + color: backgroundColor ?? Theme.of(context).colorScheme.background, borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadius), topRight: Radius.circular(borderRadius), @@ -52,6 +54,7 @@ Future showRoundedModalBottomSheet( required Widget child, bool rootNavigator = true, bool showHandle = true, + Color? backgroundColor, }) async { return await showModalBottomSheet( useSafeArea: false, @@ -62,6 +65,7 @@ Future showRoundedModalBottomSheet( useRootNavigator: rootNavigator, isScrollControlled: true, builder: (context) => RoundedBottomSheet( + backgroundColor: backgroundColor, showHandle: showHandle, child: child, ), diff --git a/refilc_mobile_ui/lib/common/widgets/grade/grade_subject_tile.dart b/refilc_mobile_ui/lib/common/widgets/grade/grade_subject_tile.dart index 17e624c..894ac41 100644 --- a/refilc_mobile_ui/lib/common/widgets/grade/grade_subject_tile.dart +++ b/refilc_mobile_ui/lib/common/widgets/grade/grade_subject_tile.dart @@ -9,12 +9,14 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class GradeSubjectTile extends StatelessWidget { - const GradeSubjectTile(this.subject, - {super.key, - this.average = 0.0, - this.groupAverage = 0.0, - this.onTap, - this.averageBefore = 0.0}); + const GradeSubjectTile( + this.subject, { + super.key, + this.average = 0.0, + this.groupAverage = 0.0, + this.onTap, + this.averageBefore = 0.0, + }); final GradeSubject subject; final void Function()? onTap; 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 1cca668..8b4f391 100644 --- a/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart +++ b/refilc_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart @@ -1,13 +1,16 @@ 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'; import 'package:refilc/api/providers/database_provider.dart'; 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'; @@ -15,18 +18,25 @@ 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(this.lesson, - {super.key, this.swapDesc = false, required this.customDesc}); + const LessonViewable( + this.lesson, { + super.key, + this.swapDesc = false, + required this.customDesc, + this.showSubTiles = true, + }); final Lesson lesson; final bool swapDesc; final String customDesc; + final bool showSubTiles; @override State createState() => LessonViewableState(); @@ -51,14 +61,28 @@ class LessonViewableState extends State { Lesson lsn = widget.lesson; lsn.description = widget.customDesc; - final tile = LessonTile(lsn, swapDesc: widget.swapDesc); + final tile = LessonTile( + lsn, + swapDesc: widget.swapDesc, + showSubTiles: widget.showSubTiles, + ); if (lsn.subject.id == '' || tile.lesson.isEmpty) return tile; - return LessonTile( - lsn, - swapDesc: widget.swapDesc, - onTap: () => TimetableLessonPopup.show(context: context, lesson: lsn), + return GestureDetector( + onTap: () => TimetableLessonPopup.show( + context: context, + lesson: lsn, + ), + child: LessonTile( + lsn, + swapDesc: widget.swapDesc, + showSubTiles: widget.showSubTiles, + // onTap: () => TimetableLessonPopup.show( + // context: context, + // lesson: lsn, + // ), + ), ); // return Viewable( @@ -232,9 +256,14 @@ class LessonViewableState extends State { } class TimetableLessonPopup extends StatelessWidget { - const TimetableLessonPopup({super.key, required this.lesson}); + const TimetableLessonPopup({ + super.key, + required this.lesson, + required this.outsideContext, + }); final Lesson lesson; + final BuildContext outsideContext; static void show({ required BuildContext context, @@ -244,6 +273,7 @@ class TimetableLessonPopup extends StatelessWidget { context, child: TimetableLessonPopup( lesson: lesson, + outsideContext: context, ), showHandle: false, ); @@ -272,13 +302,42 @@ class TimetableLessonPopup extends StatelessWidget { ), child: Stack( children: [ - SvgPicture.asset( - "assets/svg/mesh_bg.svg", - // ignore: deprecated_member_use - color: ColorsUtils().fade( - context, Theme.of(context).scaffoldBackgroundColor, - darkenAmount: 0.1, lightenAmount: 0.1), - width: MediaQuery.of(context).size.width, + Stack( + children: [ + SvgPicture.asset( + "assets/svg/mesh_bg.svg", + // ignore: deprecated_member_use + color: ColorsUtils() + .fade(context, Theme.of(context).colorScheme.secondary, + darkenAmount: 0.1, lightenAmount: 0.1) + .withOpacity(0.33), + width: MediaQuery.of(context).size.width, + ), + Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.vertical( + top: Radius.circular(12.0), + ), + gradient: LinearGradient( + colors: [ + Theme.of(context).scaffoldBackgroundColor, + Theme.of(context) + .scaffoldBackgroundColor + .withOpacity(0.1), + Theme.of(context) + .scaffoldBackgroundColor + .withOpacity(0.1), + Theme.of(context).scaffoldBackgroundColor, + ], + stops: const [0.1, 0.5, 0.7, 1.0], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + width: MediaQuery.of(context).size.width, + height: 175.0, + ), + ], ), SizedBox( width: MediaQuery.of(context).size.width, @@ -291,9 +350,11 @@ class TimetableLessonPopup extends StatelessWidget { width: 40, height: 4, decoration: BoxDecoration( - color: ColorsUtils().fade( - context, Theme.of(context).scaffoldBackgroundColor, - darkenAmount: 0.2, lightenAmount: 0.2), + color: ColorsUtils() + .fade( + context, Theme.of(context).colorScheme.secondary, + darkenAmount: 0.1, lightenAmount: 0.1) + .withOpacity(0.33), borderRadius: BorderRadius.circular( 2.0, ), @@ -302,10 +363,31 @@ class TimetableLessonPopup extends StatelessWidget { const SizedBox( height: 38.0, ), - RoundBorderIcon( - icon: Icon( - SubjectIcon.resolveVariant( - context: context, subject: lesson.subject), + Container( + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + borderRadius: BorderRadius.circular(50.0), + ), + child: RoundBorderIcon( + color: ColorsUtils() + .darken( + Theme.of(context).colorScheme.secondary, + amount: 0.1, + ) + .withOpacity(0.9), + width: 1.5, + padding: 10.0, + icon: Icon( + SubjectIcon.resolveVariant( + context: context, subject: lesson.subject), + size: 32.0, + color: ColorsUtils() + .darken( + Theme.of(context).colorScheme.secondary, + amount: 0.1, + ) + .withOpacity(0.8), + ), ), ), const SizedBox( @@ -315,9 +397,11 @@ class TimetableLessonPopup extends StatelessWidget { width: double.infinity, decoration: BoxDecoration( color: Theme.of(context).colorScheme.background, - borderRadius: const BorderRadius.vertical( - top: Radius.circular(12.0), - bottom: Radius.circular(6.0), + borderRadius: BorderRadius.vertical( + top: const Radius.circular(12.0), + bottom: (lesson.description.replaceAll(' ', '') != '') + ? const Radius.circular(6.0) + : const Radius.circular(12.0), ), ), padding: const EdgeInsets.all(14.0), @@ -325,7 +409,7 @@ class TimetableLessonPopup extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '6:09 - 4:20', + '${DateFormat('H:mm').format(lesson.start)} - ${DateFormat('H:mm').format(lesson.end)}', style: TextStyle( color: AppColors.of(context).text.withOpacity(0.85), fontSize: 14.0, @@ -357,64 +441,79 @@ class TimetableLessonPopup extends StatelessWidget { ], ), ), - const SizedBox( - height: 6.0, - ), - Container( - width: double.infinity, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - borderRadius: const BorderRadius.vertical( - top: Radius.circular(6.0), - bottom: Radius.circular(12.0), - ), + if (lesson.description.replaceAll(' ', '') != '') + const SizedBox( + height: 6.0, ), - padding: const EdgeInsets.all(14.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - lesson.description, - style: TextStyle( - color: AppColors.of(context).text.withOpacity(0.9), - fontSize: 14.0, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - const SizedBox( - height: 24.0, - ), - GestureDetector( - onTap: () { - Navigator.of(context, rootNavigator: true) - .pushReplacementNamed('/'); - }, - child: Container( + if (lesson.description.replaceAll(' ', '') != '') + Container( width: double.infinity, decoration: BoxDecoration( color: Theme.of(context).colorScheme.background, - borderRadius: BorderRadius.circular(12.0), + borderRadius: const BorderRadius.vertical( + top: Radius.circular(6.0), + bottom: Radius.circular(12.0), + ), ), - padding: const EdgeInsets.all(16.0), + padding: const EdgeInsets.all(14.0), child: Column( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'view_subject'.i18n, + lesson.description, style: TextStyle( color: AppColors.of(context).text.withOpacity(0.9), - fontSize: 18.0, - fontWeight: FontWeight.w500, + fontSize: 14.0, + fontWeight: FontWeight.w600, ), ), ], ), ), - ), + // const SizedBox( + // height: 24.0, + // ), + // GestureDetector( + // onTap: () async { + // ReverseSearch.getSubjectByLesson(lesson, context) + // .then((subject) { + // if (subject != null) { + // GradesPage.jump(outsideContext, subject: subject); + // } else { + // ScaffoldMessenger.of(context) + // .showSnackBar(CustomSnackBar( + // content: Text("Cannot find subject".i18n, + // style: const TextStyle(color: Colors.white)), + // backgroundColor: AppColors.of(context).red, + // context: context, + // )); + // } + // }); + // }, + // child: Container( + // width: double.infinity, + // decoration: BoxDecoration( + // color: Theme.of(context).colorScheme.background, + // borderRadius: BorderRadius.circular(12.0), + // ), + // padding: const EdgeInsets.all(16.0), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // Text( + // 'view_subject'.i18n, + // style: TextStyle( + // color: + // AppColors.of(context).text.withOpacity(0.9), + // fontSize: 18.0, + // fontWeight: FontWeight.w500, + // ), + // ), + // ], + // ), + // ), + // ), ], ), ), diff --git a/refilc_mobile_ui/lib/pages/grades/grades_page.dart b/refilc_mobile_ui/lib/pages/grades/grades_page.dart index 88f1030..3d18708 100644 --- a/refilc_mobile_ui/lib/pages/grades/grades_page.dart +++ b/refilc_mobile_ui/lib/pages/grades/grades_page.dart @@ -19,6 +19,7 @@ import 'package:refilc_kreta_api/models/subject.dart'; import 'package:refilc_kreta_api/models/group_average.dart'; import 'package:refilc_kreta_api/providers/homework_provider.dart'; import 'package:refilc_mobile_ui/common/average_display.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'; @@ -32,6 +33,9 @@ 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'; import 'package:refilc_plus/providers/plus_provider.dart'; import 'package:flutter/material.dart'; @@ -48,6 +52,19 @@ import 'grades_page.i18n.dart'; class GradesPage extends StatefulWidget { const GradesPage({super.key}); + static void jump(BuildContext context, {GradeSubject? subject}) { + // Go to timetable page with arguments + NavigationScreen.of(context) + ?.customRoute(navigationPageRoute((context) => const GradesPage())); + + NavigationScreen.of(context)?.setPage("grades"); + + // Show initial Lesson + if (subject != null) { + GradeSubjectView(subject, groupAverage: 0.0).push(context, root: true); + } + } + @override GradesPageState createState() => GradesPageState(); } @@ -147,7 +164,8 @@ class GradesPageState extends State { Exam? nearestExam = allExams.firstWhereOrNull((e) => e.subject.id == subject.id && e.writeDate.isAfter(DateTime.now())); - bool hasUnder = hasHomework || nearestExam != null; + bool hasUnder = (hasHomework || nearestExam != null) && + Provider.of(context).qSubjectsSubTiles; return Padding( padding: i > 1 ? const EdgeInsets.only(top: 9.0) : EdgeInsets.zero, @@ -201,7 +219,8 @@ class GradesPageState extends State { const SizedBox( height: 6.0, ), - if (hasHomework) + if (hasHomework && + Provider.of(context).qSubjectsSubTiles) Container( decoration: BoxDecoration( boxShadow: [ @@ -249,7 +268,8 @@ class GradesPageState extends State { ), ), ), - if (nearestExam != null) + if (nearestExam != null && + Provider.of(context).qSubjectsSubTiles) Container( decoration: BoxDecoration( boxShadow: [ @@ -519,19 +539,10 @@ class GradesPageState extends State { child: IconButton( splashRadius: 24.0, onPressed: () { - if (!Provider.of(context, listen: false) - .hasScope(PremiumScopes.totalGradeCalculator)) { - PlusLockedFeaturePopup.show( - context: context, - feature: PremiumFeature.gradeCalculation); - return; - } - - // SoonAlert.show(context: context); - gradeCalcTotal(context); + showQuickSettings(context); }, icon: Icon( - FeatherIcons.plus, + FeatherIcons.moreHorizontal, color: AppColors.of(context).text, ), ), @@ -627,4 +638,88 @@ 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, + child: BottomSheetMenu(items: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.0), + color: Theme.of(context).colorScheme.background), + child: ListTile( + title: Row( + children: [ + const Icon(FeatherIcons.plusCircle), + const SizedBox( + width: 10.0, + ), + Text('grade_calc'.i18n), + ], + ), + onTap: () { + if (!Provider.of(context, listen: false) + .hasScope(PremiumScopes.totalGradeCalculator)) { + PlusLockedFeaturePopup.show( + context: context, feature: PremiumFeature.gradeCalculation); + return; + } + + // SoonAlert.show(context: context); + gradeCalcTotal(context); + }, + ), + ), + const SizedBox( + height: 10.0, + ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.0), + color: Theme.of(context).colorScheme.background), + child: SwitchListTile( + title: Row( + children: [ + const Icon(Icons.edit_document), + const SizedBox( + width: 10.0, + ), + Text('show_exams_homework'.i18n), + ], + ), + value: Provider.of(context, listen: false) + .qSubjectsSubTiles, + onChanged: (v) { + Provider.of(context, listen: false) + .update(qSubjectsSubTiles: v); + + Navigator.of(context, rootNavigator: true).pop(); + }, + ), + ), + ]), + ); + } } diff --git a/refilc_mobile_ui/lib/pages/grades/grades_page.i18n.dart b/refilc_mobile_ui/lib/pages/grades/grades_page.i18n.dart index 1985e34..59eee56 100644 --- a/refilc_mobile_ui/lib/pages/grades/grades_page.i18n.dart +++ b/refilc_mobile_ui/lib/pages/grades/grades_page.i18n.dart @@ -27,6 +27,8 @@ extension Localization on String { "exams": "Exams", "timetable": "Timetable", "grades": "Grades", + "show_exams_homework": "Exams and Homework", + "grade_calc": "Grade Calculator", }, "hu_hu": { "Grades": "Tantárgyak", @@ -51,6 +53,8 @@ extension Localization on String { "exams": "Számonkérések", "timetable": "Órarend", "grades": "Jegyek", + "show_exams_homework": "Dolgozatok és házik", + "grade_calc": "Jegy kalkulátor", }, "de_de": { "Grades": "Fächer", @@ -75,6 +79,8 @@ extension Localization on String { "exams": "Prüfungen", "timetable": "Stundenplan", "grades": "Noten", + "show_exams_homework": "Referate und Hausaufgaben", + "grade_calc": "Noten-Rechner", }, }; diff --git a/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart b/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart index da4976b..f31fbb4 100644 --- a/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart +++ b/refilc_mobile_ui/lib/pages/timetable/timetable_page.dart @@ -1,5 +1,6 @@ import 'dart:math'; import 'package:animations/animations.dart'; +import 'package:flutter/widgets.dart'; import 'package:i18n_extension/i18n_extension.dart'; import 'package:refilc/api/providers/database_provider.dart'; import 'package:refilc/api/providers/update_provider.dart'; @@ -14,6 +15,7 @@ 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'; import 'package:refilc_mobile_ui/common/profile_image/profile_button.dart'; @@ -69,6 +71,10 @@ class TimetablePage extends StatefulWidget { class TimetablePageState extends State with TickerProviderStateMixin, WidgetsBindingObserver { + final GlobalKey _scaffoldKey = GlobalKey(); + + PersistentBottomSheetController? _sheetController; + late UserProvider user; late TimetableProvider timetableProvider; late UpdateProvider updateProvider; @@ -215,6 +221,7 @@ class TimetablePageState extends State firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; return Scaffold( + key: _scaffoldKey, body: Padding( padding: const EdgeInsets.only(top: 9.0), child: RefreshIndicator( @@ -235,50 +242,50 @@ class TimetablePageState extends State snap: false, surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, actions: [ - Padding( - padding: const EdgeInsets.only(top: 8.0, bottom: 8.0), - child: IconButton( - splashRadius: 24.0, - // tested timetable sync - // onPressed: () async { - // ThirdPartyProvider tpp = - // Provider.of(context, - // listen: false); + // Padding( + // padding: const EdgeInsets.only(top: 8.0, bottom: 8.0), + // child: IconButton( + // splashRadius: 24.0, + // // tested timetable sync + // // onPressed: () async { + // // ThirdPartyProvider tpp = + // // Provider.of(context, + // // listen: false); - // await tpp.pushTimetable(context, _controller); - // }, - onPressed: () { - // If timetable empty, show empty - if (_tabController.length == 0) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text("empty_timetable".i18n), - duration: const Duration(seconds: 2), - )); - return; - } + // // await tpp.pushTimetable(context, _controller); + // // }, + // onPressed: () { + // // If timetable empty, show empty + // if (_tabController.length == 0) { + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text("empty_timetable".i18n), + // duration: const Duration(seconds: 2), + // )); + // return; + // } - Navigator.of(context, rootNavigator: true) - .push(PageRouteBuilder( - pageBuilder: - (context, animation, secondaryAnimation) => - FSTimetable( - controller: _controller, - ), - )) - .then((_) { - SystemChrome.setPreferredOrientations( - [DeviceOrientation.portraitUp]); - setSystemChrome(context); - }); - }, - icon: Icon(FeatherIcons.trello, - color: AppColors.of(context).text), - ), - ), + // Navigator.of(context, rootNavigator: true) + // .push(PageRouteBuilder( + // pageBuilder: + // (context, animation, secondaryAnimation) => + // FSTimetable( + // controller: _controller, + // ), + // )) + // .then((_) { + // SystemChrome.setPreferredOrientations( + // [DeviceOrientation.portraitUp]); + // setSystemChrome(context); + // }); + // }, + // icon: Icon(FeatherIcons.trello, + // color: AppColors.of(context).text), + // ), + // ), Padding( padding: const EdgeInsets.only( - right: 8.0, + right: 5.0, bottom: 8.0, top: 8.0, ), @@ -293,9 +300,9 @@ class TimetablePageState extends State // await tpp.pushTimetable(context, _controller); // }, onPressed: () { - showQuickOptions(context); + showQuickSettings(context); }, - icon: Icon(FeatherIcons.menu, + icon: Icon(FeatherIcons.moreHorizontal, color: AppColors.of(context).text), ), ), @@ -711,6 +718,9 @@ class TimetablePageState extends State customLessonDesc[ lesson.id] ?? lesson.description, + showSubTiles: + settingsProvider + .qTimetableSubTiles, ), ), ), @@ -844,35 +854,149 @@ class TimetablePageState extends State ); } - void showQuickOptions(BuildContext context) { - showBottomSheetMenu( + 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, - items: [ - SwitchListTile( - title: Text( - 'show_lesson_num'.i18n, - ), - value: settingsProvider.qTimetableLessonNum, - onChanged: (v) { - settingsProvider.update(qTimetableLessonNum: v); - setState(() {}); + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + child: BottomSheetMenu(items: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.0), + color: Theme.of(context).colorScheme.background), + child: ListTile( + contentPadding: const EdgeInsets.only(left: 16.0, right: 10.0), + title: Row( + children: [ + const Icon(FeatherIcons.trello), + const SizedBox( + width: 10.0, + ), + Text('full_screen_timetable'.i18n), + ], + ), + onTap: () { + if (_tabController.length == 0) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text("empty_timetable".i18n), + duration: const Duration(seconds: 2), + )); + return; + } - Navigator.of(context).maybePop(); - }, - ), - SwitchListTile( - title: Text( - 'show_exams_and_homework'.i18n, - ), - value: settingsProvider.qTimetableSubTiles, - onChanged: (v) { - settingsProvider.update(qTimetableSubTiles: v); - setState(() {}); + Navigator.of(context, rootNavigator: true).pop(); - Navigator.of(context).maybePop(); - }, + Navigator.of(context, rootNavigator: true) + .push(PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) => + FSTimetable( + controller: _controller, + ), + )) + .then((_) { + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp]); + setSystemChrome(context); + }); + }, + ), ), - ], + const SizedBox( + height: 10.0, + ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.0), + color: Theme.of(context).colorScheme.background), + child: SwitchListTile( + contentPadding: const EdgeInsets.only(left: 16.0, right: 10.0), + title: Row( + children: [ + const Icon(Icons.local_cafe_rounded), + const SizedBox( + width: 10.0, + ), + Text('show_breaks'.i18n), + ], + ), + value: Provider.of(context, listen: false) + .showBreaks, + onChanged: (v) { + Provider.of(context, listen: false) + .update(showBreaks: v); + + Navigator.of(context, rootNavigator: true).pop(); + }, + ), + ), + // SwitchListTile( + // title: Row( + // children: [ + // const Icon(FeatherIcons.clock), + // const SizedBox( + // width: 10.0, + // ), + // Text('show_lesson_num'.i18n), + // ], + // ), + // value: Provider.of(context, listen: false) + // .qTimetableLessonNum, + // onChanged: (v) { + // Provider.of(context, listen: false) + // .update(qTimetableLessonNum: v); + + // Navigator.of(context, rootNavigator: true).pop(); + // }, + // ), + const SizedBox( + height: 10.0, + ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.0), + color: Theme.of(context).colorScheme.background), + child: SwitchListTile( + contentPadding: const EdgeInsets.only(left: 16.0, right: 10.0), + title: Row( + children: [ + const Icon(Icons.edit_document), + const SizedBox( + width: 10.0, + ), + Text('show_exams_homework'.i18n), + ], + ), + value: Provider.of(context, listen: false) + .qTimetableSubTiles, + onChanged: (v) { + Provider.of(context, listen: false) + .update(qTimetableSubTiles: v); + + Navigator.of(context, rootNavigator: true).pop(); + }, + ), + ), + ]), ); } } diff --git a/refilc_mobile_ui/lib/pages/timetable/timetable_page.i18n.dart b/refilc_mobile_ui/lib/pages/timetable/timetable_page.i18n.dart index c2d9f31..843090d 100644 --- a/refilc_mobile_ui/lib/pages/timetable/timetable_page.i18n.dart +++ b/refilc_mobile_ui/lib/pages/timetable/timetable_page.i18n.dart @@ -10,6 +10,9 @@ extension Localization on String { "error": "Failed to fetch timetable!", "empty_timetable": "Timetable is empty!", "break": "Break", + "full_screen_timetable": "Full Screen Timetable", + "show_breaks": "Show Breaks", + "show_exams_homework": "Exams and Homework", }, "hu_hu": { "timetable": "Órarend", @@ -18,6 +21,9 @@ extension Localization on String { "error": "Nem sikerült lekérni az órarendet!", "empty_timetable": "Az órarend üres!", "break": "Szünet", + "full_screen_timetable": "Teljes képernyős órarend", + "show_breaks": "Szünetek megjelenítése", + "show_exams_homework": "Dolgozatok és házik", }, "de_de": { "timetable": "Zeitplan", @@ -26,6 +32,9 @@ extension Localization on String { "error": "Der Fahrplan konnte nicht abgerufen werden!", "empty_timetable": "Der Zeitplan ist blank!", "break": "Pause", + "full_screen_timetable": "Vollbildfahrplan", + "show_breaks": "Pausen anzeigen", + "show_exams_homework": "Referate und Hausaufgaben", }, }; diff --git a/refilc_mobile_ui/lib/screens/settings/settings_helper.dart b/refilc_mobile_ui/lib/screens/settings/settings_helper.dart index e566eea..75959e2 100644 --- a/refilc_mobile_ui/lib/screens/settings/settings_helper.dart +++ b/refilc_mobile_ui/lib/screens/settings/settings_helper.dart @@ -751,7 +751,7 @@ class _BellDelaySettingState extends State Provider.of(context, listen: false) .update(bellDelay: currentDelay.inSeconds); _tabController.index = currentDelay.inSeconds > 0 ? 1 : 0; - if(Platform.isIOS){ + if (Platform.isIOS) { LiveCardProvider.hasActivitySettingsChanged = true; } setState(() {}); @@ -764,7 +764,7 @@ class _BellDelaySettingState extends State //Provider.of(context, listen: false).update(context, rounding: (r * 10).toInt()); Provider.of(context, listen: false) .update(bellDelay: currentDelay.inSeconds); - if(Platform.isIOS){ + if (Platform.isIOS) { LiveCardProvider.hasActivitySettingsChanged = true; } Navigator.of(context).maybePop();