diff --git a/android/app/src/main/kotlin/de/tum/in/tumcampus/widgets/calendar/CalendarWidgetService.kt b/android/app/src/main/kotlin/de/tum/in/tumcampus/widgets/calendar/CalendarWidgetService.kt index 06d79d82..c48ad1fc 100644 --- a/android/app/src/main/kotlin/de/tum/in/tumcampus/widgets/calendar/CalendarWidgetService.kt +++ b/android/app/src/main/kotlin/de/tum/in/tumcampus/widgets/calendar/CalendarWidgetService.kt @@ -9,6 +9,7 @@ import de.tum.`in`.tumcampus.R import de.tum.`in`.tumcampus.util.Const import es.antonborri.home_widget.HomeWidgetPlugin import kotlinx.serialization.json.Json +import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.time.format.TextStyle import java.util.* @@ -34,6 +35,10 @@ class CalendarWidgetService : RemoteViewsService() { calendarEvents = Json.decodeFromString>(data).asList() } + calendarEvents.filter { widgetCalendarItem -> + widgetCalendarItem.endDate.isAfter(LocalDateTime.now()) + } + // Set isFirstOnDay flags if (calendarEvents.isNotEmpty()) { calendarEvents[0].isFirstOnDay = true diff --git a/assets/translations/de.json b/assets/translations/de.json index 4cffb277..d38c095d 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -196,6 +196,7 @@ "openIn": "In {} öffnen", "unknownDirection": "Unbekannte Richtung", "showWeekends": "Wochenenden anzeigen", + "showHiddenCalendarEntries": "Versteckte Kalendareintrage anzeigen", "color": "Farbe", "resetLogin": "Zurücksetzen & Anmelden", "resetPreferences": "Einstellungen zurücksetzen", @@ -225,5 +226,6 @@ "campus": "Campus", "studies": "Studium", "suggested": "Interessante {}", - "all": "Alle" + "all": "Alle", + "visibility": "Sichtbarkeit" } diff --git a/assets/translations/en.json b/assets/translations/en.json index 4af6a238..5abfcc87 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -196,6 +196,7 @@ "openIn": "Open in {}", "unknownDirection": "Unknown Direction", "showWeekends": "Show Weekends", + "showHiddenCalendarEntries": "Show Hidden Calendar Entries", "color": "Color", "resetLogin": "Reset & Login", "resetPreferences": "Reset Preferences", @@ -225,5 +226,6 @@ "campus": "Campus", "studies": "Studies", "suggested": "Suggested {}", - "all": "All" + "all": "All", + "visibility": "Visibility" } diff --git a/devtools_options.yaml b/devtools_options.yaml index fa0b357c..f592d85a 100644 --- a/devtools_options.yaml +++ b/devtools_options.yaml @@ -1,3 +1,4 @@ description: This file stores settings for Dart & Flutter DevTools. documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states extensions: + - drift: true \ No newline at end of file diff --git a/ios/CalendarWidget/CalendarWidget.swift b/ios/CalendarWidget/CalendarWidget.swift index 55c8183a..cb4349c9 100644 --- a/ios/CalendarWidget/CalendarWidget.swift +++ b/ios/CalendarWidget/CalendarWidget.swift @@ -34,7 +34,8 @@ struct Provider: TimelineProvider { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS" decoder.dateDecodingStrategy = .formatted(dateFormatter) - let entries = try decoder.decode([CalendarEntry].self, from: data) + var entries = try decoder.decode([CalendarEntry].self, from: data) + entries = entries.filter({ $0.endDate > Date() }) let entry = CalendarWidgetEntry(date: dateFormatter.date(from: calendarSaved ?? "") ?? Date(), entries: entries, size: context.family) completion(entry) } catch { diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d61257a8..22263ef5 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -119,7 +119,7 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - - sqflite (0.0.3): + - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS - "sqlite3 (3.46.1+1)": @@ -163,7 +163,7 @@ DEPENDENCIES: - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - quick_actions_ios (from `.symlinks/plugins/quick_actions_ios/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - - sqflite (from `.symlinks/plugins/sqflite/darwin`) + - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) @@ -223,8 +223,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/quick_actions_ios/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" - sqflite: - :path: ".symlinks/plugins/sqflite/darwin" + sqflite_darwin: + :path: ".symlinks/plugins/sqflite_darwin/darwin" sqlite3_flutter_libs: :path: ".symlinks/plugins/sqlite3_flutter_libs/ios" url_launcher_ios: @@ -267,7 +267,7 @@ SPEC CHECKSUMS: PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 quick_actions_ios: 56f3cbaa71e94f212838d1f9fe354bd0734779bf shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec + sqflite_darwin: a553b1fd6fe66f53bbb0fe5b4f5bab93f08d7a13 sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb sqlite3_flutter_libs: c00457ebd31e59fa6bb830380ddba24d44fbcd3b url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe diff --git a/lib/base/enums/user_preference.dart b/lib/base/enums/user_preference.dart index f58329d1..c1e0faf9 100644 --- a/lib/base/enums/user_preference.dart +++ b/lib/base/enums/user_preference.dart @@ -7,7 +7,8 @@ enum UserPreference { calendarColors(String), browser(bool), failedGrades(bool), - weekends(bool); + weekends(bool), + hiddenCalendarEntries(bool); final Type type; diff --git a/lib/calendarComponent/model/calendar_data_source.dart b/lib/calendarComponent/model/calendar_data_source.dart index 42397435..0a9733f2 100644 --- a/lib/calendarComponent/model/calendar_data_source.dart +++ b/lib/calendarComponent/model/calendar_data_source.dart @@ -1,13 +1,24 @@ import 'package:campus_flutter/base/extensions/cast.dart'; import 'package:campus_flutter/calendarComponent/model/calendar_event.dart'; +import 'package:campus_flutter/settingsComponent/views/settings_view.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; class MeetingDataSource extends CalendarDataSource { final BuildContext context; + final WidgetRef ref; - MeetingDataSource(List source, this.context) { - appointments = source; + MeetingDataSource(List source, this.context, this.ref) { + if (!ref.read(showHiddenCalendarEntries)) { + appointments = source + .where( + (element) => element.isVisible ?? true, + ) + .toList(); + } else { + appointments = source; + } } @override diff --git a/lib/calendarComponent/model/calendar_event.dart b/lib/calendarComponent/model/calendar_event.dart index 894a2ed9..9c9f0ff7 100644 --- a/lib/calendarComponent/model/calendar_event.dart +++ b/lib/calendarComponent/model/calendar_event.dart @@ -22,6 +22,7 @@ class CalendarEvent extends Searchable { final String? location; int? color; + bool? isVisible; Duration get duration { return endDate.difference(startDate); diff --git a/lib/calendarComponent/model/calendar_preferences.dart b/lib/calendarComponent/model/calendar_preferences.dart new file mode 100644 index 00000000..29483567 --- /dev/null +++ b/lib/calendarComponent/model/calendar_preferences.dart @@ -0,0 +1,19 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'calendar_preferences.g.dart'; + +@JsonSerializable() +class CalendarPreferences { + final Map colorPreferences; + final Map visibilityPreferences; + + CalendarPreferences( + this.colorPreferences, + this.visibilityPreferences, + ); + + factory CalendarPreferences.fromJson(Map json) => + _$CalendarPreferencesFromJson(json); + + Map toJson() => _$CalendarPreferencesToJson(this); +} diff --git a/lib/calendarComponent/model/calendar_preferences.g.dart b/lib/calendarComponent/model/calendar_preferences.g.dart new file mode 100644 index 00000000..2fbd4374 --- /dev/null +++ b/lib/calendarComponent/model/calendar_preferences.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'calendar_preferences.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CalendarPreferences _$CalendarPreferencesFromJson(Map json) => + CalendarPreferences( + Map.from(json['colorPreferences'] as Map), + Map.from(json['visibilityPreferences'] as Map), + ); + +Map _$CalendarPreferencesToJson( + CalendarPreferences instance) => + { + 'colorPreferences': instance.colorPreferences, + 'visibilityPreferences': instance.visibilityPreferences, + }; diff --git a/lib/calendarComponent/model/color_preferences.dart b/lib/calendarComponent/model/color_preferences.dart deleted file mode 100644 index 94edb094..00000000 --- a/lib/calendarComponent/model/color_preferences.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'color_preferences.g.dart'; - -@JsonSerializable() -class ColorPreferences { - final Map preferences; - - ColorPreferences(this.preferences); - - factory ColorPreferences.fromJson(Map json) => - _$ColorPreferencesFromJson(json); - - Map toJson() => _$ColorPreferencesToJson(this); -} diff --git a/lib/calendarComponent/model/color_preferences.g.dart b/lib/calendarComponent/model/color_preferences.g.dart deleted file mode 100644 index 73cbcf70..00000000 --- a/lib/calendarComponent/model/color_preferences.g.dart +++ /dev/null @@ -1,17 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'color_preferences.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -ColorPreferences _$ColorPreferencesFromJson(Map json) => - ColorPreferences( - Map.from(json['preferences'] as Map), - ); - -Map _$ColorPreferencesToJson(ColorPreferences instance) => - { - 'preferences': instance.preferences, - }; diff --git a/lib/calendarComponent/services/calendar_color_service.dart b/lib/calendarComponent/services/calendar_color_service.dart deleted file mode 100644 index ffc2b077..00000000 --- a/lib/calendarComponent/services/calendar_color_service.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'dart:convert'; - -import 'package:campus_flutter/calendarComponent/model/color_preferences.dart'; -import 'package:flutter/material.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class CalendarColorService { - static const key = "calendarColors"; - - final SharedPreferences sharedPreferences; - - Map colorPreferences = {}; - - CalendarColorService(this.sharedPreferences); - - void saveColorPreference(String id, Color color) { - colorPreferences[id] = color.value; - try { - sharedPreferences.setString( - key, - jsonEncode(ColorPreferences(colorPreferences).toJson()), - ); - } catch (_) {} - } - - Color? getColorPreference(String key) { - if (colorPreferences.isEmpty) { - loadColorPreferences(); - } - - final color = colorPreferences[key]; - return color != null ? Color(color) : null; - } - - void loadColorPreferences() { - try { - final data = sharedPreferences.getString(key); - if (data != null) { - final json = jsonDecode(data); - colorPreferences = ColorPreferences.fromJson( - json as Map, - ).preferences; - } - } catch (_) {} - } - - void resetColorPreferences() { - sharedPreferences.remove(key); - } -} diff --git a/lib/calendarComponent/services/calendar_preference_service.dart b/lib/calendarComponent/services/calendar_preference_service.dart new file mode 100644 index 00000000..9db868ea --- /dev/null +++ b/lib/calendarComponent/services/calendar_preference_service.dart @@ -0,0 +1,82 @@ +import 'dart:convert'; + +import 'package:campus_flutter/calendarComponent/model/calendar_preferences.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class CalendarPreferenceService { + static const key = "calendar"; + + final SharedPreferences sharedPreferences; + + Map colorPreferences = {}; + Map visibilityPreferences = {}; + + CalendarPreferenceService(this.sharedPreferences); + + void saveColorPreference(String id, Color color) { + colorPreferences[id] = color.value; + try { + sharedPreferences.setString( + key, + jsonEncode( + CalendarPreferences( + colorPreferences, + visibilityPreferences, + ).toJson(), + ), + ); + } catch (_) {} + } + + Color? getColorPreference(String key) { + if (colorPreferences.isEmpty) { + loadPreferences(); + } + + final color = colorPreferences[key]; + return color != null ? Color(color) : null; + } + + void saveVisibilityPreference(String id, bool isVisible) { + visibilityPreferences[id] = isVisible; + try { + sharedPreferences.setString( + key, + jsonEncode( + CalendarPreferences( + colorPreferences, + visibilityPreferences, + ).toJson(), + ), + ); + } catch (_) {} + } + + bool? getVisibilityPreference(String key) { + if (visibilityPreferences.isEmpty) { + loadPreferences(); + } + + return visibilityPreferences[key]; + } + + void loadPreferences() { + try { + final data = sharedPreferences.getString(key); + if (data != null) { + final json = jsonDecode(data); + final calendarPreferences = CalendarPreferences.fromJson( + json as Map, + ); + colorPreferences = calendarPreferences.colorPreferences; + visibilityPreferences = calendarPreferences.visibilityPreferences; + } + } catch (_) {} + } + + void resetPreferences() { + sharedPreferences.remove(key); + } +} diff --git a/lib/calendarComponent/viewModels/calendar_viewmodel.dart b/lib/calendarComponent/viewModels/calendar_viewmodel.dart index d2726202..eb9925e1 100644 --- a/lib/calendarComponent/viewModels/calendar_viewmodel.dart +++ b/lib/calendarComponent/viewModels/calendar_viewmodel.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'package:campus_flutter/calendarComponent/model/calendar_event.dart'; -import 'package:campus_flutter/calendarComponent/services/calendar_color_service.dart'; +import 'package:campus_flutter/calendarComponent/services/calendar_preference_service.dart'; import 'package:campus_flutter/calendarComponent/services/calendar_service.dart'; import 'package:campus_flutter/main.dart'; import 'package:flutter/material.dart'; @@ -12,27 +12,35 @@ import 'package:rxdart/rxdart.dart'; final calendarViewModel = Provider((ref) => CalendarViewModel()); class CalendarViewModel { - BehaviorSubject?> events = BehaviorSubject.seeded(null); - - final BehaviorSubject lastFetched = BehaviorSubject.seeded(null); - - BehaviorSubject<(List, List)?> widgetEvents = + final BehaviorSubject?> events = BehaviorSubject.seeded(null); + final BehaviorSubject lastFetched = BehaviorSubject.seeded(null); + final BehaviorSubject<(List, List)?> + widgetEvents = BehaviorSubject.seeded(null); Future fetch(bool forcedRefresh) async { CalendarService.fetchCalendar(forcedRefresh).then( (response) { lastFetched.add(response.$1); - getIt().loadColorPreferences(); + response.$2.removeWhere((element) => element.isCanceled); + getIt().loadPreferences(); for (var element in response.$2) { - final eventColor = getIt().getColorPreference( + final eventColor = + getIt().getColorPreference( element.lvNr ?? element.id, ); if (eventColor != null) { element.setColor(eventColor); } + + final eventVisibility = + getIt().getVisibilityPreference( + element.lvNr ?? element.id, + ); + if (eventVisibility != null) { + element.isVisible = eventVisibility; + } } - response.$2.removeWhere((element) => element.isCanceled); events.add(response.$2); updateHomeWidget(response.$2); }, @@ -45,7 +53,11 @@ class CalendarViewModel { "calendar", jsonEncode( calendarEvents - .where((element) => element.startDate.isAfter(DateTime.now())) + .where( + (element) => + (element.isVisible ?? true) && + element.endDate.isAfter(DateTime.now()), + ) .toList(), ), ); @@ -65,9 +77,9 @@ class CalendarViewModel { final filteredEvents = events.value ?.where( - (element) => element.startDate.isAfter( - DateTime.now(), - ), + (element) => + element.startDate.isAfter(DateTime.now()) && + (element.isVisible ?? true), ) .toList() ?? []; @@ -101,13 +113,13 @@ class CalendarViewModel { } void setEventColor(String key, Color color) { - getIt().saveColorPreference( + getIt().saveColorPreference( key, color, ); final elements = events.value; elements?.forEach((element) { - if (element.id == key || element.lvNr == key) { + if (element.lvNr == key || element.id == key) { element.setColor(color); } }); @@ -115,7 +127,45 @@ class CalendarViewModel { updateHomeWidget(events.value ?? []); } - void resetEventColors() { + void toggleEventVisibility(String key) { + var preference = getIt().getVisibilityPreference( + key, + ); + + if (preference != null) { + preference = !preference; + } else { + preference = false; + } + + getIt().saveVisibilityPreference( + key, + preference, + ); + + final elements = events.value; + elements?.forEach((element) { + if (element.lvNr == key || element.id == key) { + element.isVisible = preference; + } + }); + events.add(elements); + updateHomeWidget(events.value ?? []); + } + + void resetPreferences() { + _resetEventColors(); + _resetVisibility(); + } + + void _resetEventColors() { + final elements = events.value; + elements?.forEach((element) => element.setColor(null)); + events.add(elements); + updateHomeWidget(events.value ?? []); + } + + void _resetVisibility() { final elements = events.value; elements?.forEach((element) => element.setColor(null)); events.add(elements); diff --git a/lib/calendarComponent/views/calendar_day_view.dart b/lib/calendarComponent/views/calendar_day_view.dart index 4ffa9847..2e538306 100644 --- a/lib/calendarComponent/views/calendar_day_view.dart +++ b/lib/calendarComponent/views/calendar_day_view.dart @@ -30,6 +30,7 @@ class CalendarDayView extends ConsumerWidget { dataSource: MeetingDataSource( snapshot.data ?? [], context, + ref, ), onTap: (details) { if (details.targetElement == CalendarElement.appointment) { diff --git a/lib/calendarComponent/views/calendar_month_view.dart b/lib/calendarComponent/views/calendar_month_view.dart index 10e93a01..781658e2 100644 --- a/lib/calendarComponent/views/calendar_month_view.dart +++ b/lib/calendarComponent/views/calendar_month_view.dart @@ -37,6 +37,7 @@ class CalendarMonthView extends ConsumerWidget { dataSource: MeetingDataSource( snapshot.data ?? [], context, + ref, ), firstDayOfWeek: 1, showDatePickerButton: true, diff --git a/lib/calendarComponent/views/calendar_week_view.dart b/lib/calendarComponent/views/calendar_week_view.dart index fb72d772..339f7e61 100644 --- a/lib/calendarComponent/views/calendar_week_view.dart +++ b/lib/calendarComponent/views/calendar_week_view.dart @@ -35,6 +35,7 @@ class CalendarWeekView extends ConsumerWidget { dataSource: MeetingDataSource( snapshot.data ?? [], context, + ref, ), onTap: (details) { if (details.targetElement == CalendarElement.appointment) { diff --git a/lib/calendarComponent/views/custom_event_view.dart b/lib/calendarComponent/views/custom_event_view.dart index bf11e28f..63f6714c 100644 --- a/lib/calendarComponent/views/custom_event_view.dart +++ b/lib/calendarComponent/views/custom_event_view.dart @@ -2,6 +2,7 @@ import 'package:campus_flutter/base/extensions/context.dart'; import 'package:campus_flutter/base/util/color_picker_view.dart'; import 'package:campus_flutter/calendarComponent/model/calendar_event.dart'; import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; +import 'package:campus_flutter/calendarComponent/views/visibility_button_view.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -35,18 +36,34 @@ class CustomEventView extends ConsumerWidget { ), context, ), - _infoEntry( - context.tr("color"), - ColorPickerView( - color: calendarEvent.getColor(), - onColorChanged: (color) { - ref.read(calendarViewModel).setEventColor( - calendarEvent.lvNr ?? calendarEvent.id, - color, - ); - }, - ), - context, + Row( + children: [ + Expanded( + child: _infoEntry( + context.tr("color"), + ColorPickerView( + color: calendarEvent.getColor(), + onColorChanged: (color) { + ref.read(calendarViewModel).setEventColor( + calendarEvent.lvNr ?? calendarEvent.id, + color, + ); + }, + ), + context, + ), + ), + Expanded( + child: _infoEntry( + context.tr("visibility"), + VisibilityButtonView( + id: calendarEvent.lvNr ?? calendarEvent.id, + isVisible: calendarEvent.isVisible, + ), + context, + ), + ), + ], ), ], ); @@ -62,7 +79,10 @@ class CustomEventView extends ConsumerWidget { title, style: Theme.of(context).textTheme.titleMedium, ), - child, + Padding( + padding: EdgeInsets.symmetric(vertical: context.halfPadding), + child: child, + ), ], ), ); diff --git a/lib/calendarComponent/views/event_creation_date_time_picker.dart b/lib/calendarComponent/views/event_creation_date_time_picker.dart index 2c60ed61..470b306f 100644 --- a/lib/calendarComponent/views/event_creation_date_time_picker.dart +++ b/lib/calendarComponent/views/event_creation_date_time_picker.dart @@ -41,7 +41,7 @@ class EventCreationDateTimePicker extends StatelessWidget { () async => onDateSet( await showDatePicker( context: context, - firstDate: snapshot.data ?? DateTime.now(), + firstDate: DateTime.now(), lastDate: (snapshot.data ?? DateTime.now()).add( const Duration(days: 365), ), diff --git a/lib/calendarComponent/views/visibility_button_view.dart b/lib/calendarComponent/views/visibility_button_view.dart new file mode 100644 index 00000000..3f9609b0 --- /dev/null +++ b/lib/calendarComponent/views/visibility_button_view.dart @@ -0,0 +1,39 @@ +import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class VisibilityButtonView extends ConsumerStatefulWidget { + const VisibilityButtonView({ + super.key, + required this.id, + required this.isVisible, + }); + + final String id; + final bool? isVisible; + + @override + ConsumerState createState() => + _VisibilityButtonViewState(); +} + +class _VisibilityButtonViewState extends ConsumerState { + late bool isVisible = widget.isVisible ?? true; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () { + ref.read(calendarViewModel).toggleEventVisibility( + widget.id, + ); + setState(() { + isVisible = !isVisible; + }); + }, + child: Icon( + (isVisible) ? Icons.visibility : Icons.visibility_off, + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index c269146f..0e796b31 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,7 +11,7 @@ import 'package:campus_flutter/base/routing/router_service.dart'; import 'package:campus_flutter/base/routing/routes.dart'; import 'package:campus_flutter/base/theme/dark_theme.dart'; import 'package:campus_flutter/base/theme/light_theme.dart'; -import 'package:campus_flutter/calendarComponent/services/calendar_color_service.dart'; +import 'package:campus_flutter/calendarComponent/services/calendar_preference_service.dart'; import 'package:campus_flutter/calendarComponent/services/calendar_view_service.dart'; import 'package:campus_flutter/onboardingComponent/services/onboarding_service.dart'; import 'package:campus_flutter/navigation_service.dart'; @@ -107,8 +107,8 @@ Future _initializeServices() async { getIt.registerSingleton( UserPreferencesService(sharedPreferences), ); - getIt.registerSingleton( - CalendarColorService(sharedPreferences), + getIt.registerSingleton( + CalendarPreferenceService(sharedPreferences), ); } diff --git a/lib/onboardingComponent/viewModels/onboarding_viewmodel.dart b/lib/onboardingComponent/viewModels/onboarding_viewmodel.dart index a12a55da..1cbde077 100644 --- a/lib/onboardingComponent/viewModels/onboarding_viewmodel.dart +++ b/lib/onboardingComponent/viewModels/onboarding_viewmodel.dart @@ -5,7 +5,7 @@ import 'package:campus_flutter/base/networking/protocols/api.dart'; import 'package:campus_flutter/base/networking/base/rest_client.dart'; import 'package:campus_flutter/base/routing/router_service.dart'; import 'package:campus_flutter/base/routing/routes.dart'; -import 'package:campus_flutter/calendarComponent/services/calendar_color_service.dart'; +import 'package:campus_flutter/calendarComponent/services/calendar_preference_service.dart'; import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; import 'package:campus_flutter/onboardingComponent/model/confirm.dart'; import 'package:campus_flutter/onboardingComponent/services/onboarding_service.dart'; @@ -146,9 +146,9 @@ class OnboardingViewModel { Future resetPreferences(WidgetRef ref) async { getIt().resetAll(); - getIt().resetColorPreferences(); + getIt().resetPreferences(); ref.read(userPreferencesViewModel).loadPreferences(); - ref.read(calendarViewModel).resetEventColors(); + ref.read(calendarViewModel).resetPreferences(); } Future logout(WidgetRef ref) async { diff --git a/lib/settingsComponent/viewModels/user_preferences_viewmodel.dart b/lib/settingsComponent/viewModels/user_preferences_viewmodel.dart index c4e98f4e..27f49d6e 100644 --- a/lib/settingsComponent/viewModels/user_preferences_viewmodel.dart +++ b/lib/settingsComponent/viewModels/user_preferences_viewmodel.dart @@ -34,6 +34,9 @@ class UserPreferencesViewModel { ref.read(hideFailedGrades.notifier).state = value as bool; case UserPreference.weekends: ref.read(showWeekends.notifier).state = value as bool; + case UserPreference.hiddenCalendarEntries: + ref.read(showHiddenCalendarEntries.notifier).state = + value as bool; default: break; } @@ -54,6 +57,8 @@ class UserPreferencesViewModel { ref.read(hideFailedGrades.notifier).state = value as bool; case UserPreference.weekends: ref.read(showWeekends.notifier).state = value as bool; + case UserPreference.hiddenCalendarEntries: + ref.read(showHiddenCalendarEntries.notifier).state = value as bool; default: break; } diff --git a/lib/settingsComponent/views/appearance_settings_view.dart b/lib/settingsComponent/views/appearance_settings_view.dart index 0c4ab3ae..db515795 100644 --- a/lib/settingsComponent/views/appearance_settings_view.dart +++ b/lib/settingsComponent/views/appearance_settings_view.dart @@ -1,9 +1,6 @@ -import 'dart:io'; - import 'package:campus_flutter/base/enums/appearance.dart'; import 'package:campus_flutter/base/enums/user_preference.dart'; import 'package:campus_flutter/base/util/seperated_list.dart'; -import 'package:campus_flutter/calendarComponent/views/calendars_view.dart'; import 'package:campus_flutter/studiesComponent/viewModel/grade_viewmodel.dart'; import 'package:campus_flutter/homeComponent/view/widget/widget_frame_view.dart'; import 'package:campus_flutter/main.dart'; @@ -12,7 +9,6 @@ import 'package:campus_flutter/settingsComponent/views/settings_view.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:syncfusion_flutter_calendar/calendar.dart'; class AppearanceSettingsView extends ConsumerWidget { const AppearanceSettingsView({super.key}); @@ -25,9 +21,8 @@ class AppearanceSettingsView extends ConsumerWidget { child: SeparatedList.widgets( widgets: [ _appearanceSelection(context, ref), - if (Platform.isIOS) _useWebView(context, ref), + _useWebView(context, ref), _hideFailedGrades(context, ref), - _showWeeks(context, ref), ], ), ), @@ -95,25 +90,4 @@ class AppearanceSettingsView extends ConsumerWidget { ), ); } - - Widget _showWeeks(BuildContext context, WidgetRef ref) { - return ListTile( - dense: true, - title: Text( - context.tr("showWeekends"), - style: Theme.of(context).textTheme.bodyMedium, - ), - trailing: Switch( - value: ref.watch(showWeekends), - onChanged: (value) { - ref.read(userPreferencesViewModel).savePreference( - UserPreference.weekends, - value, - ); - calendarsKey.currentState?.weekController.view = - value ? CalendarView.week : CalendarView.workWeek; - }, - ), - ); - } } diff --git a/lib/settingsComponent/views/calendar_settings_view.dart b/lib/settingsComponent/views/calendar_settings_view.dart new file mode 100644 index 00000000..20b60443 --- /dev/null +++ b/lib/settingsComponent/views/calendar_settings_view.dart @@ -0,0 +1,71 @@ +import 'package:campus_flutter/base/enums/user_preference.dart'; +import 'package:campus_flutter/base/util/seperated_list.dart'; +import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; +import 'package:campus_flutter/calendarComponent/views/calendars_view.dart'; +import 'package:campus_flutter/homeComponent/view/widget/widget_frame_view.dart'; +import 'package:campus_flutter/settingsComponent/viewModels/user_preferences_viewmodel.dart'; +import 'package:campus_flutter/settingsComponent/views/settings_view.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:syncfusion_flutter_calendar/calendar.dart'; + +class CalendarSettingsView extends ConsumerWidget { + const CalendarSettingsView({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return WidgetFrameView( + title: context.tr("calendar"), + child: Card( + child: SeparatedList.widgets( + widgets: [ + _showWeekends(context, ref), + _showHiddenCalendarEntries(context, ref), + ], + ), + ), + ); + } + + Widget _showWeekends(BuildContext context, WidgetRef ref) { + return ListTile( + dense: true, + title: Text( + context.tr("showWeekends"), + style: Theme.of(context).textTheme.bodyMedium, + ), + trailing: Switch( + value: ref.watch(showWeekends), + onChanged: (value) { + ref.read(userPreferencesViewModel).savePreference( + UserPreference.weekends, + value, + ); + calendarsKey.currentState?.weekController.view = + value ? CalendarView.week : CalendarView.workWeek; + }, + ), + ); + } + + Widget _showHiddenCalendarEntries(BuildContext context, WidgetRef ref) { + return ListTile( + dense: true, + title: Text( + context.tr("showHiddenCalendarEntries"), + style: Theme.of(context).textTheme.bodyMedium, + ), + trailing: Switch( + value: ref.watch(showHiddenCalendarEntries), + onChanged: (value) { + ref.read(userPreferencesViewModel).savePreference( + UserPreference.hiddenCalendarEntries, + value, + ); + ref.read(calendarViewModel).fetch(false); + }, + ), + ); + } +} diff --git a/lib/settingsComponent/views/settings_view.dart b/lib/settingsComponent/views/settings_view.dart index b70813b5..51ef264a 100644 --- a/lib/settingsComponent/views/settings_view.dart +++ b/lib/settingsComponent/views/settings_view.dart @@ -4,6 +4,7 @@ import 'package:campus_flutter/base/util/padded_divider.dart'; import 'package:campus_flutter/homeComponent/view/widget/widget_frame_view.dart'; import 'package:campus_flutter/onboardingComponent/viewModels/onboarding_viewmodel.dart'; import 'package:campus_flutter/settingsComponent/views/appearance_settings_view.dart'; +import 'package:campus_flutter/settingsComponent/views/calendar_settings_view.dart'; import 'package:campus_flutter/settingsComponent/views/contact_view.dart'; import 'package:campus_flutter/settingsComponent/views/general_settings_view.dart'; import 'package:easy_localization/easy_localization.dart'; @@ -15,6 +16,7 @@ import 'package:package_info_plus/package_info_plus.dart'; final useWebView = StateProvider((ref) => true); final hideFailedGrades = StateProvider((ref) => false); final showWeekends = StateProvider((ref) => false); +final showHiddenCalendarEntries = StateProvider((ref) => false); class SettingsView extends ConsumerWidget { const SettingsView({super.key}); @@ -29,6 +31,7 @@ class SettingsView extends ConsumerWidget { children: [ GeneralSettingsView(), AppearanceSettingsView(), + CalendarSettingsView(), ], ), ), @@ -48,6 +51,7 @@ class SettingsView extends ConsumerWidget { children: [ const GeneralSettingsView(), const AppearanceSettingsView(), + const CalendarSettingsView(), const ContactView(), _resetButtons(context, ref), _versionNumberText(), diff --git a/lib/studiesComponent/view/lectureDetail/lecture_details_view.dart b/lib/studiesComponent/view/lectureDetail/lecture_details_view.dart index 42fc6a97..bda7df57 100644 --- a/lib/studiesComponent/view/lectureDetail/lecture_details_view.dart +++ b/lib/studiesComponent/view/lectureDetail/lecture_details_view.dart @@ -6,6 +6,7 @@ import 'package:campus_flutter/base/errorHandling/error_handling_router.dart'; import 'package:campus_flutter/calendarComponent/model/calendar_event.dart'; import 'package:campus_flutter/calendarComponent/viewModels/calendar_viewmodel.dart'; import 'package:campus_flutter/base/util/color_picker_view.dart'; +import 'package:campus_flutter/calendarComponent/views/visibility_button_view.dart'; import 'package:campus_flutter/studiesComponent/model/lecture.dart'; import 'package:campus_flutter/studiesComponent/model/lecture_details.dart'; import 'package:campus_flutter/studiesComponent/view/lectureDetail/basic_lecture_info_view.dart'; @@ -19,7 +20,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; -class LectureDetailsScaffold extends ConsumerStatefulWidget { +class LectureDetailsScaffold extends ConsumerWidget { const LectureDetailsScaffold({ super.key, this.scrollController, @@ -32,38 +33,35 @@ class LectureDetailsScaffold extends ConsumerStatefulWidget { final ScrollController? scrollController; @override - ConsumerState createState() => - _LectureDetailsScaffoldState(); -} - -class _LectureDetailsScaffoldState - extends ConsumerState { - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { return Scaffold( appBar: AppBar( leading: const CustomBackButton(), - actions: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: context.padding), - child: ColorPickerView( - color: widget.event?.getColor() ?? context.primaryColor, - onColorChanged: (color) { - if (widget.event != null) { - ref.read(calendarViewModel).setEventColor( - widget.event!.lvNr ?? widget.event!.id, - color, - ); - } - }, - ), - ), - ], + actions: event != null + ? [ + VisibilityButtonView( + id: event!.lvNr ?? event!.id, + isVisible: event!.isVisible, + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: context.padding), + child: ColorPickerView( + color: event?.getColor() ?? context.primaryColor, + onColorChanged: (color) { + ref.read(calendarViewModel).setEventColor( + event!.lvNr ?? event!.id, + color, + ); + }, + ), + ), + ] + : null, ), body: LectureDetailsView( - event: widget.event, - lecture: widget.lecture, - scrollController: widget.scrollController, + event: event, + lecture: lecture, + scrollController: scrollController, ), ); } diff --git a/pubspec.lock b/pubspec.lock index 7cad27c3..a069e49e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1017,10 +1017,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: f7544c346a0742aee1450f9e5c0f5269d7c602b9c95fdbcd9fb8f5b1df13b1cc + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a url: "https://pub.dev" source: hosted - version: "2.2.11" + version: "2.2.12" path_provider_foundation: dependency: transitive description: @@ -1382,18 +1382,42 @@ packages: dependency: transitive description: name: sqflite - sha256: ff5a2436ef8ebdfda748fbfe957f9981524cb5ff11e7bafa8c42771840e8a788 + sha256: "79a297dc3cc137e758c6a4baf83342b039e5a6d2436fcdf3f96a00adaaf2ad62" url: "https://pub.dev" source: hosted - version: "2.3.3+2" + version: "2.4.0" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3" + url: "https://pub.dev" + source: hosted + version: "2.4.0" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "2d8e607db72e9cb7748c9c6e739e2c9618320a5517de693d5a24609c4671b1a4" + sha256: "4468b24876d673418a7b7147e5a08a715b4998a7ae69227acafaab762e0e5490" + url: "https://pub.dev" + source: hosted + version: "2.5.4+5" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "769733dddf94622d5541c73e4ddc6aa7b252d865285914b6fcd54a63c4b4f027" + url: "https://pub.dev" + source: hosted + version: "2.4.1-1" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: b62ab81e1284341783222aefbbb44f984ebf4663d672ae10408c9a8ddab4bfb6 url: "https://pub.dev" source: hosted - version: "2.5.4+4" + version: "2.4.0-0" sqlite3: dependency: "direct main" description: @@ -1462,34 +1486,34 @@ packages: dependency: "direct main" description: name: syncfusion_flutter_calendar - sha256: "17bc2c2e95737336c1bf54e27f6d006f11e3384dd556d13ee3a9a324416ea1e4" + sha256: c2105449ffb46a9a79e5b622ceb8a78e2937c88e69747469244051803fba6b52 url: "https://pub.dev" source: hosted - version: "27.1.51" + version: "27.1.52" syncfusion_flutter_charts: dependency: "direct main" description: name: syncfusion_flutter_charts - sha256: f1463e08decdae2fff4c67f0cd86bcd64050bc49ae50c2db18acd99fdc04da18 + sha256: "4e89e0893297780d8e06be0c482b9b0a23ecf54c3d64e6e40ff06cf30952bce6" url: "https://pub.dev" source: hosted - version: "27.1.51" + version: "27.1.52" syncfusion_flutter_core: dependency: "direct main" description: name: syncfusion_flutter_core - sha256: "95a53df168fd4473bbf23c481db656db97434d18d60f59fbeec97a754794f7b5" + sha256: "7130fc3259247946b59fe9b76ee89500c775c3f7e5c1d0826f3105e1dd0bebf6" url: "https://pub.dev" source: hosted - version: "27.1.51" + version: "27.1.52" syncfusion_flutter_datepicker: dependency: "direct main" description: name: syncfusion_flutter_datepicker - sha256: dcb9da082d2e39c84415a8323287a0714ffd349d5cf3bed93af1ad0b30b7dfd9 + sha256: "61efc09e962d7b7cc3c7d33a2e44ec027112403af49590d5cc1025a255cc34fa" url: "https://pub.dev" source: hosted - version: "27.1.51" + version: "27.1.52" synchronized: dependency: transitive description: