diff --git a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart index afd8a4d9d..ada7257b5 100644 --- a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart +++ b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart @@ -23,6 +23,7 @@ class PreferencesController { static const _termsAndConditions = 'terms_and_conditions'; static const _areTermsAndConditionsAcceptedKey = 'is_t&c_accepted'; static const _tuitionNotificationsToggleKey = 'tuition_notification_toogle'; + static const _hideSensitiveInfoToggleKey = 'hide_sensitive_info_toggle'; static const _usageStatsToggleKey = 'usage_stats_toogle'; static const _themeMode = 'theme_mode'; static const _isDataCollectionBannerViewedKey = 'data_collection_banner'; @@ -287,6 +288,15 @@ class PreferencesController { await prefs.setBool(_tuitionNotificationsToggleKey, value); } + static bool getHideSensitiveInfoToggle() { + return prefs.getBool(_hideSensitiveInfoToggleKey) ?? false; + } + + static Future setHideSensitiveInfoToggle({required bool value}) async { + await prefs.setBool(_hideSensitiveInfoToggleKey, value); + _statsToggleStreamController.add(value); + } + static bool getUsageStatsToggle() { return prefs.getBool(_usageStatsToggleKey) ?? true; } diff --git a/packages/uni_app/lib/generated/intl/messages_en.dart b/packages/uni_app/lib/generated/intl/messages_en.dart index 6fb90730a..324988b90 100644 --- a/packages/uni_app/lib/generated/intl/messages_en.dart +++ b/packages/uni_app/lib/generated/intl/messages_en.dart @@ -213,6 +213,9 @@ class MessageLookup extends MessageLookupByLibrary { "goi": MessageLookupByLibrary.simpleMessage( "Orientation and Integration Office", ), + "hide_sensitive_info": MessageLookupByLibrary.simpleMessage( + "Hide sensitive info", + ), "improvement_registration": MessageLookupByLibrary.simpleMessage( "Enrollment for Improvement", ), diff --git a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart index 0d32594cb..62153b971 100644 --- a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart +++ b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart @@ -223,6 +223,9 @@ class MessageLookup extends MessageLookupByLibrary { "goi": MessageLookupByLibrary.simpleMessage( "Gabinete de Orientação e Integração", ), + "hide_sensitive_info": MessageLookupByLibrary.simpleMessage( + "Esconder informação sensível", + ), "improvement_registration": MessageLookupByLibrary.simpleMessage( "Inscrição para Melhoria", ), diff --git a/packages/uni_app/lib/generated/l10n.dart b/packages/uni_app/lib/generated/l10n.dart index d713a336e..f26fc3515 100644 --- a/packages/uni_app/lib/generated/l10n.dart +++ b/packages/uni_app/lib/generated/l10n.dart @@ -1508,6 +1508,16 @@ class S { ); } + /// `Hide sensitive info` + String get hide_sensitive_info { + return Intl.message( + 'Hide sensitive info', + name: 'hide_sensitive_info', + desc: '', + args: [], + ); + } + /// `Try again` String get try_again { return Intl.message('Try again', name: 'try_again', desc: '', args: []); diff --git a/packages/uni_app/lib/l10n/intl_en.arb b/packages/uni_app/lib/l10n/intl_en.arb index e7e9a27a7..d8f913db3 100644 --- a/packages/uni_app/lib/l10n/intl_en.arb +++ b/packages/uni_app/lib/l10n/intl_en.arb @@ -356,6 +356,8 @@ "@confirm_logout": {}, "collect_usage_stats": "Collect usage statistics", "@collect_usage_stats": {}, + "hide_sensitive_info": "Hide sensitive info", + "@hide_sensitive_info": {}, "try_again": "Try again", "@try_again": {}, "try_different_login": "Having trouble signing in?", diff --git a/packages/uni_app/lib/l10n/intl_pt_PT.arb b/packages/uni_app/lib/l10n/intl_pt_PT.arb index 10587cafd..40904a8df 100644 --- a/packages/uni_app/lib/l10n/intl_pt_PT.arb +++ b/packages/uni_app/lib/l10n/intl_pt_PT.arb @@ -356,6 +356,8 @@ "@confirm_logout": {}, "collect_usage_stats": "Partilhar estatísticas de uso", "@collect_usage_stats": {}, + "hide_sensitive_info": "Esconder informação sensível", + "@hide_sensitive_info": {}, "try_again": "Tentar de novo", "@try_again": {}, "try_different_login": "Problemas ao iniciar sessão?", diff --git a/packages/uni_app/lib/view/academic_path/courses_page.dart b/packages/uni_app/lib/view/academic_path/courses_page.dart index 80c64daee..3d7a5c447 100644 --- a/packages/uni_app/lib/view/academic_path/courses_page.dart +++ b/packages/uni_app/lib/view/academic_path/courses_page.dart @@ -1,5 +1,8 @@ +import 'dart:ui'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/profile.dart'; @@ -20,6 +23,13 @@ class CoursesPage extends ConsumerStatefulWidget { class CoursesPageState extends ConsumerState { var _courseUnitIndex = 0; + var _blurSensitiveInfo = PreferencesController.getHideSensitiveInfoToggle(); + + void _toggleBlur() { + setState(() { + _blurSensitiveInfo = !_blurSensitiveInfo; + }); + } void _onCourseUnitSelected(int index) { setState(() { @@ -139,12 +149,21 @@ class CoursesPageState extends ConsumerState { ), Padding( padding: const EdgeInsets.only(top: 40, bottom: 8), - child: AverageBar( - average: course.currentAverage ?? 0, - completedCredits: course.finishedEcts ?? 0, - totalCredits: _getTotalCredits(profile, course), - statusText: course.state ?? '', - averageText: S.of(context).average, + child: GestureDetector( + onTap: _toggleBlur, + child: ImageFiltered( + imageFilter: ImageFilter.blur( + sigmaX: _blurSensitiveInfo ? 6 : 0, + sigmaY: _blurSensitiveInfo ? 6 : 0, + ), + child: AverageBar( + average: course.currentAverage ?? 0, + completedCredits: course.finishedEcts ?? 0, + totalCredits: _getTotalCredits(profile, course), + statusText: course.state ?? '', + averageText: S.of(context).average, + ), + ), ), ), CourseUnitsView(course: course), diff --git a/packages/uni_app/lib/view/profile/widgets/hide_sensitive_info_switch.dart b/packages/uni_app/lib/view/profile/widgets/hide_sensitive_info_switch.dart new file mode 100644 index 000000000..2e349239b --- /dev/null +++ b/packages/uni_app/lib/view/profile/widgets/hide_sensitive_info_switch.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:uni/controller/local_storage/preferences_controller.dart'; + +class HideSensitiveInfoSwitch extends StatefulWidget { + const HideSensitiveInfoSwitch({super.key}); + + @override + State createState() => _HideSensitiveInfoSwitchState(); +} + +class _HideSensitiveInfoSwitchState extends State { + bool hideSensitiveInfoToggle = + PreferencesController.getHideSensitiveInfoToggle(); + + Future saveHideSensitiveInfoToggle({required bool value}) async { + await PreferencesController.setHideSensitiveInfoToggle(value: value); + setState(() { + hideSensitiveInfoToggle = value; + }); + } + + @override + Widget build(BuildContext context) { + return Switch.adaptive( + value: hideSensitiveInfoToggle, + onChanged: (value) => saveHideSensitiveInfoToggle(value: value), + ); + } +} diff --git a/packages/uni_app/lib/view/profile/widgets/settings.dart b/packages/uni_app/lib/view/profile/widgets/settings.dart index d439fd017..0ee62c2fd 100644 --- a/packages/uni_app/lib/view/profile/widgets/settings.dart +++ b/packages/uni_app/lib/view/profile/widgets/settings.dart @@ -3,6 +3,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/networking/url_launcher.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/utils/navigation_items.dart'; +import 'package:uni/view/profile/widgets/hide_sensitive_info_switch.dart'; import 'package:uni/view/profile/widgets/locale_switch_button.dart'; import 'package:uni/view/profile/widgets/notifications_dialog.dart'; // import 'package:uni/view/profile/widgets/theme_switch_button.dart'; @@ -47,6 +48,11 @@ class Settings extends StatelessWidget { title: S.of(context).collect_usage_stats, trailing: const UsageStatsSwitch(), ), + ProfileListTile( + icon: UniIcons.eyeHidden, + title: S.of(context).hide_sensitive_info, + trailing: const HideSensitiveInfoSwitch(), + ), ProfileListTile( icon: UniIcons.notification, title: S.of(context).notifications,