diff --git a/mobile/lib/ui/home/status_bar_widget.dart b/mobile/lib/ui/home/status_bar_widget.dart index df3efa0c1d..1eddcb1337 100644 --- a/mobile/lib/ui/home/status_bar_widget.dart +++ b/mobile/lib/ui/home/status_bar_widget.dart @@ -10,6 +10,7 @@ import 'package:photos/events/sync_status_update_event.dart'; import "package:photos/generated/l10n.dart"; import "package:photos/service_locator.dart"; import 'package:photos/services/sync_service.dart'; +import "package:photos/services/user_remote_flag_service.dart"; import "package:photos/theme/ente_theme.dart"; import 'package:photos/theme/text_style.dart'; import 'package:photos/ui/account/verify_recovery_page.dart'; @@ -17,12 +18,13 @@ import 'package:photos/ui/components/home_header_widget.dart'; import 'package:photos/ui/components/notification_widget.dart'; import 'package:photos/ui/home/header_error_widget.dart'; import "package:photos/ui/settings/backup/backup_status_screen.dart"; +import "package:photos/ui/settings/ml/enable_ml_consent.dart"; import 'package:photos/utils/navigation_util.dart'; const double kContainerHeight = 36; class StatusBarWidget extends StatefulWidget { - const StatusBarWidget({Key? key}) : super(key: key); + const StatusBarWidget({super.key}); @override State createState() => _StatusBarWidgetState(); @@ -35,6 +37,9 @@ class _StatusBarWidgetState extends State { late StreamSubscription _notificationSubscription; bool _showStatus = false; bool _showErrorBanner = false; + final bool _showMlBanner = !userRemoteFlagService + .getCachedBoolValue(UserRemoteFlagService.mlEnabled) && + !localSettings.hasSeenMLEnablingBanner; Error? _syncError; @override @@ -112,8 +117,29 @@ class _StatusBarWidgetState extends State { _showErrorBanner ? HeaderErrorWidget(error: _syncError) : const SizedBox.shrink(), + _showMlBanner && !_showErrorBanner + ? Padding( + padding: + const EdgeInsets.symmetric(horizontal: 2.0, vertical: 12), + child: NotificationWidget( + startIcon: Icons.offline_bolt, + actionIcon: Icons.arrow_forward, + text: + "Enable machine learning for magic search and face recognition", + type: NotificationType.greenBanner, + onTap: () async => { + await routeToPage( + context, + const EnableMachineLearningConsent(), + forceCustomPageRoute: true, + ), + }, + ), + ) + : const SizedBox.shrink(), userRemoteFlagService.shouldShowRecoveryVerification() && - !_showErrorBanner + !_showErrorBanner && + !_showMlBanner ? Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12), @@ -138,7 +164,7 @@ class _StatusBarWidgetState extends State { } class SyncStatusWidget extends StatefulWidget { - const SyncStatusWidget({Key? key}) : super(key: key); + const SyncStatusWidget({super.key}); @override State createState() => _SyncStatusWidgetState(); @@ -195,7 +221,7 @@ class RefreshIndicatorWidget extends StatelessWidget { final SyncStatusUpdate? event; - const RefreshIndicatorWidget(this.event, {Key? key}) : super(key: key); + const RefreshIndicatorWidget(this.event, {super.key}); @override Widget build(BuildContext context) { @@ -275,7 +301,7 @@ class RefreshIndicatorWidget extends StatelessWidget { } class SyncStatusCompletedWidget extends StatelessWidget { - const SyncStatusCompletedWidget({Key? key}) : super(key: key); + const SyncStatusCompletedWidget({super.key}); @override Widget build(BuildContext context) { diff --git a/mobile/lib/ui/settings/ml/enable_ml_consent.dart b/mobile/lib/ui/settings/ml/enable_ml_consent.dart index 66ee553c81..ea11e132aa 100644 --- a/mobile/lib/ui/settings/ml/enable_ml_consent.dart +++ b/mobile/lib/ui/settings/ml/enable_ml_consent.dart @@ -1,4 +1,6 @@ import "package:flutter/material.dart"; +import "package:photos/core/event_bus.dart"; +import "package:photos/events/notification_event.dart"; import "package:photos/generated/l10n.dart"; import "package:photos/service_locator.dart"; import "package:photos/services/user_remote_flag_service.dart"; @@ -120,6 +122,8 @@ class _EnableMachineLearningConsentState buttonType: ButtonType.secondary, labelText: S.of(context).cancel, onTap: () async { + await localSettings.setHasSeenMLEnablingBanner(); + Bus.instance.fire(NotificationEvent()); Navigator.of(context).pop(); }, ), diff --git a/mobile/lib/utils/local_settings.dart b/mobile/lib/utils/local_settings.dart index e293375653..78923805f4 100644 --- a/mobile/lib/utils/local_settings.dart +++ b/mobile/lib/utils/local_settings.dart @@ -12,6 +12,7 @@ class LocalSettings { static const kCollectionSortPref = "collection_sort_pref"; static const kPhotoGridSize = "photo_grid_size"; static const _kisMLLocalIndexingEnabled = "ls.ml_local_indexing"; + static const _kHasSeenMLEnablingBanner = "ls.has_seen_ml_enabling_banner"; static const kRateUsShownCount = "rate_us_shown_count"; static const kEnableMultiplePart = "ls.enable_multiple_part"; static const kRateUsPromptThreshold = 2; @@ -75,6 +76,12 @@ class LocalSettings { return isMLLocalIndexingEnabled; } + bool get hasSeenMLEnablingBanner => + _prefs.getBool(_kHasSeenMLEnablingBanner) ?? false; + Future setHasSeenMLEnablingBanner() async { + await _prefs.setBool(_kHasSeenMLEnablingBanner, true); + } + //#region todo:(NG) remove this section, only needed for internal testing to see // if the OS stops the app during indexing bool get remoteFetchEnabled => _prefs.getBool("remoteFetchEnabled") ?? true;