diff --git a/packages/smooth_app/lib/data_models/user_preferences.dart b/packages/smooth_app/lib/data_models/user_preferences.dart index bf2bf7d675f8..e5b34f4b260e 100644 --- a/packages/smooth_app/lib/data_models/user_preferences.dart +++ b/packages/smooth_app/lib/data_models/user_preferences.dart @@ -9,11 +9,18 @@ class UserPreferences extends ChangeNotifier { UserPreferences._shared(final SharedPreferences sharedPreferences) : _sharedPreferences = sharedPreferences; + /// Singleton + static UserPreferences? _instance; final SharedPreferences _sharedPreferences; static Future getUserPreferences() async { - final SharedPreferences preferences = await SharedPreferences.getInstance(); - return UserPreferences._shared(preferences); + if (_instance == null) { + final SharedPreferences preferences = + await SharedPreferences.getInstance(); + _instance = UserPreferences._shared(preferences); + } + + return _instance!; } static const String _TAG_PREFIX_IMPORTANCE = 'IMPORTANCE_AS_STRING'; diff --git a/packages/smooth_app/lib/helpers/provider_helper.dart b/packages/smooth_app/lib/helpers/provider_helper.dart index 15cc1e04f2ac..9af48309ec6a 100644 --- a/packages/smooth_app/lib/helpers/provider_helper.dart +++ b/packages/smooth_app/lib/helpers/provider_helper.dart @@ -26,7 +26,7 @@ class _ListenerState extends SingleChildState> { @override Widget buildWithChild(BuildContext context, Widget? child) { final T? oldValue = _oldValue; - final T newValue = Provider.of(context); + final T newValue = context.watch(); _oldValue = newValue; widget.listener( diff --git a/packages/smooth_app/lib/l10n/app_en.arb b/packages/smooth_app/lib/l10n/app_en.arb index f3275f0f21af..01af3d8b3768 100644 --- a/packages/smooth_app/lib/l10n/app_en.arb +++ b/packages/smooth_app/lib/l10n/app_en.arb @@ -914,36 +914,6 @@ "@camera_settings_title": { "description": "Name of the camera section in the settings" }, - "camera_high_resolution_preset_toggle_title": "High performance mode", - "@camera_high_resolution_preset_toggle_title": { - "description": "Title for the Camera high resolution toggle" - }, - "camera_high_resolution_preset_toggle_subtitle": "When enabled, barcodes decoding quality should be better, but may impact performance and battery life. Requires an application restart.", - "@camera_high_resolution_preset_toggle_subtitle": { - "description": "SubTitle for the Camera high resolution toggle" - }, - "camera_focus_point_algorithm_title": "Focus mode", - "@camera_focus_point_algorithm_title": { - "description": "Title for the Camera focus mode (Android only)" - }, - "camera_focus_point_algorithm_subtitle": "Current mode: {mode}\n{reason}", - "@camera_focus_point_algorithm_subtitle": { - "description": "SubTitle for the Camera focus mode (Android only)", - "placeholders": { - "mode": { - "type": "String" - }, - "reason": { - "type": "String" - } - } - }, - "camera_focus_point_algorithm_value_auto_label": "Auto", - "camera_focus_point_algorithm_value_auto_description": "Let the system choose automatically between fast and safe modes.", - "camera_focus_point_algorithm_value_new_algorithm_label": "Fast mode", - "camera_focus_point_algorithm_value_new_algorithm_description": "A mode recommended to recent devices.", - "camera_focus_point_algorithm_value_old_algorithm_label": "Safe mode", - "camera_focus_point_algorithm_value_old_algorithm_description": "If fast mode doesn't work, this should resolve your focus issues.", "camera_play_sound_title": "Play a sound on scan", "@camera_play_sound_title": { "description": "Title for the Camera play sound toggle" @@ -956,7 +926,7 @@ "@camera_alternative_mode_title": { "description": "Title for the Alternative mode for the camera/scanner" }, - "camera_alternative_mode_subtitle": "If your device is unable to scan barcodes, please try this mode. If it works well, please communicate us your device name: {device}, in order to make this mode the default one for your device.", + "camera_alternative_mode_subtitle": "If your device is unable to scan barcodes, please try this mode.\n\nIf it works well, please communicate us your device name: {device}, in order to make this mode the default one for your device.", "@camera_alternative_mode_subtitle": { "description": "SubTitle for the Alternative mode for the camera/scanner", "placeholders": { @@ -969,14 +939,6 @@ "@camera_alternative_mode_confirm_dialog_title": { "description": "Title for the dialog explaining the alternative mode has changed" }, - "camera_alternative_mode_confirm_dialog_body": "The new mode will only be used after stopping, then relaunching the app!", - "@camera_alternative_mode_confirm_dialog_body": { - "description": "Content for the dialog explaining the alternative mode has changed = restart the app" - }, - "camera_alternative_mode_confirm_dialog_button": "Duly noted!", - "@camera_alternative_mode_confirm_dialog_button": { - "description": "Button for the dialog to confirm the user has understood" - }, "app_haptic_feedback_title": "Vibration & Haptics", "@app_haptic_feedback_title": { "description": "Title for the Haptic feedback toggle" diff --git a/packages/smooth_app/lib/pages/preferences/user_preferences_settings.dart b/packages/smooth_app/lib/pages/preferences/user_preferences_settings.dart index cea36e130cac..fb1c066bc695 100644 --- a/packages/smooth_app/lib/pages/preferences/user_preferences_settings.dart +++ b/packages/smooth_app/lib/pages/preferences/user_preferences_settings.dart @@ -4,7 +4,6 @@ import 'package:matomo_tracker/matomo_tracker.dart'; import 'package:provider/provider.dart'; import 'package:smooth_app/data_models/user_preferences.dart'; import 'package:smooth_app/generic_lib/design_constants.dart'; -import 'package:smooth_app/generic_lib/dialogs/smooth_alert_dialog.dart'; import 'package:smooth_app/generic_lib/widgets/language_selector.dart'; import 'package:smooth_app/helpers/analytics_helper.dart'; import 'package:smooth_app/helpers/camera_helper.dart'; @@ -289,34 +288,12 @@ class _CameraAlternativeModeSetting extends StatelessWidget { .camera_alternative_mode_subtitle(snapshot.data![1] as String), value: enabled, onChanged: (final bool value) { - _showWarningAfterChange(context); userPreferences.setUseAlternativeCameraMode(value); }, ); }, ); } - - void _showWarningAfterChange(BuildContext context) { - final AppLocalizations appLocalizations = AppLocalizations.of(context); - - showDialog( - context: context, - builder: (BuildContext subContext) { - return SmoothAlertDialog( - title: - appLocalizations.camera_alternative_mode_confirm_dialog_title, - body: Text( - appLocalizations.camera_alternative_mode_confirm_dialog_body, - ), - positiveAction: SmoothActionButton( - text: appLocalizations - .camera_alternative_mode_confirm_dialog_button, - onPressed: () => Navigator.pop(subContext), - ), - ); - }); - } } class _ProductsSettings extends StatelessWidget { diff --git a/packages/smooth_app/lib/pages/scan/camera_controller.dart b/packages/smooth_app/lib/pages/scan/camera_controller.dart index 3e9fddbc87d4..ada6d40b9df0 100644 --- a/packages/smooth_app/lib/pages/scan/camera_controller.dart +++ b/packages/smooth_app/lib/pages/scan/camera_controller.dart @@ -43,9 +43,14 @@ class SmoothCameraController extends CameraController { /// Listen to camera error events StreamSubscription? _errorListener; - // Last focus point position + /// Last focus point position Offset? _focusPoint; + /// Does the camera use the alternative mode (file based implementation)? + /// Enabled to [false] by default, as [changeImageMode] can be called, even if + /// [init] wasn't called before. + bool _persistToFileMode = false; + Future init({ required FocusMode focusMode, required Offset focusPoint, @@ -93,16 +98,36 @@ class SmoothCameraController extends CameraController { @protected Future startStream(onLatestImageAvailable onAvailable) async { - final bool useAlternativeCameraMode = - preferences.useAlternativeCameraMode ?? - await AlternativeCameraMode.isAWhitelistedDevice; + _persistToFileMode = preferences.useAlternativeCameraMode ?? + await AlternativeCameraMode.isAWhitelistedDevice; return startImageStream( onAvailable, - persistToFile: useAlternativeCameraMode, + persistToFile: _persistToFileMode, ); } + Future reloadImageMode() async { + final bool? alternativeCameraMode = preferences.useAlternativeCameraMode; + + /// Keep using the default value + if (alternativeCameraMode == null) { + return; + } + + if (alternativeCameraMode != _persistToFileMode) { + _persistToFileMode = alternativeCameraMode; + await changeImageMode(_persistToFileMode); + } + } + + /// Never use this method directly, use [reloadImageMode] instead + @protected + @override + Future changeImageMode(bool persistToFile) { + return super.changeImageMode(persistToFile); + } + /// Never use this method directly, by through [startStream] /// [persistToFile] is what we call the "alternative" mode @protected diff --git a/packages/smooth_app/lib/pages/scan/ml_kit_scan_page.dart b/packages/smooth_app/lib/pages/scan/ml_kit_scan_page.dart index 4734e5adaf6d..76616fe22bca 100644 --- a/packages/smooth_app/lib/pages/scan/ml_kit_scan_page.dart +++ b/packages/smooth_app/lib/pages/scan/ml_kit_scan_page.dart @@ -3,7 +3,7 @@ import 'dart:math' as math; import 'package:audioplayers/audioplayers.dart'; import 'package:camera/camera.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide Listener; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:matomo_tracker/matomo_tracker.dart'; @@ -14,6 +14,7 @@ import 'package:smooth_app/data_models/user_preferences.dart'; import 'package:smooth_app/helpers/camera_helper.dart'; import 'package:smooth_app/helpers/collections_helper.dart'; import 'package:smooth_app/helpers/haptic_feedback_helper.dart'; +import 'package:smooth_app/helpers/provider_helper.dart'; import 'package:smooth_app/pages/page_manager.dart'; import 'package:smooth_app/pages/preferences/user_preferences_dev_mode.dart'; import 'package:smooth_app/pages/scan/camera_controller.dart'; @@ -137,24 +138,30 @@ class MLKitScannerPageState extends LifecycleAwareState @override Widget build(BuildContext context) { - return Consumer( - builder: (BuildContext context, BottomNavigationTab tab, Widget? child) { - if (pendingResume && _isScreenVisible(tab: tab)) { - pendingResume = false; - _onResumeImageStream(); - } - - return child!; + return Listener( + listener: (_, __, UserPreferences prefs) { + _controller?.reloadImageMode(); }, - // [_startLiveFeed] is called both with [onResume] and [onPause] to cover - // all entry points - child: LifeCycleManager( - onStart: _startLiveFeed, - onResume: _onResumeImageStream, - onVisible: () => _onResumeImageStream(forceStartPreview: true), - onPause: _onPauseImageStream, - onInvisible: _onPauseImageStream, - child: _buildScannerWidget(), + child: Consumer( + builder: + (BuildContext context, BottomNavigationTab tab, Widget? child) { + if (pendingResume && _isScreenVisible(tab: tab)) { + pendingResume = false; + _onResumeImageStream(); + } + + return child!; + }, + // [_startLiveFeed] is called both with [onResume] and [onPause] to cover + // all entry points + child: LifeCycleManager( + onStart: _startLiveFeed, + onResume: _onResumeImageStream, + onVisible: () => _onResumeImageStream(forceStartPreview: true), + onPause: _onPauseImageStream, + onInvisible: _onPauseImageStream, + child: _buildScannerWidget(), + ), ), ); } diff --git a/packages/smooth_app/pubspec.lock b/packages/smooth_app/pubspec.lock index c9787866fa32..ddb26b90d493 100644 --- a/packages/smooth_app/pubspec.lock +++ b/packages/smooth_app/pubspec.lock @@ -139,7 +139,7 @@ packages: description: path: "packages/camera/camera" ref: smooth_camera - resolved-ref: "40497e4fc74a8512634e04c3c9d6a8c3a50284c0" + resolved-ref: "3c62b56bb6cc0ae1c9594f417ce6305ea45e214f" url: "https://github.com/g123k/plugins.git" source: git version: "0.9.6" @@ -148,7 +148,7 @@ packages: description: path: "packages/camera/camera_platform_interface" ref: smooth_camera - resolved-ref: "40497e4fc74a8512634e04c3c9d6a8c3a50284c0" + resolved-ref: "3c62b56bb6cc0ae1c9594f417ce6305ea45e214f" url: "https://github.com/g123k/plugins.git" source: git version: "2.1.6" @@ -157,7 +157,7 @@ packages: description: path: "packages/camera/camera_web" ref: smooth_camera - resolved-ref: "40497e4fc74a8512634e04c3c9d6a8c3a50284c0" + resolved-ref: "3c62b56bb6cc0ae1c9594f417ce6305ea45e214f" url: "https://github.com/g123k/plugins.git" source: git version: "0.2.1+6" @@ -300,7 +300,7 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.3" + version: "2.2.4" data_importer: dependency: "direct main" description: @@ -1366,7 +1366,7 @@ packages: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.18" + version: "6.0.19" url_launcher_ios: dependency: transitive description: diff --git a/packages/smooth_app/test/pages/goldens/user_preferences_page-brown-light.png b/packages/smooth_app/test/pages/goldens/user_preferences_page-brown-light.png deleted file mode 100644 index 5ef9a5fbbcb4..000000000000 Binary files a/packages/smooth_app/test/pages/goldens/user_preferences_page-brown-light.png and /dev/null differ diff --git a/packages/smooth_app/test/pages/goldens/user_preferences_page-light.png b/packages/smooth_app/test/pages/goldens/user_preferences_page-light.png index acabca0e0af5..6e74c8bb3ed2 100644 Binary files a/packages/smooth_app/test/pages/goldens/user_preferences_page-light.png and b/packages/smooth_app/test/pages/goldens/user_preferences_page-light.png differ diff --git a/packages/smooth_app/test/plural_translation_test.dart b/packages/smooth_app/test/plural_translation_test.dart index 5a4f72d8858b..fedb9bfd2201 100644 --- a/packages/smooth_app/test/plural_translation_test.dart +++ b/packages/smooth_app/test/plural_translation_test.dart @@ -145,16 +145,6 @@ void main() { appLocalizations.email_body_account_deletion(crazyString), contains(crazyString), ); - expect( - appLocalizations.camera_focus_point_algorithm_subtitle( - crazyString, ''), - contains(crazyString), - ); - expect( - appLocalizations.camera_focus_point_algorithm_subtitle( - '', crazyString), - contains(crazyString), - ); expect( appLocalizations.permission_photo_denied_message(crazyString), contains(crazyString),