From a52efcd3413b09b373e5e6aadc16302d0692d62c Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Tue, 31 Oct 2023 18:42:25 +0100 Subject: [PATCH 01/17] ML-130 Integrate Firebase Remote Config (#132) * implemented `RemoteConfigService` * added alternative translations * typo * added `firebase_analytics` * dim paid features list tiles * log list tile tap instead of dialog * implemented `RemoteConfigProvider` * typo --- lib/application_wrapper.dart | 25 +++-- lib/data/analytics/analytics.dart | 34 ++++++ .../api/analytics_api_interface.dart | 8 ++ .../analytics/api/analytics_firebase.dart | 26 +++++ .../analytics/entity/analytics_event.dart | 3 + lib/data/models/feature.dart | 5 + lib/data/remote_config_service.dart | 81 ++++++++++++++ lib/l10n/intl_en.arb | 6 +- lib/l10n/intl_fr.arb | 4 + lib/l10n/intl_ru.arb | 4 + lib/l10n/intl_zh.arb | 4 + lib/providers/remote_config_provider.dart | 78 +++++++++++++ lib/providers/services_provider.dart | 3 + .../buy_pro/widget_list_tile_buy_pro.dart | 24 +++- ...idget_settings_section_lightmeter_pro.dart | 6 +- .../iap_list_tile/widget_list_tile_iap.dart | 27 ++--- .../components/utils/show_buy_pro_dialog.dart | 13 ++- pubspec.yaml | 10 +- .../remote_config_provider_test.dart | 104 ++++++++++++++++++ 19 files changed, 425 insertions(+), 40 deletions(-) create mode 100644 lib/data/analytics/analytics.dart create mode 100644 lib/data/analytics/api/analytics_api_interface.dart create mode 100644 lib/data/analytics/api/analytics_firebase.dart create mode 100644 lib/data/analytics/entity/analytics_event.dart create mode 100644 lib/data/models/feature.dart create mode 100644 lib/data/remote_config_service.dart create mode 100644 lib/providers/remote_config_provider.dart create mode 100644 test/providers/remote_config_provider_test.dart diff --git a/lib/application_wrapper.dart b/lib/application_wrapper.dart index d2975d6..d28fbcf 100644 --- a/lib/application_wrapper.dart +++ b/lib/application_wrapper.dart @@ -1,13 +1,17 @@ import 'package:flutter/material.dart'; +import 'package:lightmeter/data/analytics/analytics.dart'; +import 'package:lightmeter/data/analytics/api/analytics_firebase.dart'; import 'package:lightmeter/data/caffeine_service.dart'; import 'package:lightmeter/data/haptics_service.dart'; import 'package:lightmeter/data/light_sensor_service.dart'; import 'package:lightmeter/data/permissions_service.dart'; +import 'package:lightmeter/data/remote_config_service.dart'; import 'package:lightmeter/data/shared_prefs_service.dart'; import 'package:lightmeter/data/volume_events_service.dart'; import 'package:lightmeter/environment.dart'; import 'package:lightmeter/providers/equipment_profile_provider.dart'; import 'package:lightmeter/providers/films_provider.dart'; +import 'package:lightmeter/providers/remote_config_provider.dart'; import 'package:lightmeter/providers/services_provider.dart'; import 'package:lightmeter/providers/user_preferences_provider.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; @@ -23,9 +27,10 @@ class ApplicationWrapper extends StatelessWidget { @override Widget build(BuildContext context) { return FutureBuilder( - future: Future.wait([ + future: Future.wait([ SharedPreferences.getInstance(), const LightSensorService(LocalPlatform()).hasSensor(), + const RemoteConfigService().activeAndFetchFeatures(), ]), builder: (_, snapshot) { if (snapshot.data != null) { @@ -33,6 +38,7 @@ class ApplicationWrapper extends StatelessWidget { final userPreferencesService = UserPreferencesService(snapshot.data![0] as SharedPreferences); final hasLightSensor = snapshot.data![1] as bool; return ServicesProvider( + analytics: const LightmeterAnalytics(api: LightmeterAnalyticsFirebase()), caffeineService: const CaffeineService(), environment: env.copyWith(hasLightSensor: hasLightSensor), hapticsService: const HapticsService(), @@ -40,14 +46,17 @@ class ApplicationWrapper extends StatelessWidget { permissionsService: const PermissionsService(), userPreferencesService: userPreferencesService, volumeEventsService: const VolumeEventsService(LocalPlatform()), - child: EquipmentProfileProvider( - storageService: iapService, - child: FilmsProvider( + child: RemoteConfigProvider( + remoteConfigService: const RemoteConfigService(), + child: EquipmentProfileProvider( storageService: iapService, - child: UserPreferencesProvider( - hasLightSensor: hasLightSensor, - userPreferencesService: userPreferencesService, - child: child, + child: FilmsProvider( + storageService: iapService, + child: UserPreferencesProvider( + hasLightSensor: hasLightSensor, + userPreferencesService: userPreferencesService, + child: child, + ), ), ), ), diff --git a/lib/data/analytics/analytics.dart b/lib/data/analytics/analytics.dart new file mode 100644 index 0000000..1bd6496 --- /dev/null +++ b/lib/data/analytics/analytics.dart @@ -0,0 +1,34 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:flutter/foundation.dart'; +import 'package:lightmeter/data/analytics/api/analytics_api_interface.dart'; +import 'package:lightmeter/data/analytics/entity/analytics_event.dart'; + +class LightmeterAnalytics { + final ILightmeterAnalyticsApi _api; + + const LightmeterAnalytics({required ILightmeterAnalyticsApi api}) : _api = api; + + Future logEvent( + LightmeterAnalyticsEvent event, { + Map? parameters, + }) async { + if (kDebugMode) { + log(' logEvent: ${event.name} / $parameters'); + return; + } + + return _api.logEvent( + event: event, + parameters: parameters, + ); + } + + Future logUnlockProFeatures(String listTileTitle) async { + return logEvent( + LightmeterAnalyticsEvent.unlockProFeatures, + parameters: {"listTileTitle": listTileTitle}, + ); + } +} diff --git a/lib/data/analytics/api/analytics_api_interface.dart b/lib/data/analytics/api/analytics_api_interface.dart new file mode 100644 index 0000000..1aa007f --- /dev/null +++ b/lib/data/analytics/api/analytics_api_interface.dart @@ -0,0 +1,8 @@ +import 'package:lightmeter/data/analytics/entity/analytics_event.dart'; + +abstract class ILightmeterAnalyticsApi { + Future logEvent({ + required LightmeterAnalyticsEvent event, + Map? parameters, + }); +} diff --git a/lib/data/analytics/api/analytics_firebase.dart b/lib/data/analytics/api/analytics_firebase.dart new file mode 100644 index 0000000..fb11d02 --- /dev/null +++ b/lib/data/analytics/api/analytics_firebase.dart @@ -0,0 +1,26 @@ +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/foundation.dart'; +import 'package:lightmeter/data/analytics/api/analytics_api_interface.dart'; +import 'package:lightmeter/data/analytics/entity/analytics_event.dart'; + +class LightmeterAnalyticsFirebase implements ILightmeterAnalyticsApi { + const LightmeterAnalyticsFirebase(); + + @override + Future logEvent({ + required LightmeterAnalyticsEvent event, + Map? parameters, + }) async { + try { + await FirebaseAnalytics.instance.logEvent( + name: event.name, + parameters: parameters, + ); + } on FirebaseException catch (e) { + debugPrint('Firebase Analytics Exception: $e'); + } catch (e) { + debugPrint(e.toString()); + } + } +} diff --git a/lib/data/analytics/entity/analytics_event.dart b/lib/data/analytics/entity/analytics_event.dart new file mode 100644 index 0000000..8275869 --- /dev/null +++ b/lib/data/analytics/entity/analytics_event.dart @@ -0,0 +1,3 @@ +enum LightmeterAnalyticsEvent { + unlockProFeatures, +} diff --git a/lib/data/models/feature.dart b/lib/data/models/feature.dart new file mode 100644 index 0000000..e4dc30e --- /dev/null +++ b/lib/data/models/feature.dart @@ -0,0 +1,5 @@ +enum Feature { unlockProFeaturesText } + +const featuresDefaultValues = { + Feature.unlockProFeaturesText: false, +}; diff --git a/lib/data/remote_config_service.dart b/lib/data/remote_config_service.dart new file mode 100644 index 0000000..9fc83fc --- /dev/null +++ b/lib/data/remote_config_service.dart @@ -0,0 +1,81 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +import 'package:firebase_remote_config/firebase_remote_config.dart'; +import 'package:flutter/foundation.dart'; +import 'package:lightmeter/data/models/feature.dart'; + +class RemoteConfigService { + const RemoteConfigService(); + + Future activeAndFetchFeatures() async { + final FirebaseRemoteConfig remoteConfig = FirebaseRemoteConfig.instance; + const cacheStaleDuration = kDebugMode ? Duration(minutes: 1) : Duration(hours: 12); + + try { + await remoteConfig.setConfigSettings( + RemoteConfigSettings( + fetchTimeout: const Duration(seconds: 15), + minimumFetchInterval: cacheStaleDuration, + ), + ); + await remoteConfig.setDefaults(featuresDefaultValues.map((key, value) => MapEntry(key.name, value))); + await remoteConfig.activate(); + await remoteConfig.ensureInitialized(); + unawaited(remoteConfig.fetch()); + + log('Firebase remote config initialized successfully'); + } on FirebaseException catch (e) { + _logError('Firebase exception during Firebase Remote Config initialization: $e'); + } on Exception catch (e) { + _logError('Error during Firebase Remote Config initialization: $e'); + } + } + + dynamic getValue(Feature feature) => FirebaseRemoteConfig.instance.getValue(feature.name).toValue(feature); + + Map getAll() { + final Map result = {}; + for (final value in FirebaseRemoteConfig.instance.getAll().entries) { + try { + final feature = Feature.values.firstWhere((f) => f.name == value.key); + result[feature] = value.value.toValue(feature); + } catch (e) { + log(e.toString()); + } + } + return result; + } + + Stream> onConfigUpdated() => FirebaseRemoteConfig.instance.onConfigUpdated.asyncMap( + (event) async { + await FirebaseRemoteConfig.instance.activate(); + final Set updatedFeatures = {}; + for (final key in event.updatedKeys) { + try { + updatedFeatures.add(Feature.values.firstWhere((element) => element.name == key)); + } catch (e) { + log(e.toString()); + } + } + return updatedFeatures; + }, + ); + + bool isEnabled(Feature feature) => FirebaseRemoteConfig.instance.getBool(feature.name); + + void _logError(dynamic throwable, {StackTrace? stackTrace}) { + FirebaseCrashlytics.instance.recordError(throwable, stackTrace); + } +} + +extension on RemoteConfigValue { + dynamic toValue(Feature feature) { + switch (feature) { + case Feature.unlockProFeaturesText: + return asBool(); + } + } +} diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 2f2fa27..57e91d2 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -92,10 +92,14 @@ } } }, - "buyLightmeterPro": "Buy Lightmeter Pro", "lightmeterPro": "Lightmeter Pro", + "buyLightmeterPro": "Buy Lightmeter Pro", "lightmeterProDescription": "Unlocks extra features, such as equipment profiles containing filters for aperture, shutter speed, and more; and a list of films with compensation for what's known as reciprocity failure.\n\nThe source code of Lightmeter is available on GitHub. You are welcome to compile it yourself. However, if you want to support the development and receive new features and updates, consider purchasing Lightmeter Pro.", "buy": "Buy", + "proFeatures": "Pro features", + "unlockProFeatures": "Unlock Pro features", + "unlockProFeaturesDescription": "Unlock professional features, such as equipment profiles containing filters for aperture, shutter speed, and more; and a list of films with compensation for what's known as reciprocity failure.\n\nBy unlocking Pro features you support the development and make it possible to add new features to the app.", + "unlock": "Unlock", "tooltipAdd": "Add", "tooltipClose": "Close", "tooltipExpand": "Expand", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 895b8e2..b1cd7fb 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -96,6 +96,10 @@ "lightmeterPro": "Lightmeter Pro", "lightmeterProDescription": "Déverrouille des fonctionnalités supplémentaires, telles que des profils d'équipement contenant des filtres pour l'ouverture, la vitesse d'obturation et plus encore, ainsi qu'une liste de films avec une compensation pour ce que l'on appelle l'échec de réciprocité.\n\nLe code source du Lightmeter est disponible sur GitHub. Vous pouvez le compiler vous-même. Cependant, si vous souhaitez soutenir le développement et recevoir de nouvelles fonctionnalités et mises à jour, envisagez d'acheter Lightmeter Pro.", "buy": "Acheter", + "proFeatures": "Fonctionnalités professionnelles", + "unlockProFeatures": "Déverrouiller les fonctionnalités professionnelles", + "unlockProFeaturesDescription": "Déverrouillez des fonctions professionnelles, telles que des profils d'équipement contenant des filtres pour l'ouverture, la vitesse d'obturation et plus encore, ainsi qu'une liste de films avec compensation pour ce que l'on appelle l'échec de réciprocité.\n\nEn débloquant les fonctionnalités Pro, vous soutenez le développement et permettez d'ajouter de nouvelles fonctionnalités à l'application.", + "unlock": "Déverrouiller", "tooltipAdd": "Ajouter", "tooltipClose": "Fermer", "tooltipExpand": "Élargir", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index f4c7b0b..a18cc9c 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -96,6 +96,10 @@ "lightmeterPro": "Lightmeter Pro", "lightmeterProDescription": "Даёт доступ к таким функциям как профили оборудования, содержащие фильтры для диафрагмы, выдержки и других значений, а также набору пленок с компенсацией эффекта Шварцшильда.\n\nИсходный код Lightmeter доступен на GitHub. Вы можете собрать его самостоятельно. Однако если вы хотите поддержать разработку и получать новые функции и обновления, то приобретите Lightmeter Pro.", "buy": "Купить", + "proFeatures": "Профессиональные настройки", + "unlockProFeatures": "Разблокировать профессиональные настройки", + "unlockProFeaturesDescription": "Вы можете разблокировать профессиональные настройки, такие как профили оборудования, содержащие фильтры для диафрагмы, выдержки и других значений, а также набору пленок с компенсацией эффекта Шварцшильда.\n\nПолучая доступ к профессиональным настройкам, вы поддерживаете разработку и делаете возможным появление новых функций в приложении.", + "unlock": "Разблокировать", "tooltipAdd": "Добавить", "tooltipClose": "Закрыть", "tooltipExpand": "Развернуть", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 0701781..5788ea9 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -96,6 +96,10 @@ "lightmeterPro": "Lightmeter Pro", "lightmeterProDescription": "购买以解锁额外功能。例如包含光圈、快门速度等参数的配置文件;以及一个胶卷预设列表来提供倒易率失效时的曝光补偿。\n\n您可以在 GitHub 上获取 Lightmeter 的源代码,欢迎自行编译。不过,如果您想支持开发并获得新功能和更新,请考虑购买 Lightmeter Pro。", "buy": "购买", + "proFeatures": "专业功能", + "unlockProFeatures": "解锁专业功能", + "unlockProFeaturesDescription": "解锁专业功能。例如包含光圈、快门速度等参数的配置文件;以及一个胶卷预设列表来提供倒易率失效时的曝光补偿。\n\n通过解锁专业版功能,您可以支持开发工作,帮助为应用程序添加新功能。", + "unlock": "解锁", "tooltipAdd": "添加", "tooltipClose": "关闭", "tooltipExpand": "展开", diff --git a/lib/providers/remote_config_provider.dart b/lib/providers/remote_config_provider.dart new file mode 100644 index 0000000..9736e1d --- /dev/null +++ b/lib/providers/remote_config_provider.dart @@ -0,0 +1,78 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/feature.dart'; +import 'package:lightmeter/data/remote_config_service.dart'; + +class RemoteConfigProvider extends StatefulWidget { + final RemoteConfigService remoteConfigService; + final Widget child; + + const RemoteConfigProvider({ + required this.remoteConfigService, + required this.child, + super.key, + }); + + @override + State createState() => RemoteConfigProviderState(); +} + +class RemoteConfigProviderState extends State { + late final Map _config = widget.remoteConfigService.getAll(); + late final StreamSubscription> _updatesSubscription; + + @override + void initState() { + super.initState(); + _updatesSubscription = widget.remoteConfigService.onConfigUpdated().listen(_updateFeatures); + } + + @override + void dispose() { + _updatesSubscription.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return RemoteConfig( + config: _config, + child: widget.child, + ); + } + + void _updateFeatures(Set updatedFeatures) { + for (final feature in updatedFeatures) { + _config[feature] = widget.remoteConfigService.getValue(feature); + } + setState(() {}); + } +} + +class RemoteConfig extends InheritedModel { + final Map _config; + + const RemoteConfig({ + super.key, + required Map config, + required super.child, + }) : _config = config; + + static bool isEnabled(BuildContext context, Feature feature) { + return InheritedModel.inheritFrom(context)!._config[feature] as bool; + } + + @override + bool updateShouldNotify(RemoteConfig oldWidget) => true; + + @override + bool updateShouldNotifyDependent(RemoteConfig oldWidget, Set features) { + for (final feature in features) { + if (oldWidget._config[feature] != _config[feature]) { + return true; + } + } + return false; + } +} diff --git a/lib/providers/services_provider.dart b/lib/providers/services_provider.dart index e65aa96..36f5674 100644 --- a/lib/providers/services_provider.dart +++ b/lib/providers/services_provider.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:lightmeter/data/analytics/analytics.dart'; import 'package:lightmeter/data/caffeine_service.dart'; import 'package:lightmeter/data/haptics_service.dart'; import 'package:lightmeter/data/light_sensor_service.dart'; @@ -9,6 +10,7 @@ import 'package:lightmeter/environment.dart'; // coverage:ignore-start class ServicesProvider extends InheritedWidget { + final LightmeterAnalytics analytics; final CaffeineService caffeineService; final Environment environment; final HapticsService hapticsService; @@ -18,6 +20,7 @@ class ServicesProvider extends InheritedWidget { final VolumeEventsService volumeEventsService; const ServicesProvider({ + required this.analytics, required this.caffeineService, required this.environment, required this.hapticsService, diff --git a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart index 11e8a4f..5f8adcd 100644 --- a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart +++ b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart @@ -1,20 +1,36 @@ import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/feature.dart'; import 'package:lightmeter/generated/l10n.dart'; -import 'package:lightmeter/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart'; +import 'package:lightmeter/providers/remote_config_provider.dart'; +import 'package:lightmeter/providers/services_provider.dart'; +import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/screens/settings/components/utils/show_buy_pro_dialog.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; class BuyProListTile extends StatelessWidget { const BuyProListTile({super.key}); @override Widget build(BuildContext context) { - return IAPListTile( + final unlockFeaturesEnabled = RemoteConfig.isEnabled(context, Feature.unlockProFeaturesText); + final status = IAPProducts.productOf(context, IAPProductType.paidFeatures)?.status; + final isPending = status == IAPProductStatus.purchased || status == null; + return ListTile( leading: const Icon(Icons.star), - title: Text(S.of(context).buyLightmeterPro), + title: Text(unlockFeaturesEnabled ? S.of(context).unlockProFeatures : S.of(context).buyLightmeterPro), onTap: () { showBuyProDialog(context); + ServicesProvider.of(context) + .analytics + .logUnlockProFeatures(unlockFeaturesEnabled ? 'Unlock Pro features' : 'Buy Lightmeter Pro'); }, - showPendingTrailing: true, + trailing: isPending + ? const SizedBox( + height: Dimens.grid24, + width: Dimens.grid24, + child: CircularProgressIndicator(), + ) + : null, ); } } diff --git a/lib/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart b/lib/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart index c060dc1..7050ae2 100644 --- a/lib/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart +++ b/lib/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/feature.dart'; import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/providers/remote_config_provider.dart'; import 'package:lightmeter/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart'; import 'package:lightmeter/screens/settings/components/shared/settings_section/widget_settings_section.dart'; @@ -9,7 +11,9 @@ class LightmeterProSettingsSection extends StatelessWidget { @override Widget build(BuildContext context) { return SettingsSection( - title: S.of(context).lightmeterPro, + title: RemoteConfig.isEnabled(context, Feature.unlockProFeaturesText) + ? S.of(context).proFeatures + : S.of(context).lightmeterPro, children: const [BuyProListTile()], ); } diff --git a/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart b/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart index cf65ade..a2b980f 100644 --- a/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart +++ b/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/res/dimens.dart'; -import 'package:lightmeter/screens/settings/components/utils/show_buy_pro_dialog.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; /// Depends on the product status and replaces [onTap] with purchase callback @@ -23,24 +22,14 @@ class IAPListTile extends StatelessWidget { @override Widget build(BuildContext context) { - final status = IAPProducts.productOf(context, IAPProductType.paidFeatures)?.status; - final isPending = status == IAPProductStatus.purchased || status == null; - return ListTile( - leading: leading, - title: title, - onTap: switch (status) { - IAPProductStatus.purchasable => () => showBuyProDialog(context), - IAPProductStatus.pending => null, - IAPProductStatus.purchased => onTap, - null => null, - }, - trailing: showPendingTrailing && isPending - ? const SizedBox( - height: Dimens.grid24, - width: Dimens.grid24, - child: CircularProgressIndicator(), - ) - : null, + final isPurchased = IAPProducts.isPurchased(context, IAPProductType.paidFeatures); + return Opacity( + opacity: isPurchased ? Dimens.enabledOpacity : Dimens.disabledOpacity, + child: ListTile( + leading: leading, + title: title, + onTap: isPurchased ? onTap : null, + ), ); } } diff --git a/lib/screens/settings/components/utils/show_buy_pro_dialog.dart b/lib/screens/settings/components/utils/show_buy_pro_dialog.dart index 0333570..50edbd1 100644 --- a/lib/screens/settings/components/utils/show_buy_pro_dialog.dart +++ b/lib/screens/settings/components/utils/show_buy_pro_dialog.dart @@ -1,17 +1,24 @@ import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/feature.dart'; import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/providers/remote_config_provider.dart'; import 'package:lightmeter/res/dimens.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; Future showBuyProDialog(BuildContext context) { + final unlockFeaturesEnabled = RemoteConfig.isEnabled(context, Feature.unlockProFeaturesText); return showDialog( context: context, builder: (_) => AlertDialog( icon: const Icon(Icons.star), titlePadding: Dimens.dialogIconTitlePadding, - title: Text(S.of(context).lightmeterPro), + title: Text(unlockFeaturesEnabled ? S.of(context).proFeatures : S.of(context).lightmeterPro), contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), - content: SingleChildScrollView(child: Text(S.of(context).lightmeterProDescription)), + content: SingleChildScrollView( + child: Text( + unlockFeaturesEnabled ? S.of(context).unlockProFeaturesDescription : S.of(context).lightmeterProDescription, + ), + ), actionsPadding: Dimens.dialogActionsPadding, actions: [ TextButton( @@ -23,7 +30,7 @@ Future showBuyProDialog(BuildContext context) { Navigator.of(context).pop(); IAPProductsProvider.of(context).buy(IAPProductType.paidFeatures); }, - child: Text(S.of(context).buy), + child: Text(unlockFeaturesEnabled ? S.of(context).unlock : S.of(context).buy), ), ], ), diff --git a/pubspec.yaml b/pubspec.yaml index 215f802..a7eb3a2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,8 +13,10 @@ dependencies: clipboard: 0.1.3 dynamic_color: 1.6.6 exif: 3.1.4 - firebase_core: 2.14.0 - firebase_crashlytics: 3.3.3 + firebase_analytics: 10.6.2 + firebase_core: 2.20.0 + firebase_crashlytics: 3.4.2 + firebase_remote_config: 4.3.2 flutter: sdk: flutter flutter_bloc: 8.1.3 @@ -26,7 +28,7 @@ dependencies: m3_lightmeter_iap: git: url: "https://github.com/vodemn/m3_lightmeter_iap" - ref: v0.5.0 + ref: v0.6.2 m3_lightmeter_resources: git: url: "https://github.com/vodemn/m3_lightmeter_resources" @@ -56,7 +58,7 @@ dev_dependencies: flutter: uses-material-design: true - assets: + assets: - assets/camera_stub_image.jpg flutter_intl: diff --git a/test/providers/remote_config_provider_test.dart b/test/providers/remote_config_provider_test.dart new file mode 100644 index 0000000..aa6815d --- /dev/null +++ b/test/providers/remote_config_provider_test.dart @@ -0,0 +1,104 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/data/models/feature.dart'; +import 'package:lightmeter/data/remote_config_service.dart'; +import 'package:lightmeter/providers/remote_config_provider.dart'; +import 'package:mocktail/mocktail.dart'; + +class _MockRemoteConfigService extends Mock implements RemoteConfigService {} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + late _MockRemoteConfigService mockRemoteConfigService; + + setUpAll(() { + mockRemoteConfigService = _MockRemoteConfigService(); + }); + + setUp(() { + when(() => mockRemoteConfigService.getValue(Feature.unlockProFeaturesText)).thenReturn(false); + when(() => mockRemoteConfigService.getAll()).thenReturn({Feature.unlockProFeaturesText: false}); + }); + + tearDown(() { + reset(mockRemoteConfigService); + }); + + Future pumpTestWidget(WidgetTester tester) async { + await tester.pumpWidget( + RemoteConfigProvider( + remoteConfigService: mockRemoteConfigService, + child: const _Application(), + ), + ); + } + + testWidgets( + 'RemoteConfigProvider init', + (tester) async { + when(() => mockRemoteConfigService.onConfigUpdated()).thenAnswer((_) => const Stream.empty()); + + await pumpTestWidget(tester); + expect(find.text('unlockProFeaturesText: false'), findsOneWidget); + }, + ); + + testWidgets( + 'RemoteConfigProvider updates stream', + (tester) async { + final StreamController> remoteConfigUpdateController = StreamController>(); + when(() => mockRemoteConfigService.onConfigUpdated()).thenAnswer((_) => remoteConfigUpdateController.stream); + + await pumpTestWidget(tester); + expect(find.text('unlockProFeaturesText: false'), findsOneWidget); + + when(() => mockRemoteConfigService.getValue(Feature.unlockProFeaturesText)).thenReturn(true); + remoteConfigUpdateController.add({Feature.unlockProFeaturesText}); + await tester.pumpAndSettle(); + expect(find.text('unlockProFeaturesText: true'), findsOneWidget); + + await remoteConfigUpdateController.close(); + }, + ); + + test('RemoteConfig.updateShouldNotifyDependent', () { + const config = RemoteConfig(config: {Feature.unlockProFeaturesText: false}, child: SizedBox()); + expect( + config.updateShouldNotifyDependent(config, {}), + false, + ); + expect( + config.updateShouldNotifyDependent( + const RemoteConfig(config: {Feature.unlockProFeaturesText: false}, child: SizedBox()), + {Feature.unlockProFeaturesText}, + ), + false, + ); + expect( + config.updateShouldNotifyDependent( + const RemoteConfig(config: {Feature.unlockProFeaturesText: true}, child: SizedBox()), + {Feature.unlockProFeaturesText}, + ), + true, + ); + }); +} + +class _Application extends StatelessWidget { + const _Application(); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + body: Center( + child: Text( + "${Feature.unlockProFeaturesText.name}: ${RemoteConfig.isEnabled(context, Feature.unlockProFeaturesText)}", + ), + ), + ), + ); + } +} From d36db97959ad8a337166ff53ff9ddfb34cee9711 Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Tue, 31 Oct 2023 22:32:02 +0100 Subject: [PATCH 02/17] Updated IAP version to fix network issue https://github.com/flutter/flutter/issues/135540 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index a7eb3a2..2d7730e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: m3_lightmeter_iap: git: url: "https://github.com/vodemn/m3_lightmeter_iap" - ref: v0.6.2 + ref: v0.6.3 m3_lightmeter_resources: git: url: "https://github.com/vodemn/m3_lightmeter_resources" From 37a3b79f04f4323ea26b9c3e7d0821b4daca5354 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 1 Nov 2023 10:16:41 +0000 Subject: [PATCH 03/17] Version bump --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 2d7730e..6fd97bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: lightmeter description: Lightmeter app inspired by Material 3 design system. publish_to: "none" -version: 0.15.1+42 +version: 0.15.2+43 environment: sdk: ">=3.0.0 <4.0.0" From 3bb3f12641398dc9274cc6f1fc9374f786ed1fce Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Thu, 2 Nov 2023 17:40:47 +0100 Subject: [PATCH 04/17] ML-62 Utils tests (#133) * removed redundant `UserPreferencesService` from `MeteringBloc` * wip * post-merge fixes * `MeasureEvent` tests * `MeasureEvent` tests revision * `MeasureEvent` tests added timeout * added stubs for other `MeteringBloc` events * rewritten `MeteringBloc` logic * wip * `IsoChangedEvent` tests * refined `IsoChangedEvent` tests * `NdChangedEvent` tests * `FilmChangedEvent` tests * `MeteringCommunicationBloc` tests * added test run to ci * overriden `==` for `MeasuredState` * `LuxMeteringEvent` tests * refined `LuxMeteringEvent` tests * rename * wip * wip * `InitializeEvent`/`DeinitializeEvent` tests * clamp minZoomLevel * fixed `MeteringCommunicationBloc` tests * wip * `ZoomChangedEvent` tests * `ExposureOffsetChangedEvent`/`ExposureOffsetResetEvent` tests * renamed test groups * added test coverage script * improved `CameraContainerBloc` test coverage * `EquipmentProfileChangedEvent` tests * verify response vibration * fixed running all tests * `MeteringCommunicationBloc` equality tests * `CameraContainerBloc` equality tests * removed generated code from coverage * `MeteringScreenLayoutFeature` tests * `SupportedLocale` tests * `Film` tests * `CaffeineService` tests * `UserPreferencesService` tests (wip) * `LightSensorService` tests (wip) * `migrateOldKeys()` tests * ignore currently unused getters & setters * gradle upgrade * `reset(sharedPreferences);` calls count * typo * `MeteringInteractor` tests * `SettingsInteractor` tests (wip) * `MeteringInteractor` tests (wip) * `SettingsInteractor` tests * AnimatedDialog picker standalone tests * Moved Animated dialog picker to widget tests * `ExtremeExposurePairsContainer` widget test * dialog picker test * Match extreme exposure pairs & pairs list edge values * `FilmPicker` widget tests * fixed animated dialog picker tests * add not hit files to coverage percentage * Moved `EquipmentProfileProvider` & `FilmsProvider` to the main repo * Synced _iap_ stub with repo * `FilmsProvider` tests * `EquipmentProfileProvider` tests * Pass `availableFilms` to `FilmsProvider` * `FilmPicker` tests * removed unnecessary imports * Metering layout features tests * split integration tests by screens * Films in use test * mock light meter lux stream * removed mockito mocks for integration tests From no on these are the only mocks in use: - Mock shared prefs initial values - Mock platform responses (camera/light sensor) * set sharedprefs mock without redundant group * unified granting camera permission on Android * fixed metering screen tests * extracted common values * `FilmPicker` integration tests * fixed light sensor platform mocks * wip * removed integration tests for now * moved screenshots generator to screenshots folder * typo * removed `MockIAPProductsProvider` * implemented platform mocks for unit tests * data/models/ 100% coverage * `IsoValuePicker` tests * `EquipmentProfileProvider` tests * extended PR check timeout * typo * added storage action verification for `FilmsProvider` tests * `UserPreferencesProvider` tests * Update README.md * added //coverage:ignore to `ServicesProvider` * typo * typo * `toStringSignedAsFixed` tests * `SelectableInheritedModel` tests * removed unused `TextLineHeight` util * `VolumeKeysNotifier` tests * import * `EquipmentProfileListener` tests * typo * split `EquipmentProfileListener` tests * `showBuyProDialog` tests * added `maybeOf` getter for iap stub --- .../src/providers/iap_products_provider.dart | 9 +- lib/data/volume_events_service.dart | 8 +- lib/providers/equipment_profile_provider.dart | 15 +- lib/screens/metering/bloc_metering.dart | 2 +- .../widget_slider_exposure_offset.dart | 2 +- lib/screens/metering/flow_metering.dart | 2 +- lib/screens/metering/screen_metering.dart | 2 +- ....dart => listener_equipment_profiles.dart} | 0 .../notifier_volume_keys.dart | 8 +- .../buy_pro/widget_list_tile_buy_pro.dart | 2 +- .../screen_equipment_profile.dart | 2 +- .../utils/show_buy_pro_dialog.dart | 2 +- lib/utils/text_line_height.dart | 5 - lib/utils/to_string_signed.dart | 11 +- pubspec.yaml | 2 +- test/function_mock.dart | 7 + .../interactors/metering_interactor_test.dart | 2 +- .../equipment_profile_provider_test.dart | 2 +- test/screens/metering/bloc_metering_test.dart | 2 +- .../shared/dialog_picker_test.dart | 9 +- .../listener_equipment_profiles_test.dart | 138 ++++++++++++++++++ .../utils/notifier_volume_keys_test.dart | 46 ++++++ .../utils/show_buy_pro_dialog_test.dart | 61 ++++++++ test/utils/selectable_provider_test.dart | 76 ++++++++++ test/utils/to_string_signed_test.dart | 16 ++ 25 files changed, 379 insertions(+), 52 deletions(-) rename lib/screens/metering/utils/{listsner_equipment_profiles.dart => listener_equipment_profiles.dart} (100%) rename lib/screens/metering/{components/shared/volume_keys_notifier => utils}/notifier_volume_keys.dart (82%) rename lib/screens/settings/{components => }/utils/show_buy_pro_dialog.dart (94%) delete mode 100644 lib/utils/text_line_height.dart create mode 100644 test/function_mock.dart create mode 100644 test/screens/metering/utils/listener_equipment_profiles_test.dart create mode 100644 test/screens/metering/utils/notifier_volume_keys_test.dart create mode 100644 test/screens/settings/utils/show_buy_pro_dialog_test.dart create mode 100644 test/utils/selectable_provider_test.dart create mode 100644 test/utils/to_string_signed_test.dart diff --git a/iap/lib/src/providers/iap_products_provider.dart b/iap/lib/src/providers/iap_products_provider.dart index 4895fdf..9d381ae 100644 --- a/iap/lib/src/providers/iap_products_provider.dart +++ b/iap/lib/src/providers/iap_products_provider.dart @@ -6,8 +6,10 @@ class IAPProductsProvider extends StatefulWidget { const IAPProductsProvider({required this.child, super.key}); - static IAPProductsProviderState of(BuildContext context) { - return context.findAncestorStateOfType()!; + static IAPProductsProviderState of(BuildContext context) => IAPProductsProvider.maybeOf(context)!; + + static IAPProductsProviderState? maybeOf(BuildContext context) { + return context.findAncestorStateOfType(); } @override @@ -54,8 +56,7 @@ class IAPProducts extends InheritedModel { bool updateShouldNotify(IAPProducts oldWidget) => false; @override - bool updateShouldNotifyDependent(IAPProducts oldWidget, Set dependencies) => - false; + bool updateShouldNotifyDependent(IAPProducts oldWidget, Set dependencies) => false; IAPProduct? _findProduct(IAPProductType type) { try { diff --git a/lib/data/volume_events_service.dart b/lib/data/volume_events_service.dart index d57936a..360de75 100644 --- a/lib/data/volume_events_service.dart +++ b/lib/data/volume_events_service.dart @@ -3,7 +3,7 @@ import 'package:flutter/services.dart'; import 'package:platform/platform.dart'; class VolumeEventsService { - final LocalPlatform localPlatform; + final LocalPlatform _localPlatform; @visibleForTesting static const volumeHandlingChannel = MethodChannel("com.vodemn.lightmeter/volumeHandling"); @@ -11,12 +11,12 @@ class VolumeEventsService { @visibleForTesting static const volumeEventsChannel = EventChannel("com.vodemn.lightmeter/volumeEvents"); - const VolumeEventsService(this.localPlatform); + const VolumeEventsService(this._localPlatform); /// If set to `false` we allow system to handle key events. /// Returns current status of volume handling. Future setVolumeHandling(bool enableHandling) async { - if (!localPlatform.isAndroid) { + if (!_localPlatform.isAndroid) { return false; } return volumeHandlingChannel @@ -29,7 +29,7 @@ class VolumeEventsService { /// KEYCODE_VOLUME_DOWN = 25; /// pressed Stream volumeButtonsEventStream() { - if (!localPlatform.isAndroid) { + if (!_localPlatform.isAndroid) { return const Stream.empty(); } return volumeEventsChannel diff --git a/lib/providers/equipment_profile_provider.dart b/lib/providers/equipment_profile_provider.dart index a5e0999..564c5ef 100644 --- a/lib/providers/equipment_profile_provider.dart +++ b/lib/providers/equipment_profile_provider.dart @@ -54,9 +54,7 @@ class EquipmentProfileProviderState extends State { _defaultProfile, if (IAPProducts.isPurchased(context, IAPProductType.paidFeatures)) ..._customProfiles, ], - selected: IAPProducts.isPurchased(context, IAPProductType.paidFeatures) - ? _selectedProfile - : _defaultProfile, + selected: IAPProducts.isPurchased(context, IAPProductType.paidFeatures) ? _selectedProfile : _defaultProfile, child: widget.child, ); } @@ -85,7 +83,7 @@ class EquipmentProfileProviderState extends State { _refreshSavedProfiles(); } - void updateProdile(EquipmentProfile data) { + void updateProfile(EquipmentProfile data) { final indexToUpdate = _customProfiles.indexWhere((element) => element.id == data.id); if (indexToUpdate >= 0) { _customProfiles[indexToUpdate] = data; @@ -118,13 +116,14 @@ class EquipmentProfiles extends SelectableInheritedModel { /// [_defaultProfile] + profiles created by the user static List of(BuildContext context) { - return InheritedModel.inheritFrom(context, aspect: SelectableAspect.list)! - .values; + return InheritedModel.inheritFrom(context, aspect: SelectableAspect.list)!.values; } static EquipmentProfile selectedOf(BuildContext context) { - return InheritedModel.inheritFrom(context, - aspect: SelectableAspect.selected,)! + return InheritedModel.inheritFrom( + context, + aspect: SelectableAspect.selected, + )! .selected; } } diff --git a/lib/screens/metering/bloc_metering.dart b/lib/screens/metering/bloc_metering.dart index cbb0356..753a7e7 100644 --- a/lib/screens/metering/bloc_metering.dart +++ b/lib/screens/metering/bloc_metering.dart @@ -10,9 +10,9 @@ import 'package:lightmeter/screens/metering/communication/event_communication_me as communication_events; import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; -import 'package:lightmeter/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart'; import 'package:lightmeter/screens/metering/event_metering.dart'; import 'package:lightmeter/screens/metering/state_metering.dart'; +import 'package:lightmeter/screens/metering/utils/notifier_volume_keys.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class MeteringBloc extends Bloc { diff --git a/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart b/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart index 484ee4b..40ec1f0 100644 --- a/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart +++ b/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart @@ -72,7 +72,7 @@ class _Ruler extends StatelessWidget { children: [ if (showValue) Text( - (index + min).toStringSigned(), + (index + min).toStringSignedAsFixed(0), style: Theme.of(context).textTheme.bodyLarge, ), const SizedBox(width: Dimens.grid8), diff --git a/lib/screens/metering/flow_metering.dart b/lib/screens/metering/flow_metering.dart index cca5675..f78482d 100644 --- a/lib/screens/metering/flow_metering.dart +++ b/lib/screens/metering/flow_metering.dart @@ -4,8 +4,8 @@ import 'package:lightmeter/interactors/metering_interactor.dart'; import 'package:lightmeter/providers/services_provider.dart'; import 'package:lightmeter/screens/metering/bloc_metering.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; -import 'package:lightmeter/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart'; import 'package:lightmeter/screens/metering/screen_metering.dart'; +import 'package:lightmeter/screens/metering/utils/notifier_volume_keys.dart'; class MeteringFlow extends StatefulWidget { const MeteringFlow({super.key}); diff --git a/lib/screens/metering/screen_metering.dart b/lib/screens/metering/screen_metering.dart index 6900159..380411f 100644 --- a/lib/screens/metering/screen_metering.dart +++ b/lib/screens/metering/screen_metering.dart @@ -13,7 +13,7 @@ import 'package:lightmeter/screens/metering/components/camera_container/provider import 'package:lightmeter/screens/metering/components/light_sensor_container/provider_container_light_sensor.dart'; import 'package:lightmeter/screens/metering/event_metering.dart'; import 'package:lightmeter/screens/metering/state_metering.dart'; -import 'package:lightmeter/screens/metering/utils/listsner_equipment_profiles.dart'; +import 'package:lightmeter/screens/metering/utils/listener_equipment_profiles.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class MeteringScreen extends StatelessWidget { diff --git a/lib/screens/metering/utils/listsner_equipment_profiles.dart b/lib/screens/metering/utils/listener_equipment_profiles.dart similarity index 100% rename from lib/screens/metering/utils/listsner_equipment_profiles.dart rename to lib/screens/metering/utils/listener_equipment_profiles.dart diff --git a/lib/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart b/lib/screens/metering/utils/notifier_volume_keys.dart similarity index 82% rename from lib/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart rename to lib/screens/metering/utils/notifier_volume_keys.dart index df64fdf..0c19955 100644 --- a/lib/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart +++ b/lib/screens/metering/utils/notifier_volume_keys.dart @@ -5,12 +5,12 @@ import 'package:lightmeter/data/models/volume_action.dart'; import 'package:lightmeter/data/volume_events_service.dart'; class VolumeKeysNotifier extends ChangeNotifier with RouteAware { - final VolumeEventsService volumeEventsService; + final VolumeEventsService _volumeEventsService; late final StreamSubscription _volumeKeysSubscription; VolumeKey _value = VolumeKey.up; - VolumeKeysNotifier(this.volumeEventsService) { - _volumeKeysSubscription = volumeEventsService + VolumeKeysNotifier(this._volumeEventsService) { + _volumeKeysSubscription = _volumeEventsService .volumeButtonsEventStream() .map((event) => event == 24 ? VolumeKey.up : VolumeKey.down) .listen((event) { @@ -19,6 +19,8 @@ class VolumeKeysNotifier extends ChangeNotifier with RouteAware { } VolumeKey get value => _value; + + @protected set value(VolumeKey newValue) { _value = newValue; notifyListeners(); diff --git a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart index 5f8adcd..854a914 100644 --- a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart +++ b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart @@ -4,7 +4,7 @@ import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/providers/remote_config_provider.dart'; import 'package:lightmeter/providers/services_provider.dart'; import 'package:lightmeter/res/dimens.dart'; -import 'package:lightmeter/screens/settings/components/utils/show_buy_pro_dialog.dart'; +import 'package:lightmeter/screens/settings/utils/show_buy_pro_dialog.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; class BuyProListTile extends StatelessWidget { diff --git a/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart index b10190f..6879a2c 100644 --- a/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart +++ b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart @@ -90,7 +90,7 @@ class _EquipmentProfilesScreenState extends State { } void _updateProfileAt(EquipmentProfile data) { - EquipmentProfileProvider.of(context).updateProdile(data); + EquipmentProfileProvider.of(context).updateProfile(data); } void _removeProfileAt(EquipmentProfile data) { diff --git a/lib/screens/settings/components/utils/show_buy_pro_dialog.dart b/lib/screens/settings/utils/show_buy_pro_dialog.dart similarity index 94% rename from lib/screens/settings/components/utils/show_buy_pro_dialog.dart rename to lib/screens/settings/utils/show_buy_pro_dialog.dart index 50edbd1..7ce3ff6 100644 --- a/lib/screens/settings/components/utils/show_buy_pro_dialog.dart +++ b/lib/screens/settings/utils/show_buy_pro_dialog.dart @@ -28,7 +28,7 @@ Future showBuyProDialog(BuildContext context) { FilledButton( onPressed: () { Navigator.of(context).pop(); - IAPProductsProvider.of(context).buy(IAPProductType.paidFeatures); + IAPProductsProvider.maybeOf(context)?.buy(IAPProductType.paidFeatures); }, child: Text(unlockFeaturesEnabled ? S.of(context).unlock : S.of(context).buy), ), diff --git a/lib/utils/text_line_height.dart b/lib/utils/text_line_height.dart deleted file mode 100644 index a531074..0000000 --- a/lib/utils/text_line_height.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/widgets.dart'; - -extension TextLineHeight on TextStyle { - double get lineHeight => fontSize! * height!; -} diff --git a/lib/utils/to_string_signed.dart b/lib/utils/to_string_signed.dart index 4122893..fcced8d 100644 --- a/lib/utils/to_string_signed.dart +++ b/lib/utils/to_string_signed.dart @@ -1,13 +1,4 @@ -extension SignedString on num { - String toStringSigned() { - if (this > 0) { - return "+${toString()}"; - } else { - return toString(); - } - } -} - +/// Returns value in form -1 or + 1. The only exception - 0. extension SignedStringDouble on double { String toStringSignedAsFixed(int fractionDigits) { if (this > 0) { diff --git a/pubspec.yaml b/pubspec.yaml index 6fd97bc..ed5fc90 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: m3_lightmeter_iap: git: url: "https://github.com/vodemn/m3_lightmeter_iap" - ref: v0.6.3 + ref: v0.7.0 m3_lightmeter_resources: git: url: "https://github.com/vodemn/m3_lightmeter_resources" diff --git a/test/function_mock.dart b/test/function_mock.dart new file mode 100644 index 0000000..8a4abfe --- /dev/null +++ b/test/function_mock.dart @@ -0,0 +1,7 @@ +import 'package:mocktail/mocktail.dart'; + +class _ValueChanged { + void onChanged(T value) {} +} + +class MockValueChanged extends Mock implements _ValueChanged {} diff --git a/test/interactors/metering_interactor_test.dart b/test/interactors/metering_interactor_test.dart index 1f0b05a..083a116 100644 --- a/test/interactors/metering_interactor_test.dart +++ b/test/interactors/metering_interactor_test.dart @@ -236,7 +236,7 @@ void main() { ); group( - 'Haptics', + 'Light sensor', () { test('hasAmbientLightSensor() - true', () async { when(() => mockLightSensorService.hasSensor()).thenAnswer((_) async => true); diff --git a/test/providers/equipment_profile_provider_test.dart b/test/providers/equipment_profile_provider_test.dart index 83f04f7..fb329cd 100644 --- a/test/providers/equipment_profile_provider_test.dart +++ b/test/providers/equipment_profile_provider_test.dart @@ -260,7 +260,7 @@ class _Application extends StatelessWidget { ElevatedButton( key: updateProfileButtonKey(profile.id), onPressed: () { - EquipmentProfileProvider.of(context).updateProdile( + EquipmentProfileProvider.of(context).updateProfile( profile.copyWith( name: '${profile.name} updated', isoValues: _customProfiles.first.isoValues, diff --git a/test/screens/metering/bloc_metering_test.dart b/test/screens/metering/bloc_metering_test.dart index fbffbbc..f07d35c 100644 --- a/test/screens/metering/bloc_metering_test.dart +++ b/test/screens/metering/bloc_metering_test.dart @@ -7,9 +7,9 @@ import 'package:lightmeter/screens/metering/communication/event_communication_me as communication_events; import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; -import 'package:lightmeter/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart'; import 'package:lightmeter/screens/metering/event_metering.dart'; import 'package:lightmeter/screens/metering/state_metering.dart'; +import 'package:lightmeter/screens/metering/utils/notifier_volume_keys.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; diff --git a/test/screens/metering/components/shared/readings_container/shared/dialog_picker_test.dart b/test/screens/metering/components/shared/readings_container/shared/dialog_picker_test.dart index 39c38ba..bd037af 100644 --- a/test/screens/metering/components/shared/readings_container/shared/dialog_picker_test.dart +++ b/test/screens/metering/components/shared/readings_container/shared/dialog_picker_test.dart @@ -7,16 +7,11 @@ import 'package:lightmeter/screens/metering/components/shared/readings_container import 'package:mocktail/mocktail.dart'; import '../../../../../../application_mock.dart'; +import '../../../../../../function_mock.dart'; import '../utils.dart'; -class _ValueChanged { - void onChanged(T value) {} -} - -class _MockValueChanged extends Mock implements _ValueChanged {} - void main() { - final functions = _MockValueChanged(); + final functions = MockValueChanged(); group( 'onChanged', diff --git a/test/screens/metering/utils/listener_equipment_profiles_test.dart b/test/screens/metering/utils/listener_equipment_profiles_test.dart new file mode 100644 index 0000000..ae6cb87 --- /dev/null +++ b/test/screens/metering/utils/listener_equipment_profiles_test.dart @@ -0,0 +1,138 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/providers/equipment_profile_provider.dart'; +import 'package:lightmeter/screens/metering/utils/listener_equipment_profiles.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; +import 'package:mocktail/mocktail.dart'; + +import '../../../function_mock.dart'; + +class _MockIAPStorageService extends Mock implements IAPStorageService {} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final storageService = _MockIAPStorageService(); + final equipmentProfileProviderKey = GlobalKey(); + final onDidChangeDependencies = MockValueChanged(); + + tearDown(() { + reset(onDidChangeDependencies); + reset(storageService); + }); + + Future pumpTestWidget(WidgetTester tester) async { + await tester.pumpWidget( + IAPProducts( + products: [ + IAPProduct( + storeId: IAPProductType.paidFeatures.storeId, + status: IAPProductStatus.purchased, + ), + ], + child: EquipmentProfileProvider( + key: equipmentProfileProviderKey, + storageService: storageService, + child: MaterialApp( + home: EquipmentProfileListener( + onDidChangeDependencies: onDidChangeDependencies.onChanged, + child: Builder(builder: (context) => Text(EquipmentProfiles.selectedOf(context).name)), + ), + ), + ), + ), + ); + } + + testWidgets( + 'Trigger `onDidChangeDependencies` by selecting a new profile', + (tester) async { + when(() => storageService.equipmentProfiles).thenReturn(List.from(_customProfiles)); + when(() => storageService.selectedEquipmentProfileId).thenReturn(''); + await pumpTestWidget(tester); + + equipmentProfileProviderKey.currentState!.setProfile(_customProfiles[0]); + await tester.pump(); + verify(() => onDidChangeDependencies.onChanged(_customProfiles[0])).called(1); + }, + ); + + testWidgets( + 'Trigger `onDidChangeDependencies` by updating the selected profile', + (tester) async { + when(() => storageService.equipmentProfiles).thenReturn(List.from(_customProfiles)); + when(() => storageService.selectedEquipmentProfileId).thenReturn(_customProfiles[0].id); + await pumpTestWidget(tester); + + final updatedProfile1 = _customProfiles[0].copyWith(name: 'Test 1 updated'); + equipmentProfileProviderKey.currentState!.updateProfile(updatedProfile1); + await tester.pump(); + verify(() => onDidChangeDependencies.onChanged(updatedProfile1)).called(1); + + /// Verify that updating the not selected profile doesn't trigger the callback + final updatedProfile2 = _customProfiles[1].copyWith(name: 'Test 2 updated'); + equipmentProfileProviderKey.currentState!.updateProfile(updatedProfile2); + await tester.pump(); + verifyNever(() => onDidChangeDependencies.onChanged(updatedProfile2)); + }, + ); + + testWidgets( + "Don't trigger `onDidChangeDependencies` by updating the unselected profile", + (tester) async { + when(() => storageService.equipmentProfiles).thenReturn(List.from(_customProfiles)); + when(() => storageService.selectedEquipmentProfileId).thenReturn(_customProfiles[0].id); + await pumpTestWidget(tester); + + final updatedProfile2 = _customProfiles[1].copyWith(name: 'Test 2 updated'); + equipmentProfileProviderKey.currentState!.updateProfile(updatedProfile2); + await tester.pump(); + verifyNever(() => onDidChangeDependencies.onChanged(updatedProfile2)); + }, + ); +} + +final List _customProfiles = [ + const EquipmentProfile( + id: '1', + name: 'Test 1', + apertureValues: [ + ApertureValue(4.0, StopType.full), + ApertureValue(4.5, StopType.third), + ApertureValue(4.8, StopType.half), + ApertureValue(5.0, StopType.third), + ApertureValue(5.6, StopType.full), + ApertureValue(6.3, StopType.third), + ApertureValue(6.7, StopType.half), + ApertureValue(7.1, StopType.third), + ApertureValue(8, StopType.full), + ], + ndValues: [ + NdValue(0), + NdValue(2), + NdValue(4), + NdValue(8), + NdValue(16), + NdValue(32), + NdValue(64), + ], + shutterSpeedValues: ShutterSpeedValue.values, + isoValues: [ + IsoValue(100, StopType.full), + IsoValue(125, StopType.third), + IsoValue(160, StopType.third), + IsoValue(200, StopType.full), + IsoValue(250, StopType.third), + IsoValue(320, StopType.third), + IsoValue(400, StopType.full), + ], + ), + const EquipmentProfile( + id: '2', + name: 'Test 2', + apertureValues: ApertureValue.values, + ndValues: NdValue.values, + shutterSpeedValues: ShutterSpeedValue.values, + isoValues: IsoValue.values, + ), +]; diff --git a/test/screens/metering/utils/notifier_volume_keys_test.dart b/test/screens/metering/utils/notifier_volume_keys_test.dart new file mode 100644 index 0000000..7bb6458 --- /dev/null +++ b/test/screens/metering/utils/notifier_volume_keys_test.dart @@ -0,0 +1,46 @@ +import 'dart:async'; + +import 'package:lightmeter/data/models/volume_action.dart'; +import 'package:lightmeter/data/volume_events_service.dart'; +import 'package:lightmeter/screens/metering/utils/notifier_volume_keys.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +import '../../../function_mock.dart'; + +class _MockVolumeEventsService extends Mock implements VolumeEventsService {} + +void main() { + late _MockVolumeEventsService mockVolumeEventsService; + + setUp(() { + mockVolumeEventsService = _MockVolumeEventsService(); + }); + + test( + 'Listen to `volumeButtonsEventStream()`', + () async { + final StreamController volumeButtonsEvents = StreamController(); + when(() => mockVolumeEventsService.volumeButtonsEventStream()).thenAnswer((_) => volumeButtonsEvents.stream); + + final volumeKeysNotifier = VolumeKeysNotifier(mockVolumeEventsService); + final functions = MockValueChanged(); + volumeKeysNotifier.addListener(() => functions.onChanged(volumeKeysNotifier.value)); + expect(volumeKeysNotifier.value, VolumeKey.up); + + volumeButtonsEvents.add(25); + volumeButtonsEvents.add(25); + volumeButtonsEvents.add(25); + volumeButtonsEvents.add(24); + volumeButtonsEvents.add(24); + volumeButtonsEvents.add(25); + await Future.delayed(Duration.zero); + verify(() => functions.onChanged(VolumeKey.up)).called(2); + verify(() => functions.onChanged(VolumeKey.down)).called(4); + + volumeKeysNotifier.removeListener(() => functions.onChanged(volumeKeysNotifier.value)); + await volumeKeysNotifier.dispose(); + await volumeButtonsEvents.close(); + }, + ); +} diff --git a/test/screens/settings/utils/show_buy_pro_dialog_test.dart b/test/screens/settings/utils/show_buy_pro_dialog_test.dart new file mode 100644 index 0000000..16a8e19 --- /dev/null +++ b/test/screens/settings/utils/show_buy_pro_dialog_test.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/data/models/feature.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/providers/remote_config_provider.dart'; +import 'package:lightmeter/screens/settings/utils/show_buy_pro_dialog.dart'; + +import '../../../application_mock.dart'; + +void main() { + Future pumpApplication(WidgetTester tester) async { + await tester.pumpWidget( + RemoteConfig( + config: const {Feature.unlockProFeaturesText: false}, + child: WidgetTestApplicationMock( + child: Builder( + builder: (context) => ElevatedButton( + onPressed: () => showBuyProDialog(context), + child: const SizedBox(), + ), + ), + ), + ), + ); + await tester.pumpAndSettle(); + } + + testWidgets( + '`showBuyProDialog` and buy', + (tester) async { + await pumpApplication(tester); + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text(S.current.lightmeterPro), findsOneWidget); + expect(find.text(S.current.cancel), findsOneWidget); + expect(find.text(S.current.buy), findsOneWidget); + + await tester.tap(find.text(S.current.buy)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsNothing); + }, + ); + + testWidgets( + '`showBuyProDialog` and cancel', + (tester) async { + await pumpApplication(tester); + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text(S.current.lightmeterPro), findsOneWidget); + expect(find.text(S.current.cancel), findsOneWidget); + expect(find.text(S.current.buy), findsOneWidget); + + await tester.tap(find.text(S.current.cancel)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsNothing); + }, + ); +} diff --git a/test/utils/selectable_provider_test.dart b/test/utils/selectable_provider_test.dart new file mode 100644 index 0000000..4ef2b96 --- /dev/null +++ b/test/utils/selectable_provider_test.dart @@ -0,0 +1,76 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/utils/selectable_provider.dart'; + +void main() { + group('SelectableInheritedModel.updateShouldNotifyDependent', () { + final model = SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 1, + child: const SizedBox(), + ); + + test( + '`{}`', + () { + expect( + model.updateShouldNotifyDependent( + SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 1, + child: const SizedBox(), + ), + {}, + ), + false, + ); + }, + ); + + test( + '`{SelectableAspect.list}`', + () { + expect( + model.updateShouldNotifyDependent( + SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 1, + child: const SizedBox(), + ), + {SelectableAspect.list}, + ), + true, + ); + }, + ); + + test( + '`{SelectableAspect.selected}`', + () { + expect( + model.updateShouldNotifyDependent( + SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 1, + child: const SizedBox(), + ), + {SelectableAspect.selected}, + ), + false, + ); + expect( + model.updateShouldNotifyDependent( + SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 2, + child: const SizedBox(), + ), + {SelectableAspect.selected}, + ), + true, + ); + }, + ); + }); +} diff --git a/test/utils/to_string_signed_test.dart b/test/utils/to_string_signed_test.dart new file mode 100644 index 0000000..8611204 --- /dev/null +++ b/test/utils/to_string_signed_test.dart @@ -0,0 +1,16 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/utils/to_string_signed.dart'; + +void main() { + test('toStringSignedAsFixed(0)', () { + expect(1.5.toStringSignedAsFixed(0), '+2'); + expect((-1.5).toStringSignedAsFixed(0), '-2'); + expect(0.0.toStringSignedAsFixed(0), '0'); + }); + + test('toStringSignedAsFixed(1)', () { + expect(1.5.toStringSignedAsFixed(1), '+1.5'); + expect((-1.5).toStringSignedAsFixed(1), '-1.5'); + expect(0.0.toStringSignedAsFixed(1), '0.0'); + }); +} From 068834bfe540040bd05a51582617246284ab885c Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Tue, 7 Nov 2023 11:57:36 +0100 Subject: [PATCH 05/17] ML-134 Firebase Remote Config issues (#135) * Unable to connect to the server * internal remote config fetch error * fixed tests --- lib/data/remote_config_service.dart | 7 ++++++- lib/providers/remote_config_provider.dart | 7 ++++++- test/providers/remote_config_provider_test.dart | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/data/remote_config_service.dart b/lib/data/remote_config_service.dart index 9fc83fc..8243dd2 100644 --- a/lib/data/remote_config_service.dart +++ b/lib/data/remote_config_service.dart @@ -24,7 +24,6 @@ class RemoteConfigService { await remoteConfig.setDefaults(featuresDefaultValues.map((key, value) => MapEntry(key.name, value))); await remoteConfig.activate(); await remoteConfig.ensureInitialized(); - unawaited(remoteConfig.fetch()); log('Firebase remote config initialized successfully'); } on FirebaseException catch (e) { @@ -34,6 +33,12 @@ class RemoteConfigService { } } + Future fetchConfig() async { + // https://github.com/firebase/flutterfire/issues/6196#issuecomment-927751667 + await Future.delayed(const Duration(seconds: 1)); + await FirebaseRemoteConfig.instance.fetch(); + } + dynamic getValue(Feature feature) => FirebaseRemoteConfig.instance.getValue(feature.name).toValue(feature); Map getAll() { diff --git a/lib/providers/remote_config_provider.dart b/lib/providers/remote_config_provider.dart index 9736e1d..a00b385 100644 --- a/lib/providers/remote_config_provider.dart +++ b/lib/providers/remote_config_provider.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:lightmeter/data/models/feature.dart'; @@ -25,7 +26,11 @@ class RemoteConfigProviderState extends State { @override void initState() { super.initState(); - _updatesSubscription = widget.remoteConfigService.onConfigUpdated().listen(_updateFeatures); + widget.remoteConfigService.fetchConfig(); + _updatesSubscription = widget.remoteConfigService.onConfigUpdated().listen( + _updateFeatures, + onError: (e) => log(e.toString()), + ); } @override diff --git a/test/providers/remote_config_provider_test.dart b/test/providers/remote_config_provider_test.dart index aa6815d..a215cbe 100644 --- a/test/providers/remote_config_provider_test.dart +++ b/test/providers/remote_config_provider_test.dart @@ -18,6 +18,7 @@ void main() { }); setUp(() { + when(() => mockRemoteConfigService.fetchConfig()).thenAnswer((_) async {}); when(() => mockRemoteConfigService.getValue(Feature.unlockProFeaturesText)).thenReturn(false); when(() => mockRemoteConfigService.getAll()).thenReturn({Feature.unlockProFeaturesText: false}); }); From 434327a7d0fbcc238580eeaf90f04ce01d8aaf0b Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Tue, 7 Nov 2023 12:03:38 +0100 Subject: [PATCH 06/17] Disable list tile `onTap` if IAP is pending --- .../buy_pro/widget_list_tile_buy_pro.dart | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart index 854a914..9854a14 100644 --- a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart +++ b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart @@ -18,12 +18,14 @@ class BuyProListTile extends StatelessWidget { return ListTile( leading: const Icon(Icons.star), title: Text(unlockFeaturesEnabled ? S.of(context).unlockProFeatures : S.of(context).buyLightmeterPro), - onTap: () { - showBuyProDialog(context); - ServicesProvider.of(context) - .analytics - .logUnlockProFeatures(unlockFeaturesEnabled ? 'Unlock Pro features' : 'Buy Lightmeter Pro'); - }, + onTap: !isPending + ? () { + showBuyProDialog(context); + ServicesProvider.of(context) + .analytics + .logUnlockProFeatures(unlockFeaturesEnabled ? 'Unlock Pro features' : 'Buy Lightmeter Pro'); + } + : null, trailing: isPending ? const SizedBox( height: Dimens.grid24, From ddc7ec8c8b2be7f0fb38f7ea5833599da1d26985 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 7 Nov 2023 11:15:17 +0000 Subject: [PATCH 07/17] Version bump --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index ed5fc90..eb53e59 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: lightmeter description: Lightmeter app inspired by Material 3 design system. publish_to: "none" -version: 0.15.2+43 +version: 0.15.3+44 environment: sdk: ">=3.0.0 <4.0.0" From 6566108994371f149720b330447422605227356b Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Sat, 11 Nov 2023 21:05:11 +0100 Subject: [PATCH 08/17] ML-129 Spot metering (#136) * imlemented `CameraSpotDetector` * separated generic `DialogSwitch` * added `CameraFeature` model * added `CameraFeaturesListTile` to metering section * added features dialog subtitles * added long press to remove metering spot * translations * hide camera features for purchasable status * hide `CameraHistogram` & `CameraSpotDetector` if purchasable * bumped iap version * fixed tests * removed redundant camera state emission * tests * Fixed remote config initalization * updated pro features description --- lib/application_wrapper.dart | 5 +- lib/data/models/camera_feature.dart | 13 +++ lib/data/models/feature.dart | 2 +- .../models/metering_screen_layout_config.dart | 33 +++++-- lib/data/remote_config_service.dart | 49 +++++++++- lib/data/shared_prefs_service.dart | 39 +++++--- lib/l10n/intl_en.arb | 10 +- lib/l10n/intl_fr.arb | 10 +- lib/l10n/intl_ru.arb | 10 +- lib/l10n/intl_zh.arb | 10 +- lib/providers/remote_config_provider.dart | 2 +- lib/providers/user_preferences_provider.dart | 55 ++++++----- lib/res/theme.dart | 14 ++- .../bloc_container_camera.dart | 18 ++-- .../widget_camera_spot_detector.dart | 71 ++++++++++++++ .../camera_view/widget_camera_view.dart | 21 ++-- .../camera_preview/widget_camera_preview.dart | 53 +++++++--- .../event_container_camera.dart | 18 ++++ .../widget_container_camera.dart | 3 + .../widget_list_tile_camera_features.dart | 45 +++++++++ ...ialog_metering_screen_layout_features.dart | 97 ------------------- ...dget_list_tile_metering_screen_layout.dart | 36 ++++++- .../widget_settings_section_metering.dart | 2 + .../dialog_switch/widget_dialog_switch.dart | 95 ++++++++++++++++++ .../settings/utils/show_buy_pro_dialog.dart | 31 +++++- lib/utils/map_model.dart | 26 +++++ pubspec.yaml | 2 +- screenshots/generate_screenshots.dart | 1 - .../models/camera_features_config_test.dart | 47 +++++++++ .../metering_screen_layout_config_test.dart | 11 +-- test/data/shared_prefs_service_test.dart | 68 +++++++++++-- .../user_preferences_provider_test.dart | 57 ++++++++++- .../camera/bloc_container_camera_test.dart | 59 ++++++----- .../camera/event_container_camera_test.dart | 21 ++++ 34 files changed, 783 insertions(+), 251 deletions(-) create mode 100644 lib/data/models/camera_feature.dart create mode 100644 lib/screens/metering/components/camera_container/components/camera_preview/components/camera_spot_detector/widget_camera_spot_detector.dart create mode 100644 lib/screens/settings/components/metering/components/camera_features/widget_list_tile_camera_features.dart delete mode 100644 lib/screens/settings/components/metering/components/metering_screen_layout/components/meterins_screen_layout_features_dialog/widget_dialog_metering_screen_layout_features.dart create mode 100644 lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart create mode 100644 lib/utils/map_model.dart create mode 100644 test/data/models/camera_features_config_test.dart diff --git a/lib/application_wrapper.dart b/lib/application_wrapper.dart index d28fbcf..ae7d1ae 100644 --- a/lib/application_wrapper.dart +++ b/lib/application_wrapper.dart @@ -30,7 +30,7 @@ class ApplicationWrapper extends StatelessWidget { future: Future.wait([ SharedPreferences.getInstance(), const LightSensorService(LocalPlatform()).hasSensor(), - const RemoteConfigService().activeAndFetchFeatures(), + if (env.buildType != BuildType.dev) const RemoteConfigService().activeAndFetchFeatures(), ]), builder: (_, snapshot) { if (snapshot.data != null) { @@ -47,7 +47,8 @@ class ApplicationWrapper extends StatelessWidget { userPreferencesService: userPreferencesService, volumeEventsService: const VolumeEventsService(LocalPlatform()), child: RemoteConfigProvider( - remoteConfigService: const RemoteConfigService(), + remoteConfigService: + env.buildType != BuildType.dev ? const RemoteConfigService() : const MockRemoteConfigService(), child: EquipmentProfileProvider( storageService: iapService, child: FilmsProvider( diff --git a/lib/data/models/camera_feature.dart b/lib/data/models/camera_feature.dart new file mode 100644 index 0000000..20193bf --- /dev/null +++ b/lib/data/models/camera_feature.dart @@ -0,0 +1,13 @@ +enum CameraFeature { + spotMetering, + histogram, +} + +typedef CameraFeaturesConfig = Map; + +extension CameraFeaturesConfigJson on CameraFeaturesConfig { + static CameraFeaturesConfig fromJson(Map data) => + {for (final f in CameraFeature.values) f: data[f.name] as bool? ?? false}; + + Map toJson() => map((key, value) => MapEntry(key.name, value)); +} diff --git a/lib/data/models/feature.dart b/lib/data/models/feature.dart index e4dc30e..b022db7 100644 --- a/lib/data/models/feature.dart +++ b/lib/data/models/feature.dart @@ -1,5 +1,5 @@ enum Feature { unlockProFeaturesText } const featuresDefaultValues = { - Feature.unlockProFeaturesText: false, + Feature.unlockProFeaturesText: true, }; diff --git a/lib/data/models/metering_screen_layout_config.dart b/lib/data/models/metering_screen_layout_config.dart index 7802195..7d550e4 100644 --- a/lib/data/models/metering_screen_layout_config.dart +++ b/lib/data/models/metering_screen_layout_config.dart @@ -1,18 +1,31 @@ enum MeteringScreenLayoutFeature { - extremeExposurePairs, - filmPicker, - histogram, - equipmentProfiles, + extremeExposurePairs, // 0 + filmPicker, // 1 + equipmentProfiles, // 3 } typedef MeteringScreenLayoutConfig = Map; extension MeteringScreenLayoutConfigJson on MeteringScreenLayoutConfig { - static MeteringScreenLayoutConfig fromJson(Map data) => - { - for (final f in MeteringScreenLayoutFeature.values) - f: data[f.index.toString()] as bool? ?? true - }; + static MeteringScreenLayoutConfig fromJson(Map data) { + int? migratedIndex(MeteringScreenLayoutFeature feature) { + switch (feature) { + case MeteringScreenLayoutFeature.extremeExposurePairs: + return 0; + case MeteringScreenLayoutFeature.filmPicker: + return 1; + case MeteringScreenLayoutFeature.equipmentProfiles: + return 3; + default: + return null; + } + } - Map toJson() => map((key, value) => MapEntry(key.index.toString(), value)); + return { + for (final f in MeteringScreenLayoutFeature.values) + f: (data[migratedIndex(f).toString()] ?? data[f.name]) as bool? ?? true + }; + } + + Map toJson() => map((key, value) => MapEntry(key.name, value)); } diff --git a/lib/data/remote_config_service.dart b/lib/data/remote_config_service.dart index 8243dd2..f8c123b 100644 --- a/lib/data/remote_config_service.dart +++ b/lib/data/remote_config_service.dart @@ -7,9 +7,26 @@ import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:flutter/foundation.dart'; import 'package:lightmeter/data/models/feature.dart'; -class RemoteConfigService { +abstract class IRemoteConfigService { + const IRemoteConfigService(); + + Future activeAndFetchFeatures(); + + Future fetchConfig(); + + dynamic getValue(Feature feature); + + Map getAll(); + + Stream> onConfigUpdated(); + + bool isEnabled(Feature feature); +} + +class RemoteConfigService implements IRemoteConfigService { const RemoteConfigService(); + @override Future activeAndFetchFeatures() async { final FirebaseRemoteConfig remoteConfig = FirebaseRemoteConfig.instance; const cacheStaleDuration = kDebugMode ? Duration(minutes: 1) : Duration(hours: 12); @@ -28,19 +45,22 @@ class RemoteConfigService { log('Firebase remote config initialized successfully'); } on FirebaseException catch (e) { _logError('Firebase exception during Firebase Remote Config initialization: $e'); - } on Exception catch (e) { + } catch (e) { _logError('Error during Firebase Remote Config initialization: $e'); } } + @override Future fetchConfig() async { // https://github.com/firebase/flutterfire/issues/6196#issuecomment-927751667 await Future.delayed(const Duration(seconds: 1)); await FirebaseRemoteConfig.instance.fetch(); } + @override dynamic getValue(Feature feature) => FirebaseRemoteConfig.instance.getValue(feature.name).toValue(feature); + @override Map getAll() { final Map result = {}; for (final value in FirebaseRemoteConfig.instance.getAll().entries) { @@ -54,6 +74,7 @@ class RemoteConfigService { return result; } + @override Stream> onConfigUpdated() => FirebaseRemoteConfig.instance.onConfigUpdated.asyncMap( (event) async { await FirebaseRemoteConfig.instance.activate(); @@ -69,6 +90,7 @@ class RemoteConfigService { }, ); + @override bool isEnabled(Feature feature) => FirebaseRemoteConfig.instance.getBool(feature.name); void _logError(dynamic throwable, {StackTrace? stackTrace}) { @@ -76,6 +98,29 @@ class RemoteConfigService { } } +class MockRemoteConfigService implements IRemoteConfigService { + const MockRemoteConfigService(); + + @override + Future activeAndFetchFeatures() async {} + + @override + Future fetchConfig() async {} + + @override + Map getAll() => featuresDefaultValues; + + @override + dynamic getValue(Feature feature) => featuresDefaultValues[feature]; + + @override + // ignore: cast_nullable_to_non_nullable + bool isEnabled(Feature feature) => featuresDefaultValues[feature] as bool; + + @override + Stream> onConfigUpdated() => const Stream.empty(); +} + extension on RemoteConfigValue { dynamic toValue(Feature feature) { switch (feature) { diff --git a/lib/data/shared_prefs_service.dart b/lib/data/shared_prefs_service.dart index 96d7d9d..443f2e5 100644 --- a/lib/data/shared_prefs_service.dart +++ b/lib/data/shared_prefs_service.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/camera_feature.dart'; import 'package:lightmeter/data/models/ev_source_type.dart'; import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; import 'package:lightmeter/data/models/supported_locale.dart'; @@ -18,6 +19,7 @@ class UserPreferencesService { static const cameraEvCalibrationKey = "cameraEvCalibration"; static const lightSensorEvCalibrationKey = "lightSensorEvCalibration"; static const meteringScreenLayoutKey = "meteringScreenLayout"; + static const cameraFeaturesKey = "cameraFeatures"; static const caffeineKey = "caffeine"; static const hapticsKey = "haptics"; @@ -70,16 +72,13 @@ class UserPreferencesService { } } - IsoValue get iso => - IsoValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(isoKey) ?? 100)); + IsoValue get iso => IsoValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(isoKey) ?? 100)); set iso(IsoValue value) => _sharedPreferences.setInt(isoKey, value.value); - NdValue get ndFilter => - NdValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(ndFilterKey) ?? 0)); + NdValue get ndFilter => NdValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(ndFilterKey) ?? 0)); set ndFilter(NdValue value) => _sharedPreferences.setInt(ndFilterKey, value.value); - EvSourceType get evSourceType => - EvSourceType.values[_sharedPreferences.getInt(evSourceTypeKey) ?? 0]; + EvSourceType get evSourceType => EvSourceType.values[_sharedPreferences.getInt(evSourceTypeKey) ?? 0]; set evSourceType(EvSourceType value) => _sharedPreferences.setInt(evSourceTypeKey, value.index); StopType get stopType => StopType.values[_sharedPreferences.getInt(stopTypeKey) ?? 2]; @@ -96,7 +95,6 @@ class UserPreferencesService { MeteringScreenLayoutFeature.equipmentProfiles: true, MeteringScreenLayoutFeature.extremeExposurePairs: true, MeteringScreenLayoutFeature.filmPicker: true, - MeteringScreenLayoutFeature.histogram: true, }; } } @@ -104,6 +102,21 @@ class UserPreferencesService { set meteringScreenLayout(MeteringScreenLayoutConfig value) => _sharedPreferences.setString(meteringScreenLayoutKey, json.encode(value.toJson())); + CameraFeaturesConfig get cameraFeatures { + final configJson = _sharedPreferences.getString(cameraFeaturesKey); + if (configJson != null) { + return CameraFeaturesConfigJson.fromJson(json.decode(configJson) as Map); + } else { + return { + CameraFeature.spotMetering: false, + CameraFeature.histogram: false, + }; + } + } + + set cameraFeatures(CameraFeaturesConfig value) => + _sharedPreferences.setString(cameraFeaturesKey, json.encode(value.toJson())); + bool get caffeine => _sharedPreferences.getBool(caffeineKey) ?? false; set caffeine(bool value) => _sharedPreferences.setBool(caffeineKey, value); @@ -114,8 +127,7 @@ class UserPreferencesService { (e) => e.toString() == _sharedPreferences.getString(volumeActionKey), orElse: () => VolumeAction.shutter, ); - set volumeAction(VolumeAction value) => - _sharedPreferences.setString(volumeActionKey, value.toString()); + set volumeAction(VolumeAction value) => _sharedPreferences.setString(volumeActionKey, value.toString()); SupportedLocale get locale => SupportedLocale.values.firstWhere( (e) => e.toString() == _sharedPreferences.getString(localeKey), @@ -124,13 +136,10 @@ class UserPreferencesService { set locale(SupportedLocale value) => _sharedPreferences.setString(localeKey, value.toString()); double get cameraEvCalibration => _sharedPreferences.getDouble(cameraEvCalibrationKey) ?? 0.0; - set cameraEvCalibration(double value) => - _sharedPreferences.setDouble(cameraEvCalibrationKey, value); + set cameraEvCalibration(double value) => _sharedPreferences.setDouble(cameraEvCalibrationKey, value); - double get lightSensorEvCalibration => - _sharedPreferences.getDouble(lightSensorEvCalibrationKey) ?? 0.0; - set lightSensorEvCalibration(double value) => - _sharedPreferences.setDouble(lightSensorEvCalibrationKey, value); + double get lightSensorEvCalibration => _sharedPreferences.getDouble(lightSensorEvCalibrationKey) ?? 0.0; + set lightSensorEvCalibration(double value) => _sharedPreferences.setDouble(lightSensorEvCalibrationKey, value); ThemeType get themeType => ThemeType.values[_sharedPreferences.getInt(themeTypeKey) ?? 0]; set themeType(ThemeType value) => _sharedPreferences.setInt(themeTypeKey, value.index); diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 57e91d2..02bb95a 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -39,7 +39,11 @@ "meteringScreenLayoutHintEquipmentProfiles": "Equipment profile picker", "meteringScreenFeatureExtremeExposurePairs": "Fastest & shortest exposure pairs", "meteringScreenFeatureFilmPicker": "Film picker", - "meteringScreenFeatureHistogram": "Histogram", + "cameraFeatures": "Camera features", + "cameraFeatureSpotMetering": "Spot metering", + "cameraFeatureSpotMeteringHint": "Long press the camera view to remove metering spot", + "cameraFeatureHistogram": "Histogram", + "cameraFeatureHistogramHint": "Enabling histogram can encrease battery drain", "film": "Film", "filmPush": "Film (push)", "filmPull": "Film (pull)", @@ -94,11 +98,11 @@ }, "lightmeterPro": "Lightmeter Pro", "buyLightmeterPro": "Buy Lightmeter Pro", - "lightmeterProDescription": "Unlocks extra features, such as equipment profiles containing filters for aperture, shutter speed, and more; and a list of films with compensation for what's known as reciprocity failure.\n\nThe source code of Lightmeter is available on GitHub. You are welcome to compile it yourself. However, if you want to support the development and receive new features and updates, consider purchasing Lightmeter Pro.", + "lightmeterProDescription": "Unlocks extra features:\n \u2022 Equipment profiles containing filters for aperture, shutter speed, and more\n \u2022 List of films with compensation for what's known as reciprocity failure\n \u2022 Spot metering\n \u2022 Histogram\n\nThe source code of Lightmeter is available on GitHub. You are welcome to compile it yourself. However, if you want to support the development and receive new features and updates, consider purchasing Lightmeter Pro.", "buy": "Buy", "proFeatures": "Pro features", "unlockProFeatures": "Unlock Pro features", - "unlockProFeaturesDescription": "Unlock professional features, such as equipment profiles containing filters for aperture, shutter speed, and more; and a list of films with compensation for what's known as reciprocity failure.\n\nBy unlocking Pro features you support the development and make it possible to add new features to the app.", + "unlockProFeaturesDescription": "Unlock professional features:\n \u2022 Equipment profiles containing filters for aperture, shutter speed, and more\n \u2022 List of films with compensation for what's known as reciprocity failure\n \u2022 Spot metering\n \u2022 Histogram\n\nBy unlocking Pro features you support the development and make it possible to add new features to the app.", "unlock": "Unlock", "tooltipAdd": "Add", "tooltipClose": "Close", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index b1cd7fb..f8b52c3 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -39,7 +39,11 @@ "meteringScreenLayoutHintEquipmentProfiles": "Sélecteur de profil de l'équipement", "meteringScreenFeatureExtremeExposurePairs": "Paires d'exposition les plus rapides et les plus courtes", "meteringScreenFeatureFilmPicker": "Sélecteur de film", - "meteringScreenFeatureHistogram": "Histogramme", + "cameraFeatures": "Fonctionnalités de la caméra", + "cameraFeatureSpotMetering": "Mesure spot", + "cameraFeatureSpotMeteringHint": "Appuyez longuement sur la vue de l'appareil photo pour supprimer le spot de mesure", + "cameraFeatureHistogram": "Histogramme", + "cameraFeatureHistogramHint": "L'activation de l'histogramme peut augmenter la consommation de la batterie", "film": "Pellicule", "filmPush": "Pellicule (push)", "filmPull": "Pellicule (pull)", @@ -94,11 +98,11 @@ }, "buyLightmeterPro": "Acheter Lightmeter Pro", "lightmeterPro": "Lightmeter Pro", - "lightmeterProDescription": "Déverrouille des fonctionnalités supplémentaires, telles que des profils d'équipement contenant des filtres pour l'ouverture, la vitesse d'obturation et plus encore, ainsi qu'une liste de films avec une compensation pour ce que l'on appelle l'échec de réciprocité.\n\nLe code source du Lightmeter est disponible sur GitHub. Vous pouvez le compiler vous-même. Cependant, si vous souhaitez soutenir le développement et recevoir de nouvelles fonctionnalités et mises à jour, envisagez d'acheter Lightmeter Pro.", + "lightmeterProDescription": "Débloque des fonctionnalités supplémentaires:\n \u2022 Profils d'équipement contenant des filtres pour l'ouverture, la vitesse d'obturation et plus encore\n \u2022 Liste de films avec une compensation pour ce que l'on appelle l'échec de réciprocité\n \u2022 Mesure spot\n \u2022 Histogramme\n\nLe code source du Lightmeter est disponible sur GitHub. Vous pouvez le compiler vous-même. Cependant, si vous souhaitez soutenir le développement et recevoir de nouvelles fonctionnalités et mises à jour, envisagez d'acheter Lightmeter Pro.", "buy": "Acheter", "proFeatures": "Fonctionnalités professionnelles", "unlockProFeatures": "Déverrouiller les fonctionnalités professionnelles", - "unlockProFeaturesDescription": "Déverrouillez des fonctions professionnelles, telles que des profils d'équipement contenant des filtres pour l'ouverture, la vitesse d'obturation et plus encore, ainsi qu'une liste de films avec compensation pour ce que l'on appelle l'échec de réciprocité.\n\nEn débloquant les fonctionnalités Pro, vous soutenez le développement et permettez d'ajouter de nouvelles fonctionnalités à l'application.", + "unlockProFeaturesDescription": "Déverrouillez des fonctions professionnelles:\n \u2022 Profils d'équipement contenant des filtres pour l'ouverture, la vitesse d'obturation et plus encore, ainsi qu'une liste de films avec compensation pour ce que l'on appelle l'échec de réciprocité\n \u2022 Mesure spot\n \u2022 Histogramme\n\nEn débloquant les fonctionnalités Pro, vous soutenez le développement et permettez d'ajouter de nouvelles fonctionnalités à l'application.", "unlock": "Déverrouiller", "tooltipAdd": "Ajouter", "tooltipClose": "Fermer", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index a18cc9c..f25dc8e 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -39,7 +39,11 @@ "meteringScreenLayoutHintEquipmentProfiles": "Выбор профиля оборудования", "meteringScreenFeatureExtremeExposurePairs": "Длинная и короткая выдержки", "meteringScreenFeatureFilmPicker": "Выбор пленки", - "meteringScreenFeatureHistogram": "Гистограмма", + "cameraFeatures": "Возможности камеры", + "cameraFeatureSpotMetering": "Точечный замер", + "cameraFeatureSpotMeteringHint": "Используйте долгое нажатие, чтобы удалить точку замера", + "cameraFeatureHistogram": "Гистограмма", + "cameraFeatureHistogramHint": "Использование гистограммы может увеличить расход аккумулятора", "film": "Пленка", "filmPush": "Пленка (push)", "filmPull": "Пленка (pull)", @@ -94,11 +98,11 @@ }, "buyLightmeterPro": "Купить Lightmeter Pro", "lightmeterPro": "Lightmeter Pro", - "lightmeterProDescription": "Даёт доступ к таким функциям как профили оборудования, содержащие фильтры для диафрагмы, выдержки и других значений, а также набору пленок с компенсацией эффекта Шварцшильда.\n\nИсходный код Lightmeter доступен на GitHub. Вы можете собрать его самостоятельно. Однако если вы хотите поддержать разработку и получать новые функции и обновления, то приобретите Lightmeter Pro.", + "lightmeterProDescription": "Даёт доступ к различным функциям:\n \u2022 Профили оборудования, содержащие фильтры для диафрагмы, выдержки и других значений\n \u2022 Список пленок с компенсацией эффекта Шварцшильда\n \u2022 Точечный замер\n \u2022 Гистограмма\n\nИсходный код Lightmeter доступен на GitHub. Вы можете собрать его самостоятельно. Однако если вы хотите поддержать разработку и получать новые функции и обновления, то приобретите Lightmeter Pro.", "buy": "Купить", "proFeatures": "Профессиональные настройки", "unlockProFeatures": "Разблокировать профессиональные настройки", - "unlockProFeaturesDescription": "Вы можете разблокировать профессиональные настройки, такие как профили оборудования, содержащие фильтры для диафрагмы, выдержки и других значений, а также набору пленок с компенсацией эффекта Шварцшильда.\n\nПолучая доступ к профессиональным настройкам, вы поддерживаете разработку и делаете возможным появление новых функций в приложении.", + "unlockProFeaturesDescription": "Вы можете разблокировать профессиональные настройки:\n \u2022 Профили оборудования, содержащие фильтры для диафрагмы, выдержки и других значений\n \u2022 Список пленок с компенсацией эффекта Шварцшильда\n \u2022 Точечный замер\n \u2022 Гистограмма\n\nПолучая доступ к профессиональным настройкам, вы поддерживаете разработку и делаете возможным появление новых функций в приложении.", "unlock": "Разблокировать", "tooltipAdd": "Добавить", "tooltipClose": "Закрыть", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 5788ea9..714c4b3 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -39,7 +39,11 @@ "meteringScreenLayoutHintEquipmentProfiles": "设备配置选择", "meteringScreenFeatureExtremeExposurePairs": "最快 & 最慢曝光组合", "meteringScreenFeatureFilmPicker": "胶片选择", - "meteringScreenFeatureHistogram": "直方图", + "cameraFeatures": "相机功能", + "cameraFeatureSpotMetering": "点测光", + "cameraFeatureSpotMeteringHint": "长按相机视图可移除测光点", + "cameraFeatureHistogram": "直方图", + "cameraFeatureHistogramHint": "启用直方图会增加电池消耗", "film": "胶片", "filmPush": "胶片 (push)", "filmPull": "胶片 (pull)", @@ -94,11 +98,11 @@ }, "buyLightmeterPro": "购买 Lightmeter Pro", "lightmeterPro": "Lightmeter Pro", - "lightmeterProDescription": "购买以解锁额外功能。例如包含光圈、快门速度等参数的配置文件;以及一个胶卷预设列表来提供倒易率失效时的曝光补偿。\n\n您可以在 GitHub 上获取 Lightmeter 的源代码,欢迎自行编译。不过,如果您想支持开发并获得新功能和更新,请考虑购买 Lightmeter Pro。", + "lightmeterProDescription": "解锁额外功能:\n \u2022 配置文件,其中包含光圈、快门速度等参数\n \u2022 胶片预设列表,用于在反转率发生故障时提供曝光补偿\n \u2022 点测光\n \u2022 直方图\n\n您可以在 GitHub 上获取 Lightmeter 的源代码,欢迎自行编译。不过,如果您想支持开发并获得新功能和更新,请考虑购买 Lightmeter Pro。", "buy": "购买", "proFeatures": "专业功能", "unlockProFeatures": "解锁专业功能", - "unlockProFeaturesDescription": "解锁专业功能。例如包含光圈、快门速度等参数的配置文件;以及一个胶卷预设列表来提供倒易率失效时的曝光补偿。\n\n通过解锁专业版功能,您可以支持开发工作,帮助为应用程序添加新功能。", + "unlockProFeaturesDescription": "\n \u2022 配置文件,其中包含光圈、快门速度等参数\n \u2022 胶片预设列表,用于在反转率发生故障时提供曝光补偿\n \u2022 点测光\n \u2022 直方图\n\n通过解锁专业版功能,您可以支持开发工作,帮助为应用程序添加新功能。", "unlock": "解锁", "tooltipAdd": "添加", "tooltipClose": "关闭", diff --git a/lib/providers/remote_config_provider.dart b/lib/providers/remote_config_provider.dart index a00b385..4557ed6 100644 --- a/lib/providers/remote_config_provider.dart +++ b/lib/providers/remote_config_provider.dart @@ -6,7 +6,7 @@ import 'package:lightmeter/data/models/feature.dart'; import 'package:lightmeter/data/remote_config_service.dart'; class RemoteConfigProvider extends StatefulWidget { - final RemoteConfigService remoteConfigService; + final IRemoteConfigService remoteConfigService; final Widget child; const RemoteConfigProvider({ diff --git a/lib/providers/user_preferences_provider.dart b/lib/providers/user_preferences_provider.dart index 3a4111c..764f282 100644 --- a/lib/providers/user_preferences_provider.dart +++ b/lib/providers/user_preferences_provider.dart @@ -1,6 +1,7 @@ import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; +import 'package:lightmeter/data/models/camera_feature.dart'; import 'package:lightmeter/data/models/dynamic_colors_state.dart'; import 'package:lightmeter/data/models/ev_source_type.dart'; import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; @@ -9,6 +10,7 @@ import 'package:lightmeter/data/models/theme_type.dart'; import 'package:lightmeter/data/shared_prefs_service.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/res/theme.dart'; +import 'package:lightmeter/utils/map_model.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class UserPreferencesProvider extends StatefulWidget { @@ -51,6 +53,14 @@ class UserPreferencesProvider extends StatefulWidget { return _inheritFromEnumsModel(context, _Aspect.stopType).stopType; } + static CameraFeaturesConfig cameraConfigOf(BuildContext context) { + return context.findAncestorWidgetOfExactType<_CameraFeaturesModel>()!.data; + } + + static bool cameraFeatureOf(BuildContext context, CameraFeature feature) { + return InheritedModel.inheritFrom<_CameraFeaturesModel>(context, aspect: feature)!.data[feature]!; + } + static ThemeData themeOf(BuildContext context) { return _inheritFromEnumsModel(context, _Aspect.theme).theme; } @@ -74,6 +84,7 @@ class _UserPreferencesProviderState extends State with late EvSourceType _evSourceType; late StopType _stopType = widget.userPreferencesService.stopType; late MeteringScreenLayoutConfig _meteringScreenLayout = widget.userPreferencesService.meteringScreenLayout; + late CameraFeaturesConfig _cameraFeatures = widget.userPreferencesService.cameraFeatures; late SupportedLocale _locale = widget.userPreferencesService.locale; late ThemeType _themeType = widget.userPreferencesService.themeType; late Color _primaryColor = widget.userPreferencesService.primaryColor; @@ -83,7 +94,8 @@ class _UserPreferencesProviderState extends State with void initState() { super.initState(); _evSourceType = widget.userPreferencesService.evSourceType; - _evSourceType = _evSourceType == EvSourceType.sensor && !widget.hasLightSensor ? EvSourceType.camera : _evSourceType; + _evSourceType = + _evSourceType == EvSourceType.sensor && !widget.hasLightSensor ? EvSourceType.camera : _evSourceType; WidgetsBinding.instance.addObserver(this); } @@ -127,7 +139,10 @@ class _UserPreferencesProviderState extends State with themeType: _themeType, child: _MeteringScreenLayoutModel( data: _meteringScreenLayout, - child: widget.child, + child: _CameraFeaturesModel( + data: _cameraFeatures, + child: widget.child, + ), ), ); }, @@ -172,6 +187,13 @@ class _UserPreferencesProviderState extends State with widget.userPreferencesService.meteringScreenLayout = _meteringScreenLayout; } + void setCameraFeature(CameraFeaturesConfig config) { + setState(() { + _cameraFeatures = config; + }); + widget.userPreferencesService.cameraFeatures = _cameraFeatures; + } + void setPrimaryColor(Color primaryColor) { setState(() { _primaryColor = primaryColor; @@ -264,27 +286,16 @@ class _UserPreferencesModel extends InheritedModel<_Aspect> { } } -class _MeteringScreenLayoutModel extends InheritedModel { - final Map data; - +class _MeteringScreenLayoutModel extends MapModel { const _MeteringScreenLayoutModel({ - required this.data, + required super.data, + required super.child, + }); +} + +class _CameraFeaturesModel extends MapModel { + const _CameraFeaturesModel({ + required super.data, required super.child, }); - - @override - bool updateShouldNotify(_MeteringScreenLayoutModel oldWidget) => oldWidget.data != data; - - @override - bool updateShouldNotifyDependent( - _MeteringScreenLayoutModel oldWidget, - Set dependencies, - ) { - for (final dependecy in dependencies) { - if (oldWidget.data[dependecy] != data[dependecy]) { - return true; - } - } - return false; - } } diff --git a/lib/res/theme.dart b/lib/res/theme.dart index a6320c1..52e0e92 100644 --- a/lib/res/theme.dart +++ b/lib/res/theme.dart @@ -23,7 +23,7 @@ const primaryColorsList = [ ThemeData themeFrom(Color primaryColor, Brightness brightness) { final scheme = _colorSchemeFromColor(primaryColor, brightness); - return ThemeData( + final theme = ThemeData( useMaterial3: true, brightness: scheme.brightness, primaryColor: primaryColor, @@ -60,12 +60,18 @@ ThemeData themeFrom(Color primaryColor, Brightness brightness) { ), scaffoldBackgroundColor: scheme.surface, ); + return theme.copyWith( + listTileTheme: ListTileThemeData( + style: ListTileStyle.list, + iconColor: scheme.onSurface, + textColor: scheme.onSurface, + subtitleTextStyle: theme.textTheme.bodyMedium!.copyWith(color: scheme.onSurfaceVariant), + ), + ); } ColorScheme _colorSchemeFromColor(Color primaryColor, Brightness brightness) { - final scheme = brightness == Brightness.light - ? Scheme.light(primaryColor.value) - : Scheme.dark(primaryColor.value); + final scheme = brightness == Brightness.light ? Scheme.light(primaryColor.value) : Scheme.dark(primaryColor.value); return ColorScheme( brightness: brightness, diff --git a/lib/screens/metering/components/camera_container/bloc_container_camera.dart b/lib/screens/metering/components/camera_container/bloc_container_camera.dart index 1d7d4b5..2e6b051 100644 --- a/lib/screens/metering/components/camera_container/bloc_container_camera.dart +++ b/lib/screens/metering/components/camera_container/bloc_container_camera.dart @@ -11,10 +11,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lightmeter/interactors/metering_interactor.dart'; import 'package:lightmeter/platform_config.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; -import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' - as communication_event; -import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' - as communication_states; +import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' as communication_event; +import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; import 'package:lightmeter/screens/metering/components/camera_container/event_container_camera.dart'; import 'package:lightmeter/screens/metering/components/camera_container/models/camera_error_type.dart'; import 'package:lightmeter/screens/metering/components/camera_container/state_container_camera.dart'; @@ -57,6 +55,7 @@ class CameraContainerBloc extends EvSourceBlocBase(_onZoomChanged); on(_onExposureOffsetChanged); on(_onExposureOffsetResetEvent); + on(_onExposureSpotChangedEvent); } @override @@ -166,9 +165,7 @@ class CameraContainerBloc extends EvSourceBlocBase _onZoomChanged(ZoomChangedEvent event, Emitter emit) async { - if (_cameraController != null && - event.value >= _zoomRange!.start && - event.value <= _zoomRange!.end) { + if (_cameraController != null && event.value >= _zoomRange!.start && event.value <= _zoomRange!.end) { _cameraController!.setZoomLevel(event.value); _currentZoom = event.value; _emitActiveState(emit); @@ -188,6 +185,13 @@ class CameraContainerBloc extends EvSourceBlocBase _onExposureSpotChangedEvent(ExposureSpotChangedEvent event, Emitter emit) async { + if (_cameraController != null) { + _cameraController!.setExposurePoint(event.offset); + _cameraController!.setFocusPoint(event.offset); + } + } + void _emitActiveState(Emitter emit) { emit( CameraActiveState( diff --git a/lib/screens/metering/components/camera_container/components/camera_preview/components/camera_spot_detector/widget_camera_spot_detector.dart b/lib/screens/metering/components/camera_container/components/camera_preview/components/camera_spot_detector/widget_camera_spot_detector.dart new file mode 100644 index 0000000..0ec7f17 --- /dev/null +++ b/lib/screens/metering/components/camera_container/components/camera_preview/components/camera_spot_detector/widget_camera_spot_detector.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/res/dimens.dart'; + +class CameraSpotDetector extends StatefulWidget { + final ValueChanged onSpotTap; + + const CameraSpotDetector({ + required this.onSpotTap, + super.key, + }); + + @override + State createState() => _CameraSpotDetectorState(); +} + +class _CameraSpotDetectorState extends State { + Offset? spot; + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (_, constraints) => GestureDetector( + behavior: HitTestBehavior.opaque, + onTapDown: (TapDownDetails details) => onViewFinderTap(details, constraints), + onLongPress: () => onViewFinderTap(null, constraints), + child: Stack( + children: [ + if (spot != null) + AnimatedPositioned( + duration: Dimens.durationS, + left: spot!.dx - Dimens.grid16 / 2, + top: spot!.dy - Dimens.grid16 / 2, + height: Dimens.grid16, + width: Dimens.grid16, + child: const _Spot(), + ), + ], + ), + ), + ); + } + + void onViewFinderTap(TapDownDetails? details, BoxConstraints constraints) { + setState(() { + spot = details?.localPosition; + }); + + widget.onSpotTap( + details != null + ? Offset( + details.localPosition.dx / constraints.maxWidth, + details.localPosition.dy / constraints.maxHeight, + ) + : null, + ); + } +} + +class _Spot extends StatelessWidget { + const _Spot(); + + @override + Widget build(BuildContext context) { + return const DecoratedBox( + decoration: BoxDecoration( + color: Colors.white70, + shape: BoxShape.circle, + ), + ); + } +} diff --git a/lib/screens/metering/components/camera_container/components/camera_preview/components/camera_view/widget_camera_view.dart b/lib/screens/metering/components/camera_container/components/camera_preview/components/camera_view/widget_camera_view.dart index 7c06062..c054f3d 100644 --- a/lib/screens/metering/components/camera_container/components/camera_preview/components/camera_view/widget_camera_view.dart +++ b/lib/screens/metering/components/camera_container/components/camera_preview/components/camera_view/widget_camera_view.dart @@ -12,14 +12,17 @@ class CameraView extends StatelessWidget { final value = controller.value; return ValueListenableBuilder( valueListenable: controller, - builder: (_, __, ___) => AspectRatio( + builder: (_, __, Widget? child) => AspectRatio( aspectRatio: _isLandscape(value) ? value.aspectRatio : (1 / value.aspectRatio), - child: value.isInitialized - ? RotatedBox( - quarterTurns: _getQuarterTurns(value), - child: controller.buildPreview(), - ) - : const SizedBox.shrink(), + child: Stack( + children: [ + RotatedBox( + quarterTurns: _getQuarterTurns(value), + child: controller.buildPreview(), + ), + child ?? const SizedBox(), + ], + ), ), ); } @@ -42,8 +45,6 @@ class CameraView extends StatelessWidget { DeviceOrientation _getApplicableOrientation(CameraValue value) { return value.isRecordingVideo ? value.recordingOrientation! - : (value.previewPauseOrientation ?? - value.lockedCaptureOrientation ?? - value.deviceOrientation); + : (value.previewPauseOrientation ?? value.lockedCaptureOrientation ?? value.deviceOrientation); } } diff --git a/lib/screens/metering/components/camera_container/components/camera_preview/widget_camera_preview.dart b/lib/screens/metering/components/camera_container/components/camera_preview/widget_camera_preview.dart index 3e9538f..e6f1699 100644 --- a/lib/screens/metering/components/camera_container/components/camera_preview/widget_camera_preview.dart +++ b/lib/screens/metering/components/camera_container/components/camera_preview/widget_camera_preview.dart @@ -1,19 +1,27 @@ import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; -import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; +import 'package:lightmeter/data/models/camera_feature.dart'; import 'package:lightmeter/platform_config.dart'; import 'package:lightmeter/providers/user_preferences_provider.dart'; import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/metering/components/camera_container/components/camera_preview/components/camera_spot_detector/widget_camera_spot_detector.dart'; import 'package:lightmeter/screens/metering/components/camera_container/components/camera_preview/components/camera_view/widget_camera_view.dart'; import 'package:lightmeter/screens/metering/components/camera_container/components/camera_preview/components/camera_view_placeholder/widget_placeholder_camera_view.dart'; import 'package:lightmeter/screens/metering/components/camera_container/components/camera_preview/components/histogram/widget_histogram.dart'; import 'package:lightmeter/screens/metering/components/camera_container/models/camera_error_type.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; class CameraPreview extends StatefulWidget { final CameraController? controller; final CameraErrorType? error; + final ValueChanged onSpotTap; - const CameraPreview({this.controller, this.error, super.key}); + const CameraPreview({ + this.controller, + this.error, + required this.onSpotTap, + super.key, + }); @override State createState() => _CameraPreviewState(); @@ -31,7 +39,10 @@ class _CameraPreviewState extends State { AnimatedSwitcher( duration: Dimens.switchDuration, child: widget.controller != null - ? _CameraPreviewBuilder(controller: widget.controller!) + ? _CameraPreviewBuilder( + controller: widget.controller!, + onSpotTap: widget.onSpotTap, + ) : CameraViewPlaceholder(error: widget.error), ), ], @@ -43,16 +54,19 @@ class _CameraPreviewState extends State { class _CameraPreviewBuilder extends StatefulWidget { final CameraController controller; + final ValueChanged onSpotTap; - const _CameraPreviewBuilder({required this.controller}); + const _CameraPreviewBuilder({ + required this.controller, + required this.onSpotTap, + }); @override State<_CameraPreviewBuilder> createState() => _CameraPreviewBuilderState(); } class _CameraPreviewBuilderState extends State<_CameraPreviewBuilder> { - late final ValueNotifier _initializedNotifier = - ValueNotifier(widget.controller.value.isInitialized); + late final ValueNotifier _initializedNotifier = ValueNotifier(widget.controller.value.isInitialized); @override void initState() { @@ -79,16 +93,23 @@ class _CameraPreviewBuilderState extends State<_CameraPreviewBuilder> { alignment: Alignment.bottomCenter, children: [ CameraView(controller: widget.controller), - if (UserPreferencesProvider.meteringScreenFeatureOf( - context, - MeteringScreenLayoutFeature.histogram, - )) - Positioned( - left: Dimens.grid8, - right: Dimens.grid8, - bottom: Dimens.grid16, - child: CameraHistogram(controller: widget.controller), - ), + if (IAPProducts.isPurchased(context, IAPProductType.paidFeatures)) ...[ + if (UserPreferencesProvider.cameraFeatureOf( + context, + CameraFeature.histogram, + )) + Positioned( + left: Dimens.grid8, + right: Dimens.grid8, + bottom: Dimens.grid16, + child: CameraHistogram(controller: widget.controller), + ), + if (UserPreferencesProvider.cameraFeatureOf( + context, + CameraFeature.spotMetering, + )) + CameraSpotDetector(onSpotTap: widget.onSpotTap) + ], ], ) : const SizedBox.shrink(), diff --git a/lib/screens/metering/components/camera_container/event_container_camera.dart b/lib/screens/metering/components/camera_container/event_container_camera.dart index d3e5995..fe0713d 100644 --- a/lib/screens/metering/components/camera_container/event_container_camera.dart +++ b/lib/screens/metering/components/camera_container/event_container_camera.dart @@ -1,3 +1,5 @@ +import 'package:flutter/gestures.dart'; + abstract class CameraContainerEvent { const CameraContainerEvent(); } @@ -53,3 +55,19 @@ class ExposureOffsetChangedEvent extends CameraContainerEvent { class ExposureOffsetResetEvent extends CameraContainerEvent { const ExposureOffsetResetEvent(); } + +class ExposureSpotChangedEvent extends CameraContainerEvent { + final Offset? offset; + + const ExposureSpotChangedEvent(this.offset); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other.runtimeType != runtimeType) return false; + return other is ExposureSpotChangedEvent && other.offset == offset; + } + + @override + int get hashCode => Object.hash(offset, runtimeType); +} diff --git a/lib/screens/metering/components/camera_container/widget_container_camera.dart b/lib/screens/metering/components/camera_container/widget_container_camera.dart index 944aa34..a23545e 100644 --- a/lib/screens/metering/components/camera_container/widget_container_camera.dart +++ b/lib/screens/metering/components/camera_container/widget_container_camera.dart @@ -143,6 +143,9 @@ class _CameraViewBuilder extends StatelessWidget { builder: (context, state) => CameraPreview( controller: state is CameraInitializedState ? state.controller : null, error: state is CameraErrorState ? state.error : null, + onSpotTap: (value) { + context.read().add(ExposureSpotChangedEvent(value)); + }, ), ); } diff --git a/lib/screens/settings/components/metering/components/camera_features/widget_list_tile_camera_features.dart b/lib/screens/settings/components/metering/components/camera_features/widget_list_tile_camera_features.dart new file mode 100644 index 0000000..1446be3 --- /dev/null +++ b/lib/screens/settings/components/metering/components/camera_features/widget_list_tile_camera_features.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/camera_feature.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/providers/user_preferences_provider.dart'; +import 'package:lightmeter/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart'; +import 'package:lightmeter/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart'; + +class CameraFeaturesListTile extends StatelessWidget { + const CameraFeaturesListTile({super.key}); + + @override + Widget build(BuildContext context) { + return IAPListTile( + leading: const Icon(Icons.camera_alt), + title: Text(S.of(context).cameraFeatures), + onTap: () { + showDialog( + context: context, + builder: (_) => DialogSwitch( + icon: Icons.layers_outlined, + title: S.of(context).cameraFeatures, + values: UserPreferencesProvider.cameraConfigOf(context), + titleAdapter: (context, feature) { + switch (feature) { + case CameraFeature.spotMetering: + return S.of(context).cameraFeatureSpotMetering; + case CameraFeature.histogram: + return S.of(context).cameraFeatureHistogram; + } + }, + subtitleAdapter: (context, feature) { + switch (feature) { + case CameraFeature.spotMetering: + return S.of(context).cameraFeatureSpotMeteringHint; + case CameraFeature.histogram: + return S.of(context).cameraFeatureHistogramHint; + } + }, + onSave: UserPreferencesProvider.of(context).setCameraFeature, + ), + ); + }, + ); + } +} diff --git a/lib/screens/settings/components/metering/components/metering_screen_layout/components/meterins_screen_layout_features_dialog/widget_dialog_metering_screen_layout_features.dart b/lib/screens/settings/components/metering/components/metering_screen_layout/components/meterins_screen_layout_features_dialog/widget_dialog_metering_screen_layout_features.dart deleted file mode 100644 index 2529e2e..0000000 --- a/lib/screens/settings/components/metering/components/metering_screen_layout/components/meterins_screen_layout_features_dialog/widget_dialog_metering_screen_layout_features.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; -import 'package:lightmeter/generated/l10n.dart'; -import 'package:lightmeter/providers/equipment_profile_provider.dart'; -import 'package:lightmeter/providers/films_provider.dart'; -import 'package:lightmeter/providers/user_preferences_provider.dart'; -import 'package:lightmeter/res/dimens.dart'; -import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; - -class MeteringScreenLayoutFeaturesDialog extends StatefulWidget { - const MeteringScreenLayoutFeaturesDialog({super.key}); - - @override - State createState() => _MeteringScreenLayoutFeaturesDialogState(); -} - -class _MeteringScreenLayoutFeaturesDialogState extends State { - late final _features = MeteringScreenLayoutConfig.from(UserPreferencesProvider.meteringScreenConfigOf(context)); - - @override - Widget build(BuildContext context) { - return AlertDialog( - icon: const Icon(Icons.layers_outlined), - titlePadding: Dimens.dialogIconTitlePadding, - title: Text(S.of(context).meteringScreenLayout), - contentPadding: EdgeInsets.zero, - content: SizedBox( - width: double.maxFinite, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), - child: Text(S.of(context).meteringScreenLayoutHint), - ), - const SizedBox(height: Dimens.grid16), - ListView( - shrinkWrap: true, - children: [ - _featureListTile(MeteringScreenLayoutFeature.equipmentProfiles), - _featureListTile(MeteringScreenLayoutFeature.extremeExposurePairs), - _featureListTile(MeteringScreenLayoutFeature.filmPicker), - _featureListTile(MeteringScreenLayoutFeature.histogram), - ], - ), - ], - ), - ), - actionsPadding: Dimens.dialogActionsPadding, - actions: [ - TextButton( - onPressed: Navigator.of(context).pop, - child: Text(S.of(context).cancel), - ), - TextButton( - onPressed: () { - if (!_features[MeteringScreenLayoutFeature.equipmentProfiles]!) { - EquipmentProfileProvider.of(context).setProfile(EquipmentProfiles.of(context).first); - } - if (!_features[MeteringScreenLayoutFeature.filmPicker]!) { - FilmsProvider.of(context).setFilm(const Film.other()); - } - UserPreferencesProvider.of(context).setMeteringScreenLayout(_features); - Navigator.of(context).pop(); - }, - child: Text(S.of(context).save), - ), - ], - ); - } - - Widget _featureListTile(MeteringScreenLayoutFeature f) { - return SwitchListTile( - contentPadding: EdgeInsets.symmetric(horizontal: Dimens.dialogTitlePadding.left), - title: Text(_toStringLocalized(context, f)), - value: _features[f]!, - onChanged: (value) { - setState(() { - _features.update(f, (_) => value); - }); - }, - ); - } - - String _toStringLocalized(BuildContext context, MeteringScreenLayoutFeature feature) { - switch (feature) { - case MeteringScreenLayoutFeature.equipmentProfiles: - return S.of(context).meteringScreenLayoutHintEquipmentProfiles; - case MeteringScreenLayoutFeature.extremeExposurePairs: - return S.of(context).meteringScreenFeatureExtremeExposurePairs; - case MeteringScreenLayoutFeature.filmPicker: - return S.of(context).meteringScreenFeatureFilmPicker; - case MeteringScreenLayoutFeature.histogram: - return S.of(context).meteringScreenFeatureHistogram; - } - } -} diff --git a/lib/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart b/lib/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart index a540926..1f89b4b 100644 --- a/lib/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart +++ b/lib/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart @@ -1,7 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; import 'package:lightmeter/generated/l10n.dart'; - -import 'package:lightmeter/screens/settings/components/metering/components/metering_screen_layout/components/meterins_screen_layout_features_dialog/widget_dialog_metering_screen_layout_features.dart'; +import 'package:lightmeter/providers/equipment_profile_provider.dart'; +import 'package:lightmeter/providers/films_provider.dart'; +import 'package:lightmeter/providers/user_preferences_provider.dart'; +import 'package:lightmeter/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class MeteringScreenLayoutListTile extends StatelessWidget { const MeteringScreenLayoutListTile({super.key}); @@ -14,9 +18,35 @@ class MeteringScreenLayoutListTile extends StatelessWidget { onTap: () { showDialog( context: context, - builder: (_) => const MeteringScreenLayoutFeaturesDialog(), + builder: (_) => DialogSwitch( + icon: Icons.layers_outlined, + title: S.of(context).meteringScreenLayout, + description: S.of(context).meteringScreenLayoutHint, + values: UserPreferencesProvider.meteringScreenConfigOf(context), + titleAdapter: _toStringLocalized, + onSave: (value) { + if (!value[MeteringScreenLayoutFeature.equipmentProfiles]!) { + EquipmentProfileProvider.of(context).setProfile(EquipmentProfiles.of(context).first); + } + if (!value[MeteringScreenLayoutFeature.filmPicker]!) { + FilmsProvider.of(context).setFilm(const Film.other()); + } + UserPreferencesProvider.of(context).setMeteringScreenLayout(value); + }, + ), ); }, ); } + + String _toStringLocalized(BuildContext context, MeteringScreenLayoutFeature feature) { + switch (feature) { + case MeteringScreenLayoutFeature.equipmentProfiles: + return S.of(context).meteringScreenLayoutHintEquipmentProfiles; + case MeteringScreenLayoutFeature.extremeExposurePairs: + return S.of(context).meteringScreenFeatureExtremeExposurePairs; + case MeteringScreenLayoutFeature.filmPicker: + return S.of(context).meteringScreenFeatureFilmPicker; + } + } } diff --git a/lib/screens/settings/components/metering/widget_settings_section_metering.dart b/lib/screens/settings/components/metering/widget_settings_section_metering.dart index 90de68d..0c6c07d 100644 --- a/lib/screens/settings/components/metering/widget_settings_section_metering.dart +++ b/lib/screens/settings/components/metering/widget_settings_section_metering.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/screens/settings/components/metering/components/calibration/widget_list_tile_calibration.dart'; +import 'package:lightmeter/screens/settings/components/metering/components/camera_features/widget_list_tile_camera_features.dart'; import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/widget_list_tile_equipment_profiles.dart'; import 'package:lightmeter/screens/settings/components/metering/components/films/widget_list_tile_films.dart'; import 'package:lightmeter/screens/settings/components/metering/components/fractional_stops/widget_list_tile_fractional_stops.dart'; @@ -20,6 +21,7 @@ class MeteringSettingsSection extends StatelessWidget { MeteringScreenLayoutListTile(), EquipmentProfilesListTile(), FilmsListTile(), + CameraFeaturesListTile(), ], ); } diff --git a/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart b/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart new file mode 100644 index 0000000..aa3a370 --- /dev/null +++ b/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/res/dimens.dart'; + +typedef StringAdapter = String Function(BuildContext context, T value); + +class DialogSwitch extends StatefulWidget { + final IconData icon; + final String title; + final String? description; + final Map values; + final StringAdapter titleAdapter; + final StringAdapter? subtitleAdapter; + final ValueChanged> onSave; + + const DialogSwitch({ + required this.icon, + required this.title, + this.description, + required this.values, + required this.titleAdapter, + this.subtitleAdapter, + required this.onSave, + super.key, + }); + + @override + State> createState() => _DialogSwitchState(); +} + +class _DialogSwitchState extends State> { + late final Map _features = Map.from(widget.values); + + @override + Widget build(BuildContext context) { + return AlertDialog( + icon: Icon(widget.icon), + titlePadding: Dimens.dialogIconTitlePadding, + title: Text(widget.title), + contentPadding: EdgeInsets.zero, + content: SizedBox( + width: double.maxFinite, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.description != null) ...[ + Padding( + padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), + child: Text(widget.description!), + ), + const SizedBox(height: Dimens.grid16) + ], + ListView( + shrinkWrap: true, + children: _features.entries + .map( + (entry) => SwitchListTile( + contentPadding: EdgeInsets.symmetric(horizontal: Dimens.dialogTitlePadding.left), + title: Text(widget.titleAdapter(context, entry.key)), + subtitle: widget.subtitleAdapter != null + ? Text( + widget.subtitleAdapter!.call(context, entry.key), + style: Theme.of(context).listTileTheme.subtitleTextStyle, + ) + : null, + value: _features[entry.key]!, + onChanged: (value) { + setState(() { + _features.update(entry.key, (_) => value); + }); + }, + ), + ) + .toList(), + ), + ], + ), + ), + actionsPadding: Dimens.dialogActionsPadding, + actions: [ + TextButton( + onPressed: Navigator.of(context).pop, + child: Text(S.of(context).cancel), + ), + TextButton( + onPressed: () { + widget.onSave(_features); + Navigator.of(context).pop(); + }, + child: Text(S.of(context).save), + ), + ], + ); + } +} diff --git a/lib/screens/settings/utils/show_buy_pro_dialog.dart b/lib/screens/settings/utils/show_buy_pro_dialog.dart index 7ce3ff6..181259f 100644 --- a/lib/screens/settings/utils/show_buy_pro_dialog.dart +++ b/lib/screens/settings/utils/show_buy_pro_dialog.dart @@ -7,6 +7,31 @@ import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; Future showBuyProDialog(BuildContext context) { final unlockFeaturesEnabled = RemoteConfig.isEnabled(context, Feature.unlockProFeaturesText); + + Widget splitDescription() { + final description = + unlockFeaturesEnabled ? S.of(context).unlockProFeaturesDescription : S.of(context).lightmeterProDescription; + final paragraphs = description.split('\n\n'); + final features = paragraphs.first.split('\n \u2022 ').sublist(1); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text(paragraphs.first.split('\n \u2022 ').first), + ...features.map( + (f) => Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('\u2022 '), + Flexible(child: Text(f)), + ], + ), + ), + Text('\n${paragraphs.last}'), + ], + ); + } + return showDialog( context: context, builder: (_) => AlertDialog( @@ -14,11 +39,7 @@ Future showBuyProDialog(BuildContext context) { titlePadding: Dimens.dialogIconTitlePadding, title: Text(unlockFeaturesEnabled ? S.of(context).proFeatures : S.of(context).lightmeterPro), contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), - content: SingleChildScrollView( - child: Text( - unlockFeaturesEnabled ? S.of(context).unlockProFeaturesDescription : S.of(context).lightmeterProDescription, - ), - ), + content: SingleChildScrollView(child: splitDescription()), actionsPadding: Dimens.dialogActionsPadding, actions: [ TextButton( diff --git a/lib/utils/map_model.dart b/lib/utils/map_model.dart new file mode 100644 index 0000000..1f5ea09 --- /dev/null +++ b/lib/utils/map_model.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class MapModel extends InheritedModel { + final Map data; + + const MapModel({ + required this.data, + required super.child, + }); + + @override + bool updateShouldNotify(MapModel oldWidget) => oldWidget.data != data; + + @override + bool updateShouldNotifyDependent( + MapModel oldWidget, + Set dependencies, + ) { + for (final dependecy in dependencies) { + if (oldWidget.data[dependecy] != data[dependecy]) { + return true; + } + } + return false; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index eb53e59..d88de9f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: m3_lightmeter_iap: git: url: "https://github.com/vodemn/m3_lightmeter_iap" - ref: v0.7.0 + ref: v0.7.1 m3_lightmeter_resources: git: url: "https://github.com/vodemn/m3_lightmeter_resources" diff --git a/screenshots/generate_screenshots.dart b/screenshots/generate_screenshots.dart index 8c8e7e9..814cfd1 100644 --- a/screenshots/generate_screenshots.dart +++ b/screenshots/generate_screenshots.dart @@ -46,7 +46,6 @@ void main() { MeteringScreenLayoutFeature.equipmentProfiles: true, MeteringScreenLayoutFeature.extremeExposurePairs: true, MeteringScreenLayoutFeature.filmPicker: true, - MeteringScreenLayoutFeature.histogram: false, }.toJson(), ), diff --git a/test/data/models/camera_features_config_test.dart b/test/data/models/camera_features_config_test.dart new file mode 100644 index 0000000..d7261a8 --- /dev/null +++ b/test/data/models/camera_features_config_test.dart @@ -0,0 +1,47 @@ +import 'package:lightmeter/data/models/camera_feature.dart'; +import 'package:test/test.dart'; + +void main() { + group( + 'fromJson()', + () { + test('All keys', () { + expect( + CameraFeaturesConfigJson.fromJson( + { + 'spotMetering': true, + 'histogram': true, + }, + ), + { + CameraFeature.spotMetering: true, + CameraFeature.histogram: true, + }, + ); + }); + + test('Legacy (no spotMetering & histogram)', () { + expect( + CameraFeaturesConfigJson.fromJson({}), + { + CameraFeature.spotMetering: false, + CameraFeature.histogram: false, + }, + ); + }); + }, + ); + + test('toJson()', () { + expect( + { + CameraFeature.spotMetering: true, + CameraFeature.histogram: true, + }.toJson(), + { + 'spotMetering': true, + 'histogram': true, + }, + ); + }); +} diff --git a/test/data/models/metering_screen_layout_config_test.dart b/test/data/models/metering_screen_layout_config_test.dart index 9e9393e..f3216ba 100644 --- a/test/data/models/metering_screen_layout_config_test.dart +++ b/test/data/models/metering_screen_layout_config_test.dart @@ -18,7 +18,6 @@ void main() { { MeteringScreenLayoutFeature.extremeExposurePairs: true, MeteringScreenLayoutFeature.filmPicker: true, - MeteringScreenLayoutFeature.histogram: true, MeteringScreenLayoutFeature.equipmentProfiles: true, }, ); @@ -35,7 +34,6 @@ void main() { { MeteringScreenLayoutFeature.extremeExposurePairs: false, MeteringScreenLayoutFeature.filmPicker: false, - MeteringScreenLayoutFeature.histogram: true, MeteringScreenLayoutFeature.equipmentProfiles: true, }, ); @@ -53,7 +51,6 @@ void main() { { MeteringScreenLayoutFeature.extremeExposurePairs: false, MeteringScreenLayoutFeature.filmPicker: false, - MeteringScreenLayoutFeature.histogram: false, MeteringScreenLayoutFeature.equipmentProfiles: true, }, ); @@ -67,13 +64,11 @@ void main() { MeteringScreenLayoutFeature.equipmentProfiles: true, MeteringScreenLayoutFeature.extremeExposurePairs: true, MeteringScreenLayoutFeature.filmPicker: true, - MeteringScreenLayoutFeature.histogram: true, }.toJson(), { - '3': true, - '0': true, - '1': true, - '2': true, + 'equipmentProfiles': true, + 'extremeExposurePairs': true, + 'filmPicker': true, }, ); }); diff --git a/test/data/shared_prefs_service_test.dart b/test/data/shared_prefs_service_test.dart index 8ec42e1..96f4e1e 100644 --- a/test/data/shared_prefs_service_test.dart +++ b/test/data/shared_prefs_service_test.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/data/models/camera_feature.dart'; import 'package:lightmeter/data/models/ev_source_type.dart'; import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; import 'package:lightmeter/data/models/supported_locale.dart'; @@ -191,12 +192,11 @@ void main() { MeteringScreenLayoutFeature.extremeExposurePairs: true, MeteringScreenLayoutFeature.filmPicker: true, MeteringScreenLayoutFeature.equipmentProfiles: true, - MeteringScreenLayoutFeature.histogram: true, }, ); }); - test('get', () { + test('get (legacy)', () { when( () => sharedPreferences.getString(UserPreferencesService.meteringScreenLayoutKey), ).thenReturn("""{"0":false,"1":true}"""); @@ -206,7 +206,20 @@ void main() { MeteringScreenLayoutFeature.extremeExposurePairs: false, MeteringScreenLayoutFeature.filmPicker: true, MeteringScreenLayoutFeature.equipmentProfiles: true, - MeteringScreenLayoutFeature.histogram: true, + }, + ); + }); + + test('get', () { + when( + () => sharedPreferences.getString(UserPreferencesService.meteringScreenLayoutKey), + ).thenReturn("""{"extremeExposurePairs":false,"filmPicker":true}"""); + expect( + service.meteringScreenLayout, + { + MeteringScreenLayoutFeature.extremeExposurePairs: false, + MeteringScreenLayoutFeature.filmPicker: true, + MeteringScreenLayoutFeature.equipmentProfiles: true, }, ); }); @@ -215,19 +228,62 @@ void main() { when( () => sharedPreferences.setString( UserPreferencesService.meteringScreenLayoutKey, - """{"0":false,"1":true,"2":true,"3":true}""", + """{"extremeExposurePairs":false,"filmPicker":true,"equipmentProfiles":true}""", ), ).thenAnswer((_) => Future.value(true)); service.meteringScreenLayout = { MeteringScreenLayoutFeature.extremeExposurePairs: false, MeteringScreenLayoutFeature.filmPicker: true, - MeteringScreenLayoutFeature.histogram: true, MeteringScreenLayoutFeature.equipmentProfiles: true, }; verify( () => sharedPreferences.setString( UserPreferencesService.meteringScreenLayoutKey, - """{"0":false,"1":true,"2":true,"3":true}""", + """{"extremeExposurePairs":false,"filmPicker":true,"equipmentProfiles":true}""", + ), + ).called(1); + }); + }); + + group('cameraFeatures', () { + test('get default', () { + when(() => sharedPreferences.getString(UserPreferencesService.cameraFeaturesKey)).thenReturn(null); + expect( + service.cameraFeatures, + { + CameraFeature.spotMetering: false, + CameraFeature.histogram: false, + }, + ); + }); + + test('get', () { + when(() => sharedPreferences.getString(UserPreferencesService.cameraFeaturesKey)) + .thenReturn("""{"spotMetering":false,"histogram":true}"""); + expect( + service.cameraFeatures, + { + CameraFeature.spotMetering: false, + CameraFeature.histogram: true, + }, + ); + }); + + test('set', () { + when( + () => sharedPreferences.setString( + UserPreferencesService.cameraFeaturesKey, + """{"spotMetering":false,"histogram":true}""", + ), + ).thenAnswer((_) => Future.value(true)); + service.cameraFeatures = { + CameraFeature.spotMetering: false, + CameraFeature.histogram: true, + }; + verify( + () => sharedPreferences.setString( + UserPreferencesService.cameraFeaturesKey, + """{"spotMetering":false,"histogram":true}""", ), ).called(1); }); diff --git a/test/providers/user_preferences_provider_test.dart b/test/providers/user_preferences_provider_test.dart index ffa7993..b6dc2ae 100644 --- a/test/providers/user_preferences_provider_test.dart +++ b/test/providers/user_preferences_provider_test.dart @@ -1,6 +1,7 @@ import 'package:dynamic_color/test_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/data/models/camera_feature.dart'; import 'package:lightmeter/data/models/dynamic_colors_state.dart'; import 'package:lightmeter/data/models/ev_source_type.dart'; import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; @@ -31,7 +32,10 @@ void main() { MeteringScreenLayoutFeature.extremeExposurePairs: true, MeteringScreenLayoutFeature.filmPicker: true, MeteringScreenLayoutFeature.equipmentProfiles: true, - MeteringScreenLayoutFeature.histogram: true, + }); + when(() => mockUserPreferencesService.cameraFeatures).thenReturn({ + CameraFeature.spotMetering: true, + CameraFeature.histogram: true, }); when(() => mockUserPreferencesService.locale).thenReturn(SupportedLocale.en); when(() => mockUserPreferencesService.themeType).thenReturn(ThemeType.light); @@ -184,7 +188,6 @@ void main() { MeteringScreenLayoutFeature.equipmentProfiles: true, MeteringScreenLayoutFeature.extremeExposurePairs: false, MeteringScreenLayoutFeature.filmPicker: false, - MeteringScreenLayoutFeature.histogram: true, }), child: const Text(''), ), @@ -196,20 +199,64 @@ void main() { expect(find.text("${MeteringScreenLayoutFeature.equipmentProfiles}: true"), findsNWidgets(2)); expect(find.text("${MeteringScreenLayoutFeature.extremeExposurePairs}: true"), findsNWidgets(2)); expect(find.text("${MeteringScreenLayoutFeature.filmPicker}: true"), findsNWidgets(2)); - expect(find.text("${MeteringScreenLayoutFeature.histogram}: true"), findsNWidgets(2)); await tester.tap(find.byType(ElevatedButton)); await tester.pumpAndSettle(); expect(find.text("${MeteringScreenLayoutFeature.equipmentProfiles}: true"), findsNWidgets(2)); expect(find.text("${MeteringScreenLayoutFeature.extremeExposurePairs}: false"), findsNWidgets(2)); expect(find.text("${MeteringScreenLayoutFeature.filmPicker}: false"), findsNWidgets(2)); - expect(find.text("${MeteringScreenLayoutFeature.histogram}: true"), findsNWidgets(2)); verify( () => mockUserPreferencesService.meteringScreenLayout = { MeteringScreenLayoutFeature.extremeExposurePairs: false, MeteringScreenLayoutFeature.filmPicker: false, MeteringScreenLayoutFeature.equipmentProfiles: true, - MeteringScreenLayoutFeature.histogram: true, + }, + ).called(1); + }, + ); + + testWidgets( + 'Set camera features config', + (tester) async { + await pumpTestWidget( + tester, + builder: (context) { + final config = UserPreferencesProvider.cameraConfigOf(context); + return Column( + children: [ + ...List.generate( + config.length, + (index) => Text('${config.keys.toList()[index]}: ${config.values.toList()[index]}'), + ), + ...List.generate( + CameraFeature.values.length, + (index) => Text( + '${CameraFeature.values[index]}: ${UserPreferencesProvider.cameraFeatureOf(context, CameraFeature.values[index])}', + ), + ), + ElevatedButton( + onPressed: () => UserPreferencesProvider.of(context).setCameraFeature({ + CameraFeature.spotMetering: true, + CameraFeature.histogram: false, + }), + child: const Text(''), + ), + ], + ); + }, + ); + // Match `findsNWidgets(2)` to verify that `cameraFeatureOf` specific results are the same as the whole config + expect(find.text("${CameraFeature.spotMetering}: true"), findsNWidgets(2)); + expect(find.text("${CameraFeature.histogram}: true"), findsNWidgets(2)); + + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(find.text("${CameraFeature.spotMetering}: true"), findsNWidgets(2)); + expect(find.text("${CameraFeature.histogram}: false"), findsNWidgets(2)); + verify( + () => mockUserPreferencesService.cameraFeatures = { + CameraFeature.spotMetering: true, + CameraFeature.histogram: false, }, ).called(1); }, diff --git a/test/screens/metering/components/camera/bloc_container_camera_test.dart b/test/screens/metering/components/camera/bloc_container_camera_test.dart index d54c0a5..52c57c8 100644 --- a/test/screens/metering/components/camera/bloc_container_camera_test.dart +++ b/test/screens/metering/components/camera/bloc_container_camera_test.dart @@ -4,10 +4,8 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:lightmeter/interactors/metering_interactor.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; -import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' - as communication_events; -import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' - as communication_states; +import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' as communication_events; +import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; import 'package:lightmeter/screens/metering/components/camera_container/bloc_container_camera.dart'; import 'package:lightmeter/screens/metering/components/camera_container/event_container_camera.dart'; import 'package:lightmeter/screens/metering/components/camera_container/models/camera_error_type.dart'; @@ -16,9 +14,9 @@ import 'package:mocktail/mocktail.dart'; class _MockMeteringInteractor extends Mock implements MeteringInteractor {} -class _MockMeteringCommunicationBloc extends MockBloc< - communication_events.MeteringCommunicationEvent, - communication_states.MeteringCommunicationState> implements MeteringCommunicationBloc {} +class _MockMeteringCommunicationBloc + extends MockBloc + implements MeteringCommunicationBloc {} void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -147,8 +145,7 @@ void main() { verify(() => meteringInteractor.requestCameraPermission()).called(1); }, expect: () => [ - isA() - .having((state) => state.error, "error", CameraErrorType.permissionNotGranted), + isA().having((state) => state.error, "error", CameraErrorType.permissionNotGranted), ], ); @@ -166,8 +163,7 @@ void main() { }, expect: () => [ isA(), - isA() - .having((state) => state.error, "error", CameraErrorType.permissionNotGranted), + isA().having((state) => state.error, "error", CameraErrorType.permissionNotGranted), ], ); @@ -215,8 +211,7 @@ void main() { 'No cameras detected error', setUp: () { when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true); - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler( + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( cameraMethodChannel, (methodCall) async => cameraMethodCallSuccessHandler(methodCall, cameras: const []), ); @@ -232,8 +227,7 @@ void main() { }, expect: () => [ isA(), - isA() - .having((state) => state.error, "error", CameraErrorType.noCamerasDetected), + isA().having((state) => state.error, "error", CameraErrorType.noCamerasDetected), ], ); @@ -241,8 +235,7 @@ void main() { 'No back facing cameras available', setUp: () { when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true); - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler( + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( cameraMethodChannel, (methodCall) async => cameraMethodCallSuccessHandler(methodCall, cameras: frontCameras), ); @@ -263,8 +256,7 @@ void main() { 'Catch other initialization errors', setUp: () { when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true); - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler( + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler( cameraMethodChannel, (methodCall) async { switch (methodCall.method) { @@ -300,10 +292,8 @@ void main() { act: (bloc) async { bloc.add(const InitializeEvent()); await Future.delayed(Duration.zero); - TestWidgetsFlutterBinding.instance - .handleAppLifecycleStateChanged(AppLifecycleState.detached); - TestWidgetsFlutterBinding.instance - .handleAppLifecycleStateChanged(AppLifecycleState.resumed); + TestWidgetsFlutterBinding.instance.handleAppLifecycleStateChanged(AppLifecycleState.detached); + TestWidgetsFlutterBinding.instance.handleAppLifecycleStateChanged(AppLifecycleState.resumed); }, verify: (_) { verify(() => meteringInteractor.checkCameraPermission()).called(2); @@ -500,6 +490,29 @@ void main() { ); }, ); + + group( + '`ExposureSpotChangedEvent`', + () { + blocTest( + 'Set exposure spot multiple times', + setUp: () { + when(() => meteringInteractor.checkCameraPermission()).thenAnswer((_) async => true); + }, + build: () => bloc, + act: (bloc) async { + bloc.add(const InitializeEvent()); + await Future.delayed(Duration.zero); + bloc.add(const ExposureSpotChangedEvent(Offset(0.1, 0.1))); + bloc.add(const ExposureSpotChangedEvent(Offset(1.0, 0.5))); + }, + verify: (_) { + verify(() => meteringInteractor.checkCameraPermission()).called(1); + }, + expect: () => [...initializedStateSequence], + ); + }, + ); } extension _MethodChannelMock on MethodChannel { diff --git a/test/screens/metering/components/camera/event_container_camera_test.dart b/test/screens/metering/components/camera/event_container_camera_test.dart index f136b5f..3751f10 100644 --- a/test/screens/metering/components/camera/event_container_camera_test.dart +++ b/test/screens/metering/components/camera/event_container_camera_test.dart @@ -1,5 +1,7 @@ // ignore_for_file: prefer_const_constructors +import 'dart:ui'; + import 'package:lightmeter/screens/metering/components/camera_container/event_container_camera.dart'; import 'package:test/test.dart'; @@ -41,4 +43,23 @@ void main() { }); }, ); + + group( + '`ExposureSpotChangedEvent`', + () { + final a = ExposureSpotChangedEvent(Offset(0.0, 0.0)); + final b = ExposureSpotChangedEvent(Offset(0.0, 0.0)); + final c = ExposureSpotChangedEvent(Offset(2.0, 2.0)); + test('==', () { + expect(a == b && b == a, true); + expect(a != c && c != a, true); + expect(b != c && c != b, true); + }); + test('hashCode', () { + expect(a.hashCode == b.hashCode, true); + expect(a.hashCode != c.hashCode, true); + expect(b.hashCode != c.hashCode, true); + }); + }, + ); } From 19fc039723bf87eb34f82cc06b2e3aab7d59bf78 Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:26:34 +0100 Subject: [PATCH 09/17] ML-137 Dialogs improvements (#138) * Force dialogs to have the same width * Fix `DialogPicker` bouncing when the first selected item is near the end --- .../dialog_filter/widget_dialog_filter.dart | 148 +++++++++--------- .../dialog_picker/widget_dialog_picker.dart | 40 ++--- .../widget_dialog_picker_range.dart | 79 +++++----- 3 files changed, 139 insertions(+), 128 deletions(-) diff --git a/lib/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart b/lib/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart index 76cd729..eb03e23 100644 --- a/lib/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart +++ b/lib/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/res/dimens.dart'; @@ -34,18 +35,20 @@ class _DialogFilterState extends State> { bool get _hasAnySelected => checkboxValues.contains(true); bool get _hasAnyUnselected => checkboxValues.contains(false); - late final ScrollController _scrollController; + final ScrollController _scrollController = ScrollController(); @override void initState() { super.initState(); - int i = 0; - for (; i < checkboxValues.length; i++) { - if (checkboxValues[i]) { - break; + SchedulerBinding.instance.addPostFrameCallback((_) { + int i = 0; + for (; i < checkboxValues.length; i++) { + if (checkboxValues[i]) { + break; + } } - } - _scrollController = ScrollController(initialScrollOffset: Dimens.grid56 * i); + _scrollController.jumpTo((Dimens.grid56 * i).clamp(0, _scrollController.position.maxScrollExtent)); + }); } @override @@ -61,79 +64,80 @@ class _DialogFilterState extends State> { titlePadding: Dimens.dialogIconTitlePadding, title: Text(widget.title), contentPadding: EdgeInsets.zero, - content: Column( - children: [ - Padding( - padding: Dimens.dialogIconTitlePadding, - child: Text(widget.description), - ), - const Divider(), - Expanded( - child: SingleChildScrollView( - controller: _scrollController, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisSize: MainAxisSize.min, - children: List.generate( - widget.values.length, - (index) => CheckboxListTile( - value: checkboxValues[index], - controlAffinity: ListTileControlAffinity.leading, - title: Text( - widget.titleAdapter(context, widget.values[index]), - style: Theme.of(context).textTheme.bodyLarge, + content: SizedBox( + width: double.maxFinite, + child: Column( + children: [ + Padding( + padding: Dimens.dialogIconTitlePadding, + child: Text(widget.description), + ), + const Divider(), + Expanded( + child: SingleChildScrollView( + controller: _scrollController, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: List.generate( + widget.values.length, + (index) => CheckboxListTile( + value: checkboxValues[index], + controlAffinity: ListTileControlAffinity.leading, + title: Text( + widget.titleAdapter(context, widget.values[index]), + style: Theme.of(context).textTheme.bodyLarge, + ), + onChanged: (value) { + if (value != null) { + setState(() { + checkboxValues[index] = value; + }); + } + }, ), - onChanged: (value) { - if (value != null) { - setState(() { - checkboxValues[index] = value; - }); - } - }, ), ), ), ), - ), - const Divider(), - Padding( - padding: Dimens.dialogActionsPadding, - child: Row( - children: [ - SizedBox( - width: 40, - child: IconButton( - padding: EdgeInsets.zero, - icon: Icon(_hasAnyUnselected ? Icons.select_all : Icons.deselect), - onPressed: _toggleAll, - tooltip: _hasAnyUnselected - ? S.of(context).tooltipSelectAll - : S.of(context).tooltipDesecelectAll, + const Divider(), + Padding( + padding: Dimens.dialogActionsPadding, + child: Row( + children: [ + SizedBox( + width: 40, + child: IconButton( + padding: EdgeInsets.zero, + icon: Icon(_hasAnyUnselected ? Icons.select_all : Icons.deselect), + onPressed: _toggleAll, + tooltip: _hasAnyUnselected ? S.of(context).tooltipSelectAll : S.of(context).tooltipDesecelectAll, + ), ), - ), - const Spacer(), - TextButton( - onPressed: Navigator.of(context).pop, - child: Text(S.of(context).cancel), - ), - TextButton( - onPressed: _hasAnySelected - ? () { - final List selectedValues = []; - for (int i = 0; i < widget.values.length; i++) { - if (checkboxValues[i]) { - selectedValues.add(widget.values[i]); + const Spacer(), + TextButton( + onPressed: Navigator.of(context).pop, + child: Text(S.of(context).cancel), + ), + TextButton( + onPressed: _hasAnySelected + ? () { + final List selectedValues = []; + for (int i = 0; i < widget.values.length; i++) { + if (checkboxValues[i]) { + selectedValues.add(widget.values[i]); + } } + Navigator.of(context).pop(selectedValues); } - Navigator.of(context).pop(selectedValues); - } - : null, - child: Text(S.of(context).save), - ), - ], - ), - ) - ], + : null, + child: Text(S.of(context).save), + ), + ], + ), + ) + ], + ), ), ); } diff --git a/lib/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart b/lib/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart index c893027..dc31b5c 100644 --- a/lib/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart +++ b/lib/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart @@ -32,24 +32,28 @@ class _DialogPickerState extends State> { titlePadding: Dimens.dialogIconTitlePadding, title: Text(widget.title), contentPadding: EdgeInsets.zero, - content: Column( - mainAxisSize: MainAxisSize.min, - children: widget.values - .map( - (e) => RadioListTile( - value: e, - groupValue: _selected, - title: Text(widget.titleAdapter(context, e)), - onChanged: (T? value) { - if (value != null) { - setState(() { - _selected = value; - }); - } - }, - ), - ) - .toList(), + content: SizedBox( + width: double.maxFinite, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: widget.values + .map( + (e) => RadioListTile( + value: e, + groupValue: _selected, + title: Text(widget.titleAdapter(context, e)), + onChanged: (T? value) { + if (value != null) { + setState(() { + _selected = value; + }); + } + }, + ), + ) + .toList(), + ), ), actionsPadding: Dimens.dialogActionsPadding, actions: [ diff --git a/lib/screens/settings/components/shared/dialog_range_picker/widget_dialog_picker_range.dart b/lib/screens/settings/components/shared/dialog_range_picker/widget_dialog_picker_range.dart index cc3f4ca..56f7967 100644 --- a/lib/screens/settings/components/shared/dialog_range_picker/widget_dialog_picker_range.dart +++ b/lib/screens/settings/components/shared/dialog_range_picker/widget_dialog_picker_range.dart @@ -36,47 +36,50 @@ class _DialogRangePickerState extends State Date: Tue, 14 Nov 2023 12:30:33 +0000 Subject: [PATCH 10/17] Version bump --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index d88de9f..3cfdf6d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: lightmeter description: Lightmeter app inspired by Material 3 design system. publish_to: "none" -version: 0.15.3+44 +version: 0.16.0+45 environment: sdk: ">=3.0.0 <4.0.0" From 561f849eea2adbe261dc618326d0b6e17b547c8a Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Tue, 21 Nov 2023 21:37:23 +0100 Subject: [PATCH 11/17] Add app icon indicating dev build (#139) * [Android] added (DEV) to dev flavor app name * [Android] added `applicationIdSuffix` instead of explicit `applicationId` * [Android] removed main/res for app to be able to see flavored resources * replaced `flutter_launcher_icons` with `icons_launcher` * [Android] generated icon for dev & prod flavors * Create README.md * [iOS] generated icons for dev & prod flavors * [iOS] added (DEV) to dev flavor app name * [iOS] cleanup --- android/app/build.gradle | 5 +- android/app/src/dev/ic_launcher-playstore.png | Bin 0 -> 24066 bytes .../res/mipmap-anydpi-v26/ic_launcher.xml | 0 .../mipmap-anydpi-v26/ic_launcher_round.xml | 0 .../src/dev/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2055 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 2882 bytes .../dev/res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 3788 bytes .../src/dev/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1326 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 1721 bytes .../dev/res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2169 bytes .../src/dev/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 2878 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 4283 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 5486 bytes .../src/dev/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 4462 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 7398 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 8763 bytes .../dev/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 6355 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 11041 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 12788 bytes .../dev/res/values/ic_launcher_background.xml | 4 + android/app/src/main/AndroidManifest.xml | 2 +- .../res/mipmap-anydpi-v26/launcher_icon.xml | 5 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 1451 -> 0 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 2865 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 3101 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 784 -> 0 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 1382 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 1587 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 2087 -> 0 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 4471 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 4436 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 3268 -> 0 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 8485 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 7072 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 4669 -> 0 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 13009 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 10473 -> 0 bytes .../app/src/prod/ic_launcher-playstore.png | Bin 0 -> 15132 bytes .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/prod/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 1450 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 1866 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 3048 bytes .../src/prod/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 787 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 1105 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 1610 bytes .../src/prod/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 2058 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 2835 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 4404 bytes .../prod/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 3151 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 4858 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 6937 bytes .../prod/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 4468 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 7224 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 10193 bytes .../res/values/ic_launcher_background.xml | 4 + assets/README.md | 11 ++ assets/launcher_icon_circle.png | Bin 3977 -> 0 bytes assets/launcher_icon_dev_1024.png | Bin 0 -> 21938 bytes assets/launcher_icon_dev_512.png | Bin 0 -> 14568 bytes assets/launcher_icon_prod_1024.png | Bin 0 -> 14418 bytes assets/launcher_icon_prod_512.png | Bin 0 -> 6166 bytes assets/launcher_icon_square.png | Bin 2256 -> 0 bytes ios/Podfile | 6 + ios/Runner.xcodeproj/project.pbxproj | 85 +++++++++--- .../AppIcon-dev.appiconset/Contents.json | 14 ++ .../Icon square (dev).png | Bin 0 -> 21938 bytes .../AppIcon-prod.appiconset/Contents.json | 14 ++ .../AppIcon-prod.appiconset/Icon square.png | Bin 0 -> 14418 bytes .../AppIcon.appiconset/Contents.json | 122 ------------------ .../Icon-App-1024x1024@1x.png | Bin 34665 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 323 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 626 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1008 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 476 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 964 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1420 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 626 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1268 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 1786 -> 0 bytes .../AppIcon.appiconset/Icon-App-50x50@1x.png | Bin 785 -> 0 bytes .../AppIcon.appiconset/Icon-App-50x50@2x.png | Bin 1532 -> 0 bytes .../AppIcon.appiconset/Icon-App-57x57@1x.png | Bin 942 -> 0 bytes .../AppIcon.appiconset/Icon-App-57x57@2x.png | Bin 1771 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 1786 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 2305 -> 0 bytes .../AppIcon.appiconset/Icon-App-72x72@1x.png | Bin 1184 -> 0 bytes .../AppIcon.appiconset/Icon-App-72x72@2x.png | Bin 2041 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1269 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 2113 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 2241 -> 0 bytes ios/Runner/Assets.xcassets/Contents.json | 6 + ios/Runner/Info.plist | 96 +++++++------- pubspec.yaml | 3 +- 94 files changed, 192 insertions(+), 195 deletions(-) create mode 100644 android/app/src/dev/ic_launcher-playstore.png rename android/app/src/{main => dev}/res/mipmap-anydpi-v26/ic_launcher.xml (100%) rename android/app/src/{main => dev}/res/mipmap-anydpi-v26/ic_launcher_round.xml (100%) create mode 100644 android/app/src/dev/res/mipmap-hdpi/ic_launcher.png create mode 100644 android/app/src/dev/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 android/app/src/dev/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 android/app/src/dev/res/mipmap-mdpi/ic_launcher.png create mode 100644 android/app/src/dev/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 android/app/src/dev/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png create mode 100644 android/app/src/dev/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/dev/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 android/app/src/dev/res/values/ic_launcher_background.xml delete mode 100644 android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png delete mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 android/app/src/prod/ic_launcher-playstore.png create mode 100644 android/app/src/prod/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 android/app/src/prod/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 android/app/src/prod/res/mipmap-hdpi/ic_launcher.png create mode 100644 android/app/src/prod/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 android/app/src/prod/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 android/app/src/prod/res/mipmap-mdpi/ic_launcher.png create mode 100644 android/app/src/prod/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 android/app/src/prod/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 android/app/src/prod/res/mipmap-xhdpi/ic_launcher.png create mode 100644 android/app/src/prod/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/prod/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 android/app/src/prod/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 android/app/src/prod/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/prod/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 android/app/src/prod/res/values/ic_launcher_background.xml create mode 100644 assets/README.md delete mode 100644 assets/launcher_icon_circle.png create mode 100644 assets/launcher_icon_dev_1024.png create mode 100644 assets/launcher_icon_dev_512.png create mode 100755 assets/launcher_icon_prod_1024.png create mode 100644 assets/launcher_icon_prod_512.png delete mode 100644 assets/launcher_icon_square.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Icon square (dev).png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Icon square.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 ios/Runner/Assets.xcassets/Contents.json diff --git a/android/app/build.gradle b/android/app/build.gradle index 5ccd388..be85756 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -75,12 +75,13 @@ android { flavorDimensions "app" productFlavors { dev { - applicationId "com.vodemn.lightmeter.dev" + resValue "string", "app_name", "Lightmeter (DEV)" dimension "app" signingConfig signingConfigs.release + applicationIdSuffix ".dev" } prod { - applicationId "com.vodemn.lightmeter" + resValue "string", "app_name", "Lightmeter" dimension "app" signingConfig signingConfigs.release } diff --git a/android/app/src/dev/ic_launcher-playstore.png b/android/app/src/dev/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..00039fd87d913bced7dae9ef768ae517fa2fb696 GIT binary patch literal 24066 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 literal 0 HcmV?d00001 diff --git a/android/app/src/dev/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/dev/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..c7d106b343f6d287ff481ed4602901a4edbd792d GIT binary patch literal 1721 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz1|<8_!p|}=ur+wPIEGZjy`6J1TO?EB*x&FF zmcs6iM}3A`UEEg1pC8FD5I6s_L_F|d^9#p|3QZj=G%jv_&{6!!pqS(4aUEgVWU;B8 ziy~w0y=a}cu(}~#;Af_KD)3JYJ&-~?z zAOj3?1&>@?8~yak%HU5Q9y({{=1$$X(QxLRIaB2A>sTJ;>m2?sXHy|yBfkD3$Hd=D z`NU^TdwqTVbnoeUp7HVV0$!?LzI|hR-}wE}cYp79)2(6_WY3;8>&eB%?nb7jNB^#$ z@$zLR5KKHf+g!YMUiQxTR|SphVm768#_X@Vn;F1!Z}-lfmN(vie7<`U$nY13YJY$8 ztgpBKZf?rP#@2NHiB-%Akl)u_6ISN;ZK7S;=*!Jovu;8(7as49sY`&}qyHeHc4wZ>3 zxcd}rjgGqv^HpmLu_wDG?<)KE=M78SW}Zwrk=;zDk8-%L%c~#ymHYA%P&C+iUqf(m zO#PIf8*WKSZ4#95+xMtuo_>O^ch#XC25Zi+v>89!*Es8E^#++RHKxO+nlaBl@Wx#0 z+%+#uYmE;}8+WH&Q+C0Mx%>HDBK*Burgk1E_%X_uj$rD*-33rYZGSFh4rgfO>Vj+Ew1Y&1C)Q5lE2h= z-mAuw;p?A#7uD`^>I8*qyU^0}jlO&9bnjZ1iLeT(1EZZ!)hph-GkB-z>PZ{+@Si#E z=x&-=DKGIQGa^1WVkQR<`+U2Amv-Gx>sB6aJo57JO3m;@M_}yAc+9bAj5@FEIvvK9 zsCW?MYWv7a2NZnFo=LWG2Yi&**h?D;N$73Aewk&?jty?>Vke*To!vFf{paybsh>_a zvEJn1NlNmzosjb4-@>J?ZtLQ7qwHpLyuKb2@naq^YAiaIB)yvPEoz#I&W+94(|!2) zy^r78>iR#K`|zod1cAvWTRXV3x9p6(cYn9~-P_yQ`|sc1ukS3bCt|Cw1$KwChPzMm zx~IL>m5;tfZqP3OVOaKgS&gjh)bjH8UiTZBjb^UiT6=ZXqUYzt#GU}X$T}^1ZGKw^ z*Xr7*rxMQox^qkGect_P=X#}?+x6r5;=cdAtp4-)mzRsKpM|OqOIn*}-o?eeZ+Ef! z4W4iB?(6@zt5gz>jlJ~m^RMvZudaT2c1H5&?+Xi$fWs*!Vd=73XZd#1f)5LNVs;8; z)fsF!!FqXb?rfhuHJZ)s{NA@eJvCmqu@I`-beX7BJ8N~>`)Mz?=Qk&>`D65Eah$BZ zp77qi|J$cVn^iq-s8#@m^atw%NLgO+BLEN7R<=jR|S_Htr8tOc3jlYdeO&t?8e&YPfOS8O8Bs3 zN9BEP|FEz2kH+Kk^G;rQuz+W-eY{B6owN-B;0&&9_@CMQPiR$vtf-iafxMhO-#35b z>|5tARDF9h@nG`tCF#%4tvb{ME~KtMI%a>zJM7$B&%(rm{`zqz9!yj=?)QFsc@-}= zxG=kH^#5@}Vfj9nx0|_+CM5lNc{!o?l>Xr;^SRam|FYl5sY8S0me{{Pa?f6hgGgRA zPVTb28w!(aYd_h2my?JoF*Q3i{oJ_(kN1%H=e{DKnBXL2=2#u!E2A0K>T@N%U4Zs%H#G4jyG#=g?R1K@eK;#B9^xn z>f6}Y#Sq(HTrxRSR2eYG<=yl|i8d_g%C!FsA?G`N=DqsD0<4l4JYD@<);T3K0RXqy BM0EfF literal 0 HcmV?d00001 diff --git a/android/app/src/dev/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/dev/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..89c0f9f918905bce32453a1f41537a51bc497156 GIT binary patch literal 2169 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 literal 0 HcmV?d00001 diff --git a/android/app/src/dev/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/dev/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..79cc56fdba89d5c62e6c6de75e270ecf5eb285ac GIT binary patch literal 4283 zcmdT|XG2rV7DZ7+iVBy0K`8Q)M z+0f?q{R`vA$?^M|D5*?kV>=OJVyO4`Z8vJ}*iAui;e>662ge^BededAeBSvY)Z*2V z%7r-fj)!8$HOA-S`X9>4NuT8B?Qds4drA7~GxblOpFunX${n(7-=rJVVFb-)Ue;$l zX_<1nsa5$aCzOV2CO1V}t+c-m+wkvoE=Pq;-XT}_a7sNmq5r?RTpoc${hWy(fVHEg zxp;&yQTYGIyFKPMUeFqb}uQL|M>o$lx=Hx|6TWsWMQCs!#FJY&OdR& z(EDiZI|Jqx7AVQIjrqmJ8k(Zf@X(Og#pA68_DsI)pJZXH11B`c0xZ!NuFA>FSE=jk zaanRX>Na37va1uk@T4;;j!u;&B^}Vw+ODMq3o9$n9pj{kmWb5e9E~wr+|+sQYnFV6 zITT+3oNGJPG&FLkV+}b~RjPzlL&>QdA5tVrs;c^<+_!lB1({&}wFL$5YU}DyiHS!E z^M=w>a56F1r}yc3>{P}j)zXItV-a#MU%ViEe&y1OgOgPfZ10Qz(LLuK5>mI=fH5H` z6u$Mq=!q7LRbGu16&G(uTga|xO>Y#3H1IL;O~Td}KKX1cO=K6LJchBZC0HzRJtq?| zD`4$WnL+urzS!H>cVgDNByDP=&)_&N>TU*$3Vzqd;IffwZ!-`1_{@|o%b(3FZ&Za$ z1X!r>pDQyZMMX07RVQni)`pszK_!=Zf?#HGBG^bkr2Mo3e2Y$-O2s)?2Zx1?UGRWr zoMu_P78%)`dqD5e{QP{?@>>yEBW47$dM0wH9%F#i^5yI4SD6F`dWT)!!OH~}7s&^O zv0@22dt?np&=b0pV&eVvh^KHVbCQ$HL^GaPgKWe_?JNdP=rYZaY>1nGk6wu=yNo{V zCerqrxhm|%yLld)f)m9B_<@OkcAPuLq*t)++y-EAF#o+iNe&KDEwN5!MsNl(^6lI^ zL{^GY$-NvMcRgZ004H$@5HewM+x6aRHYj8cx|jZBa7Hk+iEitdmJ2Uq+-#X}qb zsJDlKP=wSw8SY)fD$3i@5uz;q_nU(pK&W?Db#3`hmilRIb+AN-_GQfLC~MX`6{xrC zU;HPl0jE2(&s4#y-fG{|9Gp%1V6oFgy@^|eSIF1y-(h1Hdjdo95uc=TB-V`EaWvd_ zZx#^dF6R^(s?2ivnKqYp`X@Fq<2As2 zld0H95<)4+gsrs)SeswWO+Gw(fajJ-cYvMAS|=42LDLhuaNlpa2#E-btcU_jEK$hgT&R8+p+4J>eH;Brg*B_t#S7aK=nFXz^<*03F2a#s|dnL}E=2wLe*zWF|w@KQw`uo@xoY+JWC6jqb3JW&ANlxhk zB6&@Fd z?vFA9MA?d26O({;43yvT;@kyk$7fU31dtCIFq~Jrv>?A^l<~4m2>tBt=2(*;%Dqd8 z_>k|7i;&c~nVqH_Y*WTzdrqYol~-kDs-B*n*;aRp0Oc3FGD5B6b*r<~W}3T|P-@`safom0h@WM}O+7EA&p zp*cA@z3uIXX6^AZc)ROln0Poj7q#*0r|)1h472$2Sr#dSI0Ln11aXja%qUq1RbQ`u zxuRR{dE%Rdn~h!O$ByUBmnp#4b~ar$}zt-+r znw-1+&yivHOwyis9j$R8i=S~Q`}BOqWV7Fk ze1^f9Ncr>f7cb7m#>QsD1r5NtW|z3-t@7198c^PK|dCr=1 z4n~>2=#q?^}w=_TZ_= z>8NJo4BQcqt$`QF|+IFM0cbh~n!rFPFcW~fa)H-ZyKWR<= zB17REik3*Admy8(f}c8b2_enB&#EbC>~7t@SuydcXCiU~O`d+;a}qw2OsTNa4QjPl zC`ysmO?fiFTHmpP4KM9qb+?Cj#w9KOWrq;;zX2+Bi;jFJohhBc_dYsmJA^pZc@O`i zzeqT_$81@k8ojTY(~j=$`3rRd$-I7@*c@5+)37Er_w*TOXUb9m&!SeUgg>-4R=obT z?)Dn#fg89*lin#)LarZ!&}<2?JuO#e6bd+5S$#yeTd=#ulQ4^&R~mIvo<6Mx0V_L? zRXBM99z8~t^;^S#wC?6A07~HjW9p@FiI2ia4=s{*zDB;@UOw@VH5qZGEG@+gSOV~x zNc+$~0@9EEv^?)Fzv)Y#ye>nf!Zn4Lgm!iaAUf@rdwAD6m|N74%-R~;4?yansCf#- zeCtG%0uuejl0Jh3<(en)Xrdm8n=XS1VFcM-;G6W7U*kF(uXWjZtM{dl*nOe}EpN8a zH3yShTCns=bipD(m$wRA0w`?w<&udKA4fG$XK$iZ{Nu=!UY@ATb>9ziLm|(zS zH)6Iu)9Pt|e$+X#Rc_;2d|y|w0Wa;#Rc`YO7ccm6+nmgqTdYZaOis0%$?jbjHEkWt z-(oG>ViyMo-%#pkh=P=7F`9V($7h$&d*9x-?v7qdFZ?x?r$djVzD-#0f@R$PI)m(; z?(7@~rU5%@rXqch4G+JWJjJ_LmN*o7yQ|q@WoGE%Oa#2DSjkjI!eo|5-?=&Ewy0$F=FW|rHV(kHbU6|KF2-u&r=$=u$iHqdEM`5v0kFNNwe`^u_* zRxa6eXVpimRQ36)ubYqG?e&kxbt`G$&l6P53XIOqk8jA9zjngJqt~p5rwG1j^6AYi zUX>Iy(0=~@RSlLIxW|}0WA0+Of_H%!N*36Odljc?J7sG%(h6=4$PwM4fIcG8hEA+f zTv`31e7FDi;el~Tp@~im50lHja`h$wjYXSo%}RG8Ivu^Llh4>U6`}c zVWFcR5?X(}Uw2k}G;bBf%r8Q@LDURcA6k+i*6Y|1LNQ2IB`~ z_iQR@+Cnzp0{|bku=(X|>tV(Tu382@q2_sDPv9!h9ugF`mvQYH(}S^xwXe7akOfX= z^#sq}Ir(_6_H(?zt)-LB2|x_3E(|G!*@7F`#Ytm*SOO|ETV;4G-NoP z&W_2+$r&jrDHDm<`Ggf#tMy}g-Agz|_?mEua76&`@!3%vBaU5x-{KrN7tX0(gG!qq z^sw+O?hH>%OpGVu3W=~k5OKQ+7YQs#z`1te+_(m=rC!@|yCJmtA_FBa>FMb`h?Iwj zl>a4yPP-wF(RX$9dQ$>_3)E}CKi3|sJ)gj7Toczu9X!>qHI+t&B_$=1?I|x15eK#8 zs07pBx3u4zz%7k~wBH{@T~H@a^$q7Db(R+jn5ks&?+NEsf(SQ)NVqR>htTT{yjMO) zoqmrx%KEyCPhnG3;;D5-kZ}tMwbEckE}DaMPr$XcQiVD$M4jE)5)P$}NcDIj<0g?o zM-&6K28RTc1|dH?Leex@+97NT`Q9K$sunUJhOkO8NXm@P_)vl(Px3R^5F_l9BkhnZ z4MB@q&iyu5zAlYWTUNM0t@BaXxMb=L?G4RVy6oLoed$U$0@juYe{3v={x&=OSg9S#SZF=GZRDk@^-<>l<= z&6}*gzTPz8oNe2-u~%Pxl{+KIj)3h5&MYY@=>?UepcfhK>0)DL1%j3BP)5Oq4I9Sh z&6~$|?b^j#cU@hbj?6%CQiHZNBauu{91B}fz zy@0z;xOh->KQl9v&73)t?cBMO%ZZk_rog##=h&)Mt9U#KMywzS;&WT{daQ5Xz6mO4 z!6?u+4)XH(_N8H3!a~JX#Pf-W^ifk3`-<3?6cP{137wyp-iIT22nqH-5V z;QW_e@duJCQjc>K3mo9m z=-7a3zfIg+F-tyL5VD<63%LGb_wL;+KR;h*m!IGxWaj;6n;7i{kRcjGv5}+*|7EpK1-CEgm&rFO z@DAkXHE{yNtsnFG=(1V^!X1#)1q&7!9-s|PO|4(+bh35n>3;;bYrOOT8KFDS55K^V z%{Tx97z|{z2DAp0l$5Xm0|w}9_JmP(J6o5TS-&SYmlbDb?vA%u`OKz2qD`G3mFVtcZ)>-Ulawq#}1F0xwtgJZXY zGU}<9wEo~t< z7F;(fGCyrk1BbV8A~U03tX|MoxU~UuL|Fc!wH>lETxt2z0o)0>xplj8a@gAR^pzIZ z5*FQfKnCEB)bfjQLZc4A96FYcXe->>fcw_7XV2Ez56xFwz6N!B$N?WZ9G_Zl2jWK4 z68s*fnE&|_Cp78+%=cs6j<&+B5lfaVX=FRHo%h|ee2FjN0D9e!k+CnqH7}%_oa4jf z=;-JeazHswYSaOvM~`mx0ayYPbg&t+GmKmd%$G3|b z&49365G&TSm2Hi{LND0-UGK8ffD)04Zgx7WABc&`^5lTFxP@jjIR?O5&DJ^q)8g=< zL!5l%`QBQ-)&ZY7owXC=;|GFkw+^5lkV9mCW5xl~r%!Kn^FN+YQ(Eda+wlbHfWJAN z7stoM4E5xIcI1Fuvkt&2<>p%1){?kHiN?W)9@3HQ4XOhQVq)?n-#Q1x#>V2wBc>#1 z+O%nWA*{B-tp;^ltg;0K1uR~>*LJcd-pqXQx%BNK@D3J_{E4aMjX>+`i0Zw=tG1M=OF>knia zT1;u^z@9zrg6~H2K?n*!q}hQOcBWu+gtqcw4U!$+@+rkO)AAMYf!Ie5$G#|wC020V zs0Z--z=WPe{6;elz_uXlOwkz;#<+ao06P>w%U8gsBL0+~{wW%{;JVRN1fPf_bWci3 zT5iSxxKp%d%^IB%;R?tO54d_Vje&@llW|3M`zqoX&nMzj|EdGz{ot+%2?@^&QZW^6 zXgV5uvb2VT9Y}VrR#mxD&A?25$eJlr#ezyLo;#_e=l}=cl>+b{;bkyWQT2ULq(Cyl%z;0AvVj?6n4lGA@;r_?%uS{mysT zfr0|v=f1F)BxnaI!<#87xEmHBICfvem)&DyW2Y*l8VbbNhl}}gt&t%KOfMkS^d&p= z-RU>pU}x8^WhFy~=)d;_R{&;zC;fjWA>m)aEj8-STHe)y!9kbq-MeSffqXlvnO^YN zV~??~zy4ZpaEQUk^um#uGuic;8g^jfMBR6uAoYKx!*L?MYgbG|cd_`fTL!%#Ix#WP z^p;d?g2p~vt-+xLp6B}*WR(mY*zkUDULHGNT+C|7u9886bjRx8%KvZvm0JHj@$u`3 zQ#|&}v-~IpDN=8ep(zTfhGYo9CTQ%#)f(R75Yr2sd@n7(bi@dDX2l9t@$9o~-?zTS zk3I6EAF)fNrT(RK1~Q_TUV16y z?h!!q{h3(XKW-eWe)nB={mdD5;j_+ah^BXs^GjF}6J6?-Va&qdvmzKu* z_U(JHW5wJkFu{ujne&AVnbHetqEyq^|s_>78Mn>L~!Zt zsqVT08R|)82(^Aw_Xi}f109>7wPZ9a{G47mFku2a|H&up+VSJ;>ak<&+(#d={SQ3A zV*ygolZzL#D@Ts7o0l%J2+s}yTS)$J$m%Ghfa0|WSZ>-Z~}IqH~Rq1 z&GZ6V^U>#@XI1m(HzF3AkCu;?j$=+NTEs5x-OI{<{A2DMU-|zAYWd$M&9@1TsP)%S z>mLaY30`x5PX!*s)M)}`L@x)@3ji!##18c4T)N_JdZA?SV0P-Y*VuJx3`c+c>qZW^ ze(oF(&{eyi{yv{4?f5a?d%&q zoReQ&RK(x!9Xgbqe*JYm&jTkwiZJrUsJEPej7Zy)kZL|ivLiGf;9QXORJL#5ei*nS zn96)SmA1Wl^+GgHqG9#p)Xn5GGfhj81meQI_uk9zBjB+Hrh0^2z2IYd0l>ftExzpW z#~VJw2$ws7T0NH|FLOPRok@*bzRY@V5=S$^k>IM)s)t~d4wP0!)2p4bqD8@o2U@@p zFTVI9-;HR*5m>S2&-4NSU5CURU%0T*=VVu?=g;#jNc%egdH#gk*-j(fr(FMc z;6`xd_KsJe1>FhLspwt~>Tauq6Yx|J!_yR=fF3cB@^B2^-hA^-zT+NQlP8BXtX}ZZ z@*9YzH1zbcWxU6fO`CT6a|*)eH*I2P-hSI-zycgi?RBhcew6jZU=KbDgT%>hT z^lBvxA}4HBFjckta2IxK}+aO_IjTxgOAF_i~Q=|D@c8L7#Wcv_sAh^&k zwraw{S5Sz6VI{up~iho%p<3hl_K|XuI+g8wE0kfLw^a5d1R7wR%X-da?<3wK9Zl_?IOi zMZPSk5Yn)2M1CT@rV(~W%)paTAjJgXOU<+(&@d@+N>kn<|xolbY3MH26M{eCMc(h-=pMLvy{1F~0Sff(F*%ZrF8m=PEE(-)GHUtVmr zu3ny+x_Nb4+V1z$)63SUr=R$X!*OOqM#fnH?>}@nPT;#Wbj)(Qee)8lb=3m;?Nf1a zvvDq*Q;?3QmEc;qCa#S-pf0VRcx{m}g6~P_PMRA*L9bV*PRKg2nHlrzAS;K6>rWU2 zxuDjYZ|l}=l%q$Fg3R8%#{+ne&muZ^9*$$gv6wD^rsEtqmmTX}MPP-#SoA7^zwsT8!Lcd$t;pYTqXg%~xp56# z3)lRoCf-v~9fG+Q+=T;i`1i3`X@Gx@1HA^RD)1S;!!bA(zrk;Djyr@0P(Ye=3INFf kK&lG)xjat(E~Lvp0J0^Vo*;{N?*IS*07*qoM6N<$f*BB)Q2+n{ literal 0 HcmV?d00001 diff --git a/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..f1c2f64bac8bcf23d8191dae7fb8d4ff261186f8 GIT binary patch literal 4462 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 ^Z?0d{NYvlIHgPF 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 H>+t^pL)HY6 literal 0 HcmV?d00001 diff --git a/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..92032302daecb5fc9491d9cc1391c6534dae522f GIT binary patch literal 11041 zcmeIYi8s{$7eB5PWl8b2l+YrIq|KnQRFou?Flp>U80%yh3`Hr)l2G=NCB$SKJK1F| z+l(25>@kK6Gq&OPGBf)8{)F%MoNwnioioqp>pt)Eu8(`~GvuzG7BANkE;cqcUhP|& z25fA*zHR^Q;{bkX(K|20#wIhZt$EGR+kB3={@!Q;)%<$E8DG9PTPGsQdy(gQugI5!-1|K4N$>VZIehi7 z3uVbqG5L49eb+=BoH{T?sv1TYtEr#154M{0t?nYxO{o$ay8sUUulx5jn-+uiYdm!Q zR(h)H{)LQ2&3(t+Z~F3&=!S+IygvGdD)~J@NZ|PMhQo8(PZi~)uI~%Egn!58`tZ*4 zgZ%bI(z}L=KI}U#+4)$1ccsGxfK1}AsOsr5qtu5_OU+AJp*hsjhXsIh6Uu7!rEvb*&LO@!tw5jQ)*Wb|_UX)2)NXsT+vxbgDp{l@7rtdDeQ~%0W zE(Ag=5V_Ez$M+Ui=jIQq`FStUX0X=_gqfxkHH3S5!Mb4|?WYD`*(znKVtE!@fyY1e zBH=E0ZEmbuvN^iAAQW8&A74_s(Wr(-`LFwSCV{8Ik1CJO%*+gyd(IA4A}NFQeCkL2 zP>8*m7GP~xrbXWJ>8=R~Q1n@PtZ383LurmzuIsaWZQR$bQMYT$4c|O74r$YV= zX;#gDqm)pMs(=u3ffb`-sZ{u?Fdc~ zpP`#D_|>E^FrdU={?;PP>7w3V3*y+T>o?XER%_H>?1U}CX5#yDAjGWunSs}QsiXmN zCwQI*6>;k#>x*nf)H>DEra9bG7Lvzfyw|+i&t%<4YJg@nT#a&Bp6PShSov!jcj_$D zThrDqx{X{_wC_AhTWpiBcqgszxOMZ{CHu}&hy|)oHvuHKQvHV(WoW??;PQAlnCupz zzUlofMW%!DaKdsJt?ElH-ODYsXIP6q6g3mV3=LU+o66?m-BaS)v*b3<|)E3OD ztw&#d?q=8#!8P-Dty;`*Vkm_ej8eeaw#Dw1HZiU7H}k!4+cMM?b_`nZC`1$ldoaDO zFT=78{s0a>agxwE)9C|8l_GJfP;ILk5fZUNamAlc?8@b(!ef6~R2ziB7ab z;f}$JE4K?R{zJ^+Co=BD)%`LO3}L>a2S+_-A zdejnWDS`ddlWFqt-YL?QWkTxQl(o79J?`xyD;h>iQ!Bq}NuVx2;P0BNn|Y)&@9a-{ z#wk8h*(kzNd1?gR*tH8=U~l_rZNPz!P_S$E{L>YsDZw;&erKsW9}b@FzPgC(D^T^j zACMu5XSv;D>nWjgX63yK3JMMunt`~kF3>eX*ZqJd$#~X|ZW}%;zrT&b#28sfk;I8- zq^Za1`s-ygUGdT4O!5YPK2*{laleIYv?1U5{Nu{Dq$vk=$oeY2%OrrBw!$JbYOQsx zueZ0f(7wxYUgI^c3!BVisqUJ)%fOT+4Vq0?N`cl8+}{d;%Qi>`3+e7GSaa5^t&<9C z1p?oSQ7M>AD?SM|6+?kEUzWRU9=>4xJSR7I!o=*btvao|y!_*VBG9V<=J&5G$mO$n zmI1<{3I!eho32&M#&`K1o@|h3ndt0bz!sfMrwwDxgLw*lzLo!cc-)Mo<|pFdxZexE z>+v;DKb})6`@GINQLH(>r#6VQ*mYO#S2dA_a+dvc`;({#A?6EKo^^AYTdbSA!2*+& z<)6Ilmm88dNzX0|VM(8o@mK`yTZ(Dt(QPPpRf_ytt>AB)`v7b4)Z zkoEls!4)r(CZHj#&q9b-#uGIRgPgE=dzZf`#K$njXL}q7fACDbq;9p{hV6ha5<9`&e$|(tAzT*lijNPni@eT!5i`jncBOX?U##QH zaaRH6iW{j7(kM>IXm8;)ui5liux8WHE-LL#e8Da3(SJNUUT*r^72UDIdRV8^%=;2v zN{}$S$nDe{vHdt3q6sKMQps)Psi=aZ;g{fdi5r2uVwED_@AAtP71{lWI#sK&_nD); z*Zx>Js8IHA$tkcHk2#O!=@6lZM{H_3#KDL=>wE4N&&) zlX#3ZocpQ)juOje*V+Zo8BX3FTC-cleoUZKu(S@9N z-|8jAP(@{tZEfIQ*u$GAOo(cmD`TJH^{!ue`0bZD!*&+Bqo0*2{!CW&Es|#ovErmZ z6mxQhz%ztl22^I0w}`*!jK6$wP43^E++i>eDkdb%w# z&#`$};Ir&F$9~n?h(f6om$PE(K%^%UJYU%}M<~(vWs7{UPMh}%^5`&ks_H&t*Qvt@ zzI)?>+mlrZWw5Ft!&g}_))A1v)^ zZ;17~0%p2<{4U;?T-Ge6?r%CgdvylqvG(h;*2^LGdw{;G?@tnfUoZ%b>N;lVr;uHS zDzml;eeJYw|8U5MPxI}Uf1D^~At&SPmrw`NV*4tpIa6DDKXA&2GBU0ke-D_J0YIzF z>gH#?_>awDIbJ!wDEa>cpfXzz?r?+f zOe%1G%0fL~MQ|_&DuO-B^LO1|TCOWfcFBC&rL{_XK$;OxermS^Fwj&-Cv^L$0-qH1 z0RQQ#pTveL%gRlszSMjDL_f_@PR7+oZEf<3xcdQR* z$|AX_7s$$!lXfUq_AGl(*Jbp42$dhZV-wt}4kp`3`i|sTdGn(_`u_nzLdIRi z(2GG~Z%WZuvkK#3>{UAeUrH?{w`B7FyUChlx>kfZ`Gv6gPuk_k!(FO0(*?DkwBS>n zTB*_e3_o6zY>YkVI#6(9xaX?f1A0kGbhW|1?>8jVA!u_K8kxA3%yF@PW_XBmmG)dN zCdIgMM_UKDv|m@b1MniqEVm8VAaJN$FLkZeq5H@2`qZ?EblDjlliBhe$D z?-iZ9v2F9)>qDhsVPXI1BM9dmAm)t1*G@R)B`%00v##@CoYkis>Oka9(_m;uh zxc@9*02$Sp&tNTm{x)Vw>m4JtpROI(X4ombAeUPxmQ3uZ1CB4fg9m>Hvz} zpzBd}Y{6e0@t6*=jWw)B&^3NWFk$|F)^Vc`ZQwo;6R~a4!0ou;mMzh-LRdp+LN?2S zw|B~DKDz1ODSN7fm;2w>YUdv{Hj04_y#Dv~YhFtP|E@?o(A0A6^si4%DY4tO$++2J zH-ym9NaHY|z6u&%x%uT!CL_UKIW2i6@n%Htnn$N>$Nx_f3o7T+40LoHL9B?t5Ur+@ ze%jvdG>6&#JEq7979-sSK<$RwVh<678R)GhzGpyL&gW^ie@7e1O<|&V&Zm#ckUa{{ z!^y2Eb2FwQo~NZ}WHc!#DmsDLqE0p@M57qO0)%!Ex%fzL>}sk)U!N_48593JjVyX| zRJl7zJ;2;|cjP_?@Q0EQjEeyaID<8yKyk2O%T5q$ukdu56oM5o0Gimrs1HD;=gfC? zxpifStsqG|`r0!7#MA7Ublp}phVp8Ug~X``R6991{8HOxCjrxH%Z%Hqm!&I}JTKf6E$nYBbz5h%H;MX~#dW zh)61QsZicv4tyMqcXTpw#@%3SK6cB|uKmOB?GQ+3{~`j&n<=5dG`pqgU*v`m0ldc3 zm4Vty0_K7@k}2H4w2XkQ&AhxkJ?Q>}@}M(b;Oz)-<)EZ;+k1H|Vt2z#sw)2rS+on2 z)H6wYAk(Ob@(2pFBi$$Z<`}X&7CFu%a{g%$>QD_}Z!1lrFoSa!8FcnZGSUlBF8!qL zj_!I7HwTu~SWBw#sZLL9o>>owT{A+r^(`Y`a6V1Tw5ahvo2hk{ggFi|PiMeb&Zn0j z0cZ>F^z@eddDkZlVNa$6x5q2AF>>gEyH^q@J``PJ(VHUM(ZPAsq2=RXg7wxW9q;qB zdtC9%r71yXW?#)b1(cw@RQ6~|CGpp?=v$P@@6P~ilMLD{dPKtIlY!8O4|XeMQu5HeQADc zXiii`X=zHkOCBDCeLgs1J8#6`YQv#5Q5mlEkgGB0XKf{-Z~0H^4f4(V@7Ddg#A&r( z?tQ{aD%Z$}R5Gey{8CT!Gj`5$poifE-Cb!qn17NgE8mtGD$E)5-r)y*H}watTG&U| zzy@wk6Xang2j?}1wy_9x^23J@(-d|k6)K}|!wfJv^3V*6>2BA6S+x~B_BvYk;ZTbi zk|-PWo}t#zGtT*C=Y`-O!ADA9S<_Mz5nH43gB^jWH;M@fX7s?lpRlLSfTk3xlUQ-2 zF}msNgZw(P8vm+~H+Ic^i3&pUZTylblR_%xpv=}^@^V*!_9NvKy>&^JEHH8*{essp zsw4-EcI`R%6qHS}9Ezw}H^UmZon8(DIy12TuRmwARS6zJSezaQD=puDSO^;^7?j5; za$ga0gZA|23f3&jv_Bh^H^aD>-yNGpzchz*pI23nN6_-~eh0mMJ;*(XxrjO&YmFbwhG9S2>Y;WSwHf*WZp;?l-@0EGRI zrY1j(d)=VpTIIPu>+Impi>~B{dGuqA@55?u+QZF{Fj7#)W&4GZ+U-)lig+;6Oc0+o zNc1zkKjvau{$#yvbCjF*`}zJ)SR)-+mY-G*FZeYBYuv|Qf={*+ba~>8fG~Lk+HWzv z6hMaCl&&x6Z%Qte-);(jxn_6hpL)3uU$T1xMy)-$rlTQ+tF45V zG*w%k48U0V!wck^N-KR!*2hDn2cNw?se#7g60tApg0kRS;XSihNQcpb-#bY$^o(r& z)QkL&CpBb>wUrfHHa1;1GnQfXAPWO{Va3X8Y5?oj+rd1C>#o%tHptR#MJyWvVRO9>3Yo7m^9c`yRV-K1_{_)MJU<3l|Rs(U=(mgB==Us8;SPblt zCJACb*U)*Xa;X!XH!)*G=ZBhY4sUrb>#O~t@=1uVc|%d&g_bu)V@_%fK09>sIy&?u zRCOmHhn~>^in$1Ap`Grv^{aS8f|RYOn_4^=t5CU?UE%&W)xT^PRK^wl2sAQK_G&ev zxU2}SPIs7%Ni-`H+iDKrp^Hs~cOb(;AMcpHtsFx3ZI#uTN87R8urUVWn;(Q!k5`Z_ zy}~nz!7ERaCSzpD-2_)o_@mXA55@f#YDY{PDrH~tc{$y%$@)WCW9LIQePYg*vSvMp_wn-0l6BK0|dT2yxPd&~U_wW@*Y~8QqIG(OI)(kbtFc&TpPu zLbkodze2Ncw{@#y>^ZZUym9}r8;c5k{ldr3*(=?R)v^l@rqa z(x&I91Sv7tXTR%-e*;!HX^or`dngb&phvo9?E%pS>D$81bX}_t4|0(fEu!qw^z{Umv#+#&qufo0cc@{N!s=JM5MiX3{{3mRK(mS*S3!q3u zK`?O>{8xYLzoX^86F)zJ&_4=o(q~e<>wFJ#UwrgxeZ_Ye{@x=1eIODGuX%#HY_GRs z^ZJcgJCrmKOk^G+P_|6^W|U)GmLp#B;;u=|l@GK*egAH|gZb=;Ims~k3u%XO4(SAm zoUKh7L9B&zM-w{!Ytlx=T2?qhZS70NLbpz>b+}We{_v5?@=GEJ{))x5n|F4iMabao z8h`p=VVByh%M%aTeS*E+qeq6lKc7g5b{>)qIFHWHNg2`pk;HTCCAp%@%+bE)lU%RT zWxG4m%WC;X5icctTEvn-x%DT%l#3=%X2_Jv+dFJ0S=9%Z0Z7VN$~eK`z+?ySMPk+H zuZS(!@(d``DscrHz+0nd&7P}zJKb$7)=U`%qZp_AsUDgv7TLjKa#G!(lQ-Xtq=h>g zv`S43j@alcVPa5b=j`W?VY<77?vD>7=jP?@p6imQQ%m-4?VEDBd|A_nfbQ*$L1y{c zGtKA3??F$j*>>~Jwdd*G!wAARoGdzGYom)8*7iOqM~c7$D;c?to;?8?M$p^i`q9lC zmr%M^2f{>!kN$*CNcNz}@4(hbwfEuvhid(|X=iY*-^R6xn z1uwOP)b!gxM^iStwn)@tb^%)*fg0YHB{kEKzf+OkNu%J7 zHN`x5vzQPa8b^_7;SAVlu045Y>6>Xq(&KduDbkewfofeMk48~VW}69fnyRx4BZ@Uh zr-%o&!?v8u93{Nq(#3*jITLMFFA<@CTS}@0eRQLdpLhRDdIEp0Ai!^x^S$>pYX~AI z((_eK!q7G1K2Jh;tuX~Zrx2-fqu=V`P<4>vbfRf><#Jb$to*>pQP{;~u;Nk~*ZnO> zK;N1Vbi{orzxg^kL7PaHPQlr99+~0nvYkouZn^yPpXjO2|Z{eDK!+J0mYJxzU z*|nt2h^@yJM>iWnM*6MKPuT*+&s3#HfDn(l7*Kvt02r1l0jJl!u>4$5E%kas#%sdU zLXdYy38NBFYYPaZ*>38~1jo~nx2F&BnXme}b*Yl;x&p+-8(>yiE^af92f-Ve0Y`Ye zb3H83yszKWNDgpM`yhxG+}t@zbgbjMhEF-o6C&GPrZ z>t9xci7I-K3=OTXe86(#2Sdyqwh*JOF=m}11FNA)4pjhX8Howy?Zt>l&QoYZa88e! zqkm>^hnOLa#&!bZ31Wm8xY({EK9Kst8c4dIVF1Pul?+tQM+hPI1U-<3SR?%I|JFFg zy_XxL;vzZ;AGO#__uTbTIVR^6O7~2@GTO1i`2hn(%SjoSlGsL+;gdiIm>-u2xt9>F z^GfcM>q^SjexhE{wXZpZ5NgB3$nPj;wQr3{zSIHBKh@RMRlV{Le%c+YT>Fzr{z<0+ z7!3w1{#|9H;%&l&Hn;xfYvto84Wv&W&XT8-o8+Lc328^K!McpjOG`!k{Nq?yI7hrf zD@=LeqJiHmpmeEAB-Z`4jDv=O2U3rhymCtu4{`HP$8m<*`09%}(?Lj`R~_1@ z&44ZJBqD`)q6pn6bpL24y}b-r0M0oiz>d-D<3FU$>YdPKvSrt19+Kztdld43E>vDWmQ&vj zGnN_H7c6#maoQyt(4IA;lyB5*O*jsq1BeaKY;UFWizlz>7k>bqDG>%|XDwv6aJ*Yv zrD&jK?|i#D26#Quh19w0JLoRq!~ue$U9-l3k);;It><)TAG2NS0D+n1X?#T>VJ%=*W%D+!?&hnc^q>8Z(Hrh>j zFi?5j|H!Coygc9uGz6a1tP|%4m-D2y-T_5^abNHSdEDuCY3i4#K#PNF!xf69s$bBv zXQ?Xr;gbzA7hW07{?FzO&(#O>!gXTLx;KZ5!LduPQYEu{rEGryWn#%{!MXV%v9m=# zv7UnKUbtP~%e}q=aF{lbZDbC&zBj(SM;`ZhXPmWoIL0Xtvmehk{*pAVKE^&FOb2P1#%u6?2$?xz;j81uw!jzg0CNrIwEG|E4l%UgnDn1bRzsEh zF84u*z!ap&)i?>LUdd-M!>u4*;VbL!Qlg7EXIG+5eOf)=)3@t;BhXN6N_X3V*>7jU zRK40`hk<7Uc%b>-wcQz5x3?Wg#DB_-Y%s9?I0JRT~xa}Qo*Ue zGzsj*0eQ^J%lqqWS4j}E#960dL{L((6c^=#8V?~pETWseRGG}B@`>RmXJ(tyb;zH~ z;D9fla!8?c@6c=t&pQH4T76f3za(xyfdHODn3|a-fj!1wfxXCy72bbSom^a~&;pBE zAX2qP9N4>gpi{5Qu}_%x156 z2)_}mvrSwt&cgd%OQ)g=kaNmT-p?qC6J2*3)%4n2og$E=3w!3~qJ8NbjevLR*8dNN zA72Foby8#y=F(veaf={7Nl~>q=c(Vdq1FMPKYeO@)((=l@Scci(K~{a1I&gs znh-c1FK$t$;9V6{S1T(4Ep>JXR;QwhcUq;^CnReugKA~*m2dw75ue$I3W?0(F@M_(Iy2lh(&xg$ z3K*cj#bf>p2%hB;wK?@HUBjAUTh*Ha!&-n<6ENW$s}*o!Kqp@D4CJDT3ahc}aN#X! zg3yk+I znEwg}l0S3KBcSb7;C9~iltJ6yyEj;4_B1fYFu5=ISCd|heP_xCuYqt6jU&^VAa zSyxPx2Te8pz5DAWu)=zjq76~{P@*zW=UCsuN_gFZfMud!?-mtBDo^Yjs;~4xaSa!P zRXkjIf>lvz`@^y}E(^gl#ewGV&hwB0V2UyEWA-fWG?XR6g8IO)>B6M+McbY4Tu3mD zyvo$Dq;IuS6FYB4Brm}X!qtFAUwCZ}iB%~5c-?{2wd#~z{HCp3&6552^B`o~yIfOb zBg-125>;A91d*7j>Xde5BXj&O74-%v|4{&cA{=NO%gnRE2*S_2N|DM`UbuM->tb0$ zfH0AZvU<2Lk68>aHyMjw^u8eq{_wt#SC&Q4ASqv2KDJdWLD2(ZPP^!Bq{5h1-AP-s zmWBamIm0?br;tWkJ2V(vVjq0FXT-Wo-yzVM_tM)fM!-0;ncX;ntZ*EqvUKq^2;`lw zUAD$jfQ$s_jFv=&b4v`wll7v;@EkA;5pxl}DGoXV@nRifTL*}*A-1&;|E-*LN11ml zBQEU9S!4Y+8qtBguzer#88r^HCJR6{2m|v&5pK{4U=^qZJXmLs?oWtr6Y!Pf3W5~; t`-vNr3her;f*uF#=>NKRn`~*gEp`L+*e4BWw!k*`+Bftx^R8P4{(q~AfL{Or literal 0 HcmV?d00001 diff --git a/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..5711a6656d3a57fcd9620408fd6e0813673606d1 GIT binary patch literal 12788 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 + + #212121 + \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6dba1a5..a7d420e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@ package="com.vodemn.lightmeter"> - - - - diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index de34bbe32f92571a164d5ba711e34bd35f965864..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1451 zcmV;c1yuTpP)(K=3Vi@ioeq`Zv=XQ`OG&v@=!RLx1o?5T^S3|EH?D>iaY)$qhH$ zaKjD9$Fs)9#uteMH1Q&>#&iA`2^3G(_F;g6f`Tve^Ya6Fd3isupKlo7JB&A>+yl^J zq%qpiKIrrLQrV#I8I)kW_jo+154A=UAJ!)u=&#U#!32ZYjQTt2KXc6QNuf;)%jzo( zqz{;21ermUlaurHL(Qf_-{si=-|2%HJizH_26?^SAEDKXLC=}HKk0)RJizH_24!bw z{{pR640^!~`dJ^$-~moYH|SSrwQA6mKA6D+oQ`hLZ_sMhptt&91`lvLxp|PrM|vCs;#Y!wORHv$nW>l=;$bIY;4fY%?;h( z-}3Z%F1YDWJH@KcXxM!_-KH!tE;Qj*4Fk^qtqLO<<#8V zOlxavQO}rgz+}v*@$qqO|Kgu(614^u6%|o$Z!hic?g|29#r5?yEiNunU0t2^m(<_iFXZ(I@(sePJeF@OE9~s- zXs2>MHv{AvghL?CIefw@n3$L_b4HS95H{vOAn@cvV5~SiJk;)Te4ZTg48q+C*9SgP zl?)6FXkQ$ks}h57@l?I{@GLJcYn1{%SLp^}t>aeCC#ahJ{e7(hz~?L7Abd+GS?~#} z1~a<7yl*X`TNs1_J8H;$a&};9YD&mgxuD&)x_&mhp**=d^_J<7f&YSVHJ!mS?d7u7|xtE(&O>gp2mGeE9E z0PSFvdl9}IEOnEA(d{*(@+QH~}@*=H*SNX!iLNpt)5%w@h2c=nbJkiwS z1)BxS6^B5ab4X3rKqU~xF4S{SvcRp};yx1&`x;~uT!SJI6NB9U)i4To21SSm22JRL z89c!0Xa;#ap106y$sp$LH~L@(4{$oc+}vDBPfvdht$x4%CGSJHc*gjMk>&Mz|AEsO zFp&r?uMMWr8`28RQ3XEqDmgj10RzEp44Mc)3)8g8w0!}M4D-v2i;o!|Mnzg$+P4`Q z8NX*`W&N3%nfZ?Khr@V>+@S$lpedy7lm97>GBE8vWn?mn8KsQR9S$@=O9tb!BnwN+ zC|<%BE$ylYs_kfhJyLECOyP0&ckBh8vEEe*p+x4mqW2JwgBg002ovPDHLk FV1jyhyAl8Z diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index ae5b4264af3bc3b9d0ab8ecff867cb694050f4f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2865 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 diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index d49e5da819114701a6b2af2174565f3c8301e458..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 784 zcmV+r1MmEaP)Oix7+7B0S+RmDE8b#TjB9WKC!S-Nxev)uxi9peQ!G3|kTK7Yw`-7#4LsQj@;qrqCO7VC66tlRCn zSNz6(JQsZ)!pQ{G>vc954A^8cVYAtc&F6Er*=*Q$yLGSljr(}s@AuvIVvHat7eI>* z>-BnUI-RoBYUL7s49n%xZ4W>Ai!pg97cd+S*pfzJ z0RD(0##Sl--98$P?#KACfC%(N&~Q>B0Au%mhfNp|4{^m@(gmP;U;>H+WB_r+>LgtN zN+7C;m|O-B7x9$|z#@b?E+&=<#OD_~sRFQ)Vlfhv$^_ygj}igc4q!zUlgb3*BaadR z*we@=onb(HDv|l&{2q@p~b_=-nuQ zeLME=#~x;UocuiC!`KrU52Me-0RL7Z>Nz1+ZzX)7dY}Xv_g+XuEZ)pjOn$j*SytUS zq6cI{=z%Mqt7z^=gKRcivTggf7a%qtILhVnO(v76dRzkq!0`DdMZ@SjIq&@&x&SUT zGJX)ZmmbGZ!^5*=GI>D`KS}j1Isc^|xx@98@NGT(!APyaH@i;w7-ZwN%5?&MDXa+cdOJwrAoj04!7dinBBB>{fll=oII&z+D8FfSe O0000P~m=#is~_>|Bn5xDP`X zI%14dsgrI4xmHhg*Yr$PwdaFFg4$i@-udb3s$10)6NC^#2qA zH+Yn$A0;LkFHMi_NDbGC7`6KF2(QxrV`9=I;KLNesTP2M9ItE;Q}?CebDcVwU~v?+a5P(L5WN{@UX_uLYc zQ@E~dY;4r}^;Z_OiMEHhww)(AV63uHcNvUR?RH!5?Ckv4+Z#7%8y?_A`YWkznUAQ! zT$1vbBEh?QZ*NcE-QCF?jvaWwi{|-B`;pXq8YTcOK{$o4qL7~~3B16Q^jSv8fy_&k z*7WuDwai&?a82{eW?+aYM{WVVWZ~;JM;_S|7QQ`3g?HFhQCv6ebdV=CeWr&+sne86?wF z{3!Dk9F?sid0@6knEg!^c$e`wbSU!`9F;BSkwy!JDf?7`cNvdEUuC|6qp~$v(rBSj zXOSxKF5_|NLgp(t%D$McP$-T`6?m8NIMkE*3Xa9(K*cmFUln+l@wg=O6&z{MrPPt} zxFqux9BI&{)RFPHB=Z# zDGYF0j24Q6zk%WON}-~iUf~3$U2#re0#&g@0BgNM)X)3Us1gC7ScGF!yhS)Hb9nj|G;+%#a&1WR6|R(=jZ1i_%5NiOSOUTVhAiah_M6G_{9)_%Z(CRZUlx| z(1%5IT+kN)#U-<8!A0o_(n@UGhfb&C+rhY3y4ybFaATF!Xw|%RQJu?^xOGths>aR1 zF!;*N!A8%d3Fw_AP;YVjy)mG;!DVuA3)uwWCe10LvTNGV9gzTfblafcGpYEXf%L$= zOMY|hJt8s&@lhTEJ}f6i@&RK$jw&_yz_&!+#fO%r4N9L;uinZQVDPcPgb+dq oA%qY@2qA6b8!3uObi_hTnON6zi-Sf*LoHkhpQ<#swiPj0+oMQ===I7!!?)8rE9lLKn6X z7Ay=K6Jts=hM2}Bq>!!^L#Wz~O~L2)-8tv=_P+au0p3ifC;9ST-`so7ckVss+#lM| zaC&J3&P+{BW%zV|^oZS-eIJ=L&CJX+yB{gVVzF~;iWLeCM|tY$I*Y+B$0Dh)lf^jwlE%0N(?5f$*4MANF0yX0shW z8)=G(bA8X}^A}+FmP6=2d_SxNZ0q#BMV(?tXCt-zh!PVP8GHt%*=IA&|Ik4i70uX=yO+T5+)`l!s+ShaA9E~Tv}QRmzS5rwY4<^ zzVjP@V;i=0``fVX;rWHd>FC7P8jp^bTxC8?PELk%b93R!%1XGqyBi)H9E695hhFeE zwxL7p!@jOQ+X*~rn=|pA%`H*12BYKic`IRE`NWgt{%UcIuh>@T zyu}XUy|>ydE-r@q`};9MCk1s;r)x(*4kna_hlk&>x!Php8XO#K4`hY))p<@eM=MS8 z3hJb8UpOfjII-Q+)AN+g*@$`+l=e1>anE?&+S-a4PYVnu+Hma(G@;+LIaBPi$;}lT z$6}uqgGqOqm_G{CO&bZ-NpsxSIt6@ih_1uF^LHEPJdRuFi&qfb)Y=+Sk{|(-n_= zUI)03ag9_PwCVD&^5Aw?S66rB01|izKm3v80AtcMP;Jnr%R{;0xr;>3M-CvS3i!C6 zZ_!6OWq%Rw*@Gh|!>Q_2G4(4nyeA{{H?#uZ&vp`qWvZCE(^uNlR&mfqgp*WmFzcJzf3QHzT$wT%NVv-ujWB+jlqw}vAG{(|!#3F8V(FSaNN}FQ)#N<^NPEP=X-QC@D*!11B zWqw&jQ-_9s;rY-9JK z4(dYH`xv^PqYbfDal%$CQiD0I1DQ3X@NqvI8V@BGH!qz&7$Pw7-uW8$tbR+|~O61zG({QnP6 l3i!@%8McwpCh=3p`TvSTQb`1z**yRN002ovPDHLkV1hM@{v!YY diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index afaeb3c945d83314d0ffb65425b29145d690325f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2087 zcmV+?2-x?DP)Nkl z&vQF-=9n;H!h{JECQO(xp;dgqd}y$M78wiYrY8O$>DOh=nl&Fe|6EsB_i;rg_lNQhvja0dHLswMB+#0w|G3>$Gl<&?Z3H%lXD-mfF{t!tyO5@ zxXO-K@(mv{Wbou+Sy@??TeC32ax)f-74i)p**6+x#@X=+L-_=>ur(q6_diNXN+NFU zQVr`OeDR-b@yD2dJlxN9pvf2;K>QZ`?A9)ou!dLM(ahtE|Bf4R=L5&Zn;YW)X~Ru* zXCxBIcWW3lECDDl4;6I)ljYg~Z!b9$x7-Sr6 z_zf5?Dk^G#cD9Cr!0o8G1z>K&I7-9pyg?6@vfy0{JEn2jwHf{`<5%(KVSXkKT z=qG6ED~tg?Fa~59V?dUf)duifgsQ5lX!YvVv~}xN+O=yJ?cTlnJ#B4mv}w~OYG`Pn z<;#~-B9V};k#1(40oB#jv}MZ{I&$O)UAlCMIy*b5r>BPo1_o$kWQ5+ldGnsvuU}JN zUmrbw{FrXtx<&2n?X+*-K5A}mw#*Z+oepM&0T2tK9XfP~u3x`SPoF-e(a}+woSgK< z#KeSUN_TfRojrS&T3TAHHz=KNhSml^n8wCNI(FdAcQB&dN%a?TJ$`#tV zb0@7>u|m3k7-(z2%9ShW;K74*@7}#YPrD!b`}^tq`SY}H-8x#jbgA@PQb9Wd@YJtb zwTjN2J4Zu9Ly}nO1WnWa{rf}hAG9-I^XAQT_wHRuoJ=u1JWQugpQg&nO6j)+K^p_` z=rY7p@>XH&v9lQm{k01Bd7bs}}RyD(3Sj!Yx{`S)sC}#lH^Rc8X zCZ-D*mSXTA<~0?{8Gy|cm1ewt!Jfi}3m1}}AuDG9CN;Wsz9J7EJg`P_Vs2h2WdKG$ z*hUl+(hY3n?AWnG%Fhd>48ZmuIx#UJ-M|3i@ZrN!eqJbL0ICk@E9G zDFaYCg6ah^86CNH?V6OI7fKm`x*ZJT#AI~j_U+qJeqJbL0E(qhuOlX-BX{oHk@EAx z7?3860a->%15m4p$}}+<9l3GihLoQdN*RDcS=4HZ$>_+%ix;K*yim#jR4JoSR!l}m zPMkO)<>!S`2B1V7Rmx&Ay7BhyTRL#yfRvvXN*RES43vmtMNv#jCwhB(Y5n^3Qhr`2 zWdJ~ZzV00{Ht3VBnp4gI)cIp?RZL13uq}D=L50D$HQ<%>8LBnp#m&<~-*MVp^Wv*SiP0{}W^oXNtfW2TxUG&vY*1|988g_Z^Y zJb|dg$FU&H71Ct{mKQL?#Uv}pIDaOzHNXLH1C9mZWD4p^(LbcRp#w9qs)>a)tnK(+ zUhsqV1~@ox1P(`_J|89GczTmPX@hM<>|~)?!+JiJl+*FVi_97W++ehX`h1j#qe>Zt zvUr+NE{J*^2Xv^YUcd%A_HeO{h~aKn9c(hpN&|Gl7?5R*0a?ZvkY$VkS;l3+P^bn( zB9U+6#()_S-hl5M{RB;Yg>?aZjDRoR@4ksa#?hv%tZbmTxVX;IPtep?SpWa~{QUd~ zU%U$!H=i(>8b_O0EcR&r{Q0HO&L*Y6N6HFHOH13?1l$N8sxcq&5wJBGV-tv5j9;Lc ztzF82i{vj@u%Mn_t-l--;_p6VHEFP#9el>h`hpTas6G7jqXYho`9#n%P|UTz2vk~7 zP|(V+R}WkkpMYEkny~o23l}c@0a|e%00Zz1nNR{>g)3$%^78V&k4B>%Y{Z}ZMhr3| z==Je8mvH6$3R))xrO#6Jp`Pb$IZ}}bKc#chF`NLej{4g@ix2}xrm*6 z3v1B~O`wgf(L7tTPy-{PPnjqaXTD;-X7IhNTm~9I3uppupixR6Z<{XQDmvvnridwF zzF^>bE`r>l0knW7&?fXJ-z%ICl%bu&O>-G&04*{iya^K~OqeiX!o=)|e*u5VNw=1{ RnH~TD002ovPDHLkV1hQd=j;Fg diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index f75d3c23664f601d00258791816e1b580e8b1e48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4471 zcmb`LX*d*I!^agGlD$FMB5Tx#_eiST4f$-UhS$9V>3AW_c24?TtNyF# zW|WR*o%_YampW}gSMk8dS%ssGNnGJMucYqYr9{ON+s4wcL5tLVh zN&3r?bnlCHo1zjTW*OMrlqC9ir#q2+`r#;*>q5I625^@>Z(d)>fHQNmdvTu6V41cNc zqbG>de*D(#CjpHo+vL{_TX01LP|f@~BK;0OZ$!kiPRd3H?_kN$*^^SVddTtTbO(_# zLWj&E;Vc9X!q9HV{~XCO>2tOrWJSMwxx|uRx-EEuybX)#6RskZMDmJ7-_P5owNmGI zZ*a0c4ZaPz>Lj=Js^;1vO~%i(tW0E4|NJY)EhYUJBu z109VN8ax5#$gin%RB@&29!XSAOjSS5BRmFI4Umq&p6{pIS?uwTlwDR9TZKI4fKU|`RL4#a|MU*Nx1Ky738ih+ z57ljTo_xUfSGJui65?m?Lp~UcCA6Ezv^;BkbNpzfKX?m= z7E}wAqAkR**I76DII|0B^yNX2zw)ER9@}r4s7kS~6e2Q5vpTenv;@Z2&93f>OMXjq zU8-V-`=`~=_K5>2g6gkrTl~eX;qdJiI~J+Qy}dnuRcYTBLJf>d<;8N!BKAXH(lfr! z+BO6j=c=UHwgyVKMV>@_Y-m{i-D+tH`Kli(9bz=&j!i3;tERz|u*=uetYoa#!{j`3 z<;gfBV`G<)E!-dvFE3JV^72>17HKHyEd-O2prax0;T+hgU>@Uq3{lZn*3igBs|HB4 zg>2;w&F001nF{|}Av}mO=5`f+lJ+#}`#I%}GmA0lu;d$p;4r1OFp@`u+c8XayYWnJ6t9;ralgQ7@5=Z-CG-6YhYgN*G z7rT(+mPNnlrn#D0xtP`}qDq~yCriRE4%H@kER5;D_QbZ`No^xQ+l$NC@&fwveEQwE z!lvYNU~je^uWdj+*S;LriAmrOmq)?DDc(lGbz-(Z_OiXl*!d@ALav@~=A{DHM=x?u-TW&8e3F5=b$=lvS{-{_g(NCvl zD~HE{H^Ot7s}A;O_$bdKnOzs>#h{4q@r|Rd5-B-CJScvPhBkO%f$@vMs7MOR4SXr| zhH)MR%jtP#E8CZskKa~C(d%ni)%$L}!#$y_cOP3fKzA^Vv&6IJMTyeT%4OhA*AUFS z+-KFgBZ0)FRvlN&CNtXj&F-R17Vl1%3BqVN$RuJrTWTVSarO6E?V`lLGpDwTC-;ZT z)F}zo6aqL^b{D&v@`TN0Zr{{@^;~|HmsL-dfhdHM*vX9f(w9Mm#9^yP7W5 zh1r~E6*t*j$>e0y;#i3pq7a=pte_bnNLFmoxJQSB3tCn|A)AkGMM`*3^)5XG9}*q4 zTECn+Bt4?D7C037z`;(*k56#bIU#W26v}YeMCr`iJyn!`o6$|ipE}%dkf+HEQv7>KzT);f-r&D)@XYz1GiE@PHkF z_|vIihw(x{rDMBQZ84zo!QNAgWYG1GN^F+0mjM;1w{HYq=-yPlCgCRMSTtgTP3(Sq zcC=8xe!W7ce*L}HqlKAsyA#hOniknGFPa#;<<7x0K54jnO_vaXhNmK9! zc}G?USIe9018091>Z{XA^wen+4EsFnGdUPPH{XNox1$!>amIg@Us4mUv|2;dWOD|7 zaxNNX&QjKPRRXb~M{KlJlp&caLeJR*)iPyeWGDy@&hGysz{==1w>-igIJhVgaUJSy z{woImP+SW}XJ1-cnuR=7Do?25uYfz1T5AI0w3@DOZgnOd8&kDT(?>Ki(kGs2;rj7X zJsDE>ugefn(}l2eaJf&MZIW*bT)+3Rxq0okw%6H1>|ckZyk4Hrr2xIkGdF!TGUwRv zqaG^xw(6)qPNaONbtdR zoBFx))g4(+w}Ah0DwJ=)TH|$GM>xa;d#hgM)GXIQd?~q^A&s|PXrFqDl6Re*^BNaGEZ<&KEiNu@{2H&wE^5}?WZJ+|{#;!}ZpJG={dcNK($mvd$EHi3RK+t!l^Uae zG)<{>%OkFbYC1PXNXR3q;#nP^+es<3TpVdc93N6Q`ZFXUsjxGr=w)tQZVT#Ojh|xR zX$K9C39}^2=>XUS`c6-w#5i^J>HouX`@nIA>2BBWM2Zr`fBDX>n>X>Na*l#hGPh@w zD3OI#R4xT4_MFX&D7)F--T?o*IiOz#+$GG9`s9kNv^_)t2$bw#Bx#{0w?~v@=e=P3M zON#Y{9W_{vQ$;Ys)c2Qtx2MPhu}ugsj2Sf@ZZv<9p&)SNZRw;}MbM(T{V$`V4#@;q zJNdwdL%hayC=WVSIz2zQ-OCsyWwG~qM0~J$$nsKhN#0minB<1+#)Q+7(cI}vn%)PJ zLbCzeuZeQKc*Am+-Q!nG&-KNSd1RB#P@<3w3{l!x;Kn#rIumj8Brf``80Tm-D!i9r zvZQgKjJ>x5Lz=LbE`84y0 z%hqko=HqviKYt7H@UP-lUuHe3l;leB95C4%n4l7&V}q>JVO;J=+=83(oR5BG6UbDP z!)5)tR^GuD1S+=4O!dEqJFl+T&J$l6#_EafjsZmaGVijpe3xfDQvnl`$?>VHmz~wC z*HZ_G+#e_O{V{)UHBLjx_*%DCCx_nBx|7Vc9ti39qFMm(#FnG^>z6Z3xr(36Ah}tu zesSF1{Cw0bPd0hX@mW`At|Y!F^+Oo|NwxHy)MlM=8sZ`fuodC4dbi>iHyqiRQpd-K zf|`X+^V3`$ZTuaQB*R%vpz?UlU`u+oUpC6X>lrmG(R@xz4%-C<1uM9=+S*z#M@Lc5 zrr80!X+S{0z|F~g@qhEj);oL?VM>N`@%ij!Wg_2NKZa1P8KW{iB$nP;?Sgf2>pLKp zg-OWUdmr|c{qB|O`hL2biZ6)-GFZO1!>*|K?M88f88j~(NL1v+1K6|N=w_d=n&ngq ziLzm1nklyvgr0>QBHGS`@p{fan}7UIPROY!Shl51Y8wHH_+<`Va+9i_j5t`HD|)kI zmg8>0$_p`Z=LjVX_Xg%7HbuE(Nnhb9+d*gYf3KT_HGkx4px?Ek$OM%Kg01ME<;$ps z>JdN4-o=bPBR!It+0z&Gw&C5eFf_(0Qop)=6n02WHMsS|{pl$&j6KEcq#XJAD`UU= zSoAl=68sh?m5vvSK$h_*pLib9qmjJR8~5g2Dp(>h-SXZaBqlC+0}OLJ=+WM-(=7Jv zGbiVvLMz7`7S@JdD8xA?yh})Q>t6YZ;ArM+RJ_}=o}?e-QXHLxx_iA#A#UuXCWV8m zxT`-=UA=eO-$e;f4>}r8J1`q!8MBr&Ond~V;em$j0VO#lag6=b{~JR^fwPsej-h-# zM&6^u;WnbuS0ie9uL`L!0`p1hzNT=s2^F^F7mhyA2*fa=6z@+0QvA&@aiO8T(vioP z%R*xcaqv$*pcfBzjc11VOQ^%{Lll^a^l7&6SzfuU>`iv&EiB~|5J2>Eg<{hWY-ynr zd*$nfqcNs9kifr`g&y33YK0;$J#%CDU`b$f0iQ;AuYO2wYCXCkGLlb?nE%Gc6TE?* zx2EOpKG3%l$ScG-pHwLA(HXaF@@kVc@;8fqi73P?goNob>zP@{-6X-Z*&%ER09xqI(&_xGEbo!@U}cV|XU^3BZ7 z{C>ZC&iCGX&bhDItgP#DUE+{7g0=?jnt;8Id#+1JX?xR6H?;>@^`wTCcFuFClng)Z{NOy`t|EKQ;1zAc&4JFV!OQlOYpJazk-W`{~7R}&pzTBbL}(S%QJWu&veTW zX_JH=mYx#H@bdEV5+QDu5Vlr`+b6gnP)P#M+RL*kgRK)faZ0|sBCnS%_}k#B2l{jGwch6$d_tL&jSkWD%Oq)JSf4(9#P)s<2@!|9 z>#Czv+ zbXtRsR^LeRDQ(0hURqb47`H-j&Km5vi-!hUu{T+^M_4r5cw_Xays%@PB83)VXZSvTV|K9%6OC;J&T^fva{k#~aBcaM*s5)A^-8e8mcfiDwiN|U&YkkUJ}5kPZ4;N&!{wmG#n!$k zl`9IpZWL?nw6eLO(^lS#-EWkYmF2r!w3yfeP0Qb9l*=TS(-dqayiNmjIcW*882~>2 zAFe{pg{rD5HE`fSHFoS+HD$^ab;lidsM)h;t2uM#G~lkg?o!jIPgl3xa*G-Z6wR>C&n!n&bm&yE^$U@81rN0Fqu9r3Sf(4awT!h{Lxo_p?5t5&U2+qZ95 zZ@&4aI(qb|I(_=II)DDWx^Uq_1Ni&Ii4*F`kt1sN?%itR#*J#(vSn(p+nVz1q;-=b?ekS@4TZv|NL`x z_3G8opt5%D+ND;nUaclgnxuP%x7-AP?F47lr%#`UT#k}1Hrh*Jw^;>}mF?gv#D}Wo z%a^PD`}gY>efjcbADLls<;oTH<(FToQ>RX;7hil)&6_t*yD6_8VPH9+63WZVr@34u zO>BUvte;+B)rrCr_WQK>+S*#RaN$C=XU`sW@!~}vdC3NqK}D=zzh2#b`|U|_P2z&| z+?Kq4Tv}RM=5m${!MABhEw3|$CQN>Hb+z`-J9g~Qt0y_4FJuF zsf0N$cZrA&D2)2#;fE=}cDJw?Hf)%B^2sOFxpU`yWV9v@A3m(+&Yhc(OLAP%k&=>< zUM`1Wg`3;R1DCr6gaQ73{P^)|^XAR!(xpp20#X5I&z@EH-+#XvJb18A|9DYRzx1hO zl>AG$GaQBzeIsk7mGxUb63TkW>0f&3rB?Iz@#5sklj_k&9}PW-vm8ldJzHE{Jjiev z+!Y!BMc{qRJTP?Y$L-MaQ=NQ^Pe1)sXJ%o?3~*)A(zS3HI2Jg87dg#C!?u3Nf9k2H zQr7K6!?9z>)V=rK>$4{wSgyo-oRL^C5H5p`4YcpCG>a=?$tSB=x^$^-QCkfj%_giFI|T%zYP3JMCk$^+i!VPV`4L6c$&y^w}8)?C5wymT~I_QAKwV zxv5BSjE98r|5DR>ZpUj#y5fs3zEDp*@kHQ3n&nR7z=@)wq6))t^jKgwA4!dU-+53V z_k-_$_~D0JWMZu)!ALo1Kz7}bRKSnmHo`XfMndi2etv5n5V-X-pTBqSUY`N!4tl}L zl`F#x&}=sJ2e>sHM-&^Ov*o5e+#Iw5X#FgvFrV)=AQM1ZI(qbIpWU(Gj0yG$xAydo zzY=WrBLfGH`{>=vK`Ve|L{_rWJ@bhM8rI!+-|e$I7A%M2hR#W9KLU;;4$5o=l$Dju z@ZKCRnD1d3(W`i-fWg_?wQE&PO^wg?XmBb(6&4oGhT~}IsP_MI!&2wQKmnKq^hDQi zQypY?&B&}r7PgraNS63e%fAY>i66jbo5JbV)ueq;Y`EvxdN~Jz$tzc;3A!Ua&zn zQ%AsFy!-CEKKoJ_t5!*x<827MyXw zTf%XX;kr=|(Cfg0?sD-f?oIK6{r2R?US%^4%!sa7vBGD6EI2*jHQ|_%ux;>-Du6E0 zRU-A%?oIK6U1S^!@+zEZAkNL7Ki_A6EL2>Zj9V`p^ZP`4>ffyZyB?e)we+C5k!jSp zr=yt-O$WJXl-zX2y*XZR8j%BW_(`wgnE-amJ@UvS zfi`Jb4kZAe&CAQ10LKw~fCxT`FAAi#LM_U(Z-yg3nX)0v3yw5RojTQLcPv;AOG`@+ z2)Ct%hf9CYs5 zwd-KHP#;GP(+fCV;)dop4+`Xl0EeJa+-poaf+ffx zsVA`RM+UaIpM`K5)Bihy8_Ma}v166o9QuHU&4@UM>oq8yz&4binGdj>N%nK7Lx&C= z)?+tBlkP{0`2})*iToEl#Q3tny?_(w9D?>5l`dd?gSoBB-HwV1t-wi+U+$i)xn@^)22=OkfGP6rr-qMQX-z$KlR!7`XLYAr|CI6d%fQOH)ALae;+ByvHHv zR2wPd^XtUz(DJ={#|xYJNWeXuot@3Vi^Z2fzTYctq$a7sQt@XCsaXmL>xuwV6`Vll zv`MO*o@bGTfQ!!$<92}MguFjLKmVt2Ca(nF(5>GJxhpkUB?0+)Tv0_5e*K&SZybVd z?ehfW`5YG6B=mm-o3ZLmEkPDyuS&d2FYQIq+5Nnyu4g*-mOf)6 znHky@S&*jE^*M*jc%eBfg1AExz{DDJJ3*%xBEiXeE(=Es;K*>*XxBqBBwNy|LV2xb zZ8I71zy+-kx5QCU;sc}5WCdzs4K1Gee5RC{)eJGQ=7a0^CD(rpZVX2eSG*Dxx)al> zbgzM|@S93t!6EQ8MKlluISR^YL=MDpCJR3uWR;DIBe1f7&KfS$3C!n^3MYejU~JYY zr!>gt;lyx*yH1+x@rvF%lvTg9Rx6dT%?9OUR)Phm5jhaYVn4@%IGMuCB>RupBF-L7 z3$_c^NgBzfDfaEKb%fmuxS1epxbXm6ZO|3+cL*253@30CdATu(f^XCDKrliwqn*uJ z38@B`{Nm!`H-v*xhKpwL`;kO%;u2q1Ag>jIQBn!J9CwtIn2?GvwrRH`SZ-4{C zg@3bEGm73pVFFI2V5GRCSCSo=Qwi24$L+AqywVA}Ek?c-3hdCOOBa^f`U!^1Amndk z1V-tE#|bF}ZHviv2)O*@KtE$U(={zlz7<^w0=ghQp;lVQuS8M)WtEK!Y1su#fIeP=g*UY$@|tNRiTu?5$*?OkTt~Eh^?*S zcA|-`gdUwbb*hlpL7h8y9xpCwGu@WnP+1?m5}re9ZWtYPua#Dh%lW(5#H!XHV;ldn zB&Eo=fO4cx0jC)$*!@n`sxF&GfR7SJ+3d%5~H^e1$K_}7enVg)Q zDd>vMMt9ajQqtu#CDtX;atg$M61-{z!=xf6iEsV21h==H7-6AZfpJp_xhm^g9QV@D z+bEN=(SfZaqSI~YhK@#8vK(|zd6(0apgf~Q{AX`5jxhrjQ7hg22Jy3tC0K6~B920c zr)OB`bdZ+o!jc=|^M*j`sSr#0hm=X#q5~(_Y4H$`ZnztCZPAf!O9=jxu52r!BCFmt z4G|KC%ilK>u!WfCgrI-2t3b%o!+wa1P$^MiujgK#!Tubc$+IbgvM7_X(ZT3qiI2X2 zKSRV;1k<+U)9f6uy<#ZDu=3WeTeqpXxw(tQFRv2f{wf2!Iw5hNkog|FjRhwqO*{>F zZ$5jEYq(bKShLfS|{oRC&)~X6Dx+ zYnTu>LNE$?)e`leDXYy>ype)M#S`!~l z+zMf?g;h9+Ht~5EDQ_`KwX%o$=RIp z8_a;S@tgKaBLf3#g03d?aiHCgT+6uY=HR}n-XedSmN~oc*@Nu+?-zSO={ej->%bUCunp->DOl3FT#;=n;(Q`UB|83Cn&0$QF^a_s#l z_h>j$Xv-GKx`BGMtaJI#(5-{h?SKqr|8@&~_5VvkqwYl>q##|`9rti9?yIEUB%W!} zsS)>h2Q9R9wgdj7_x$M_^C~;b^z?KQ7Z;b+HsLXjJyr0!nrjaliMk#oU}^;%Ps%O1 zZ((QmD{YOi7Qgma3fKB`x&2E9BchZC8Lm*~3c+Syq`$^63dinFL6LfU(3zBKFx=R9 zXSxwE72)mN_Upi2@MOlyq8X=1l~c6SSnAS^ZoFS<{8oQ_N4>gQZmhX1H8oXt$Lf%K zO256ixtZiW)U+RSi5pvF>fy1`k&uv}(v7C-DGfqZ2lIRs#U9GDWI;(&M%THxegP$P z0mYOuR&*r1q*KEXNf?C)&PW-VYH4ZZp(S*g+sV-|f6`MwKb1{wn__9YFxfMo-Qfm# zj~!EoC^1yMVGAT7ILzpy9gQ!&--ot9hv>FRoad8@vIsD>{=q?>h++kCwlUl6h=>U6 zYLZ4KNUUpwyI&gaWoSrYwl=q4gHGKW7#^;=?PC)ZkCjObWOQ+Jd#R4d#xZrg4SmU{ zYA5*zqs!eL0ClnL$X#yoo$Nb9T_ph6N)j+&!OD1Y(E#ZrP|);t4r1w)KeWaTSm}=i z!QAF)>iXy#)b1J?wb&YjI^N$Y4?F!;xx}s64Y>rj zv@DCc!dqT!lvknjeWOWHK%Pm!!kV%Ye-T^{ZF?MH*euGCPdlNBV>SK?OeO#$14*^aOdys|%P zw&oS6KgQ>8`j0tMe1-Vq6hRG{QM<+`1=NL>hE2aBd_Pazo?6h~&a_E$drLo7M85uK zO0Ej3D+btp@8G7F0Nvj%?8M*yEP4=%KS#9biVlD1*G&q>85kABb=Sh7=v3-;A2w+8 zOo=4;>3FD2AQj*=ht1vbnyW8^Mgp21KCg*?i+#Ntu*;7l`JBD$`g%WsGFwT3ZJI0lEZRM`RgxngD7tXAj zx82gD#_2(+ojYIpNH>LC^MoV&L2-T8vTC|=Je5!%-Zqz)4@};(i;u#Bngi=yFrK*m z)lB<|m7WCK&@bsDJaHl_Mw3BOC=3ecF#5CS4|@w8Z}P*x)z^XDL43*1nvRn+p&4hJ zju)XOd5f{LkY}8+oe@t7w-$bi9Da`FPsK;8d*wTJ#gzGUoJ>u=GLCuE7*dv6M`R;m z1E=bodj5RJs{xc*3fWDft;!q`MWUu4#8xE+9}EFr_2Tp-fJRZ-7Iu;3v|`+;#zn5X ze!B$pD=>O^AS@octKlKgZrR$9PBr(D$x8U+UiqbKqK$`=#_Apdi=fpawc7D0ZHp`! z9l4`_d3K5!pEnPFLb4bST$e;1i2=J?s5i=GR15;~+a0HiyQsT3z)B%w)pohgxf;1D z{p^!W<^oyv*pfz(uJ3m{feDE&gBeYSQdia81nM`MoO*sU2M-Lg6@q5jSaPwjkMqMw zOvW;RF_iwvjlhSFqCn606Kjp3Y z9nrm{;SZehyV)7J}N37B*Sdf@>Hw0j_!ds+h)b=4a!6{#<@tj@qUkZ8r zVaLXF>`FlhWMb(YT9TEflYHY7}g`7G4Mi@}=` z=Kp&60w+2x(!~IQKp-a}vPTle>S%%6C%*BGpM2H39D@gh0zY9f%p`0nH?&ACNOEoM zkhW+((7bX(QW1UjzWbfZtjY^4gYErjIaZ9YXo817~f? z%8sT`9G1WsV2D8CWL`lV8`FsWze|GfQCYCwRmL`k7(k+C7VP$kF_Ao+80CAvYe@RB zAqSvG>55an>jya0k>mGTQm{2n|51;x<&}<|MKc3~B-%`L?0cweawJF$+7HWl`qqMn zR<9(aKFMRI;e5FU;U|mR^^q1lg11&sHhWv82lT>P8&;=d9L|i2oRhgG!X;*-{^QaB z)06N7z1F74kto^OdDh-l!};MZM@8?C%l}^Sqa={n$CLulR{xFG>tme9s;9}eU!F;H zreQ&_pHcq@nzKM$cJ|Sq-VoA)fHXYD5#-K_?+uZG^B9=f*)6g!gdbrdyCK}#Iaoet zH@8!610?XH;Ob7QXa%w_S=FEM7gDi!@vLd_yg~jmA;IUJ&r-W0z89RTG4Q6YI8wBP zNc`>xE(n{-0&+$qDZq2JuXA$dj99JB;tRb7-uSi(C;nuBkpunfgJY?BIbbLWhi|*_RpR4z>pK47_ zPnT~;Pglw|KiiPegYjEMDvqk7O_CJcozbSwXC~WS`ENZT)|G+K?l2<*pM^%~;WvkB zvhZ7O9X4wo1>h(PdE^Q(boilRcXnw)u@2GE$+mK%AQ#wfoxMM|ak-wz`hQ3??`X+WqCHkh5e8Gd2^3OOz zdNu;&AeZH!Jbg-7X`>J&AkqXNX9iPC=EKSxB0kGm!0vJU4-rv@_`Y-t(UO;eNYoovf7)nP<xhT1Hrxle;YAQqjw z8m1r+jmGi!Bm-~+hSzQffiADWXRYg3U!|+nEOd{om&Gj9I|Fa(+X|>ALuaX2{(WFW z|2saX^~)_9%Aw`n=>c#*d)>GNv7vSISNb`paAa-RYWV>9?kvWJK!`a7a%f$_0!mc-*1;U_^~7n7jnJ9#@hJ1}T`-%T+cgd)<3>fhcH#O+17Rz7rYNOZ)=%Ul^1 zOmjKFqD5sMyyFY zd?3}gp5ESvk+RFS@L@6Bn392%0(zj|Z9ktHkT~ieiI?DSlm|VDuXNe>wXykuDZc{K zC%k)@D>HTyQDIJ)t2vbDWTpISIuUfLm7CxVuRp3mOI(YFhlX%Pzwy8>gzWoVAuW3o zctKI;(ufdW~AMzw28|g?6f%LM&M#KnGb~39{gnSX(oVAhx>e~1RQMc z^L51o1F+}9{A^~Koz#6CpV3p9O@g=VCrc}cYL-JMiJR~gnD zm<2L~g1H1{gO_t`S%^@eoc>0}z<>X|z$tFO{~1UZh;*RWPtsBF)vVjJJ^_{)Y4;1GzUfvBa}zbS zuQC2&2QdSM<(HTLZWbF3)Z?~+J=>y-)+D8i?J#;ZKU=7#H|DI-vni+&p9u~vGBkc} z8gK?|gj){;ea*?so1Y#0yn!i%7fy8Wum$lR#{bW{-GFm{zS5tvP8>iI;~Wg=n5#$#i{REIVbO<$JeIspYn2N9Oja z3wB+OS&pVKK9%ltc?nVLf3B6;Hz}6c)QUfv_($;3kB?%FTfItiEy1*N{W*8W#14+A z$_H3`ZA{VF$m%L;JK&HLYCh{mlrySP70+jqU75JA{I*Eg7^!Nb&YfUUX2mvIVQ0f% z>Ag12wzEFXvqPBWKf@2X^p;nN-7w=8n_<>%E<-egSKO}tLi@|Zz=Ny+7$$FQXcbQ) zLHtyjFf*`kIrE#}#?=Rjj;KySCiRw{1&ea^I2rbb{ndqHo44%!{ryvv{k^TQNME1z zy5-iTp7c8i1Y*3})o6u4U~Ow_n`;eY3eZnC-VX4CH8lebEpL8s6L;LuJOaf96Q8}m z{ZK8UxU-m5yya7Th3k94M&0Iz2HM)%DJp>hRv#Z(TUEOl_}~hXTYEE=R$;DvS<0*5 ziopF(al4*>dg)u(a?aM~vXwfj99g(}{e=D{obDKO>cj9VS8uAcu&C`P$uirzn~%mT zuWXY@VV^&%sq9=h!CU+1ya8X_{=P!8KGbNF&0;3}l)$uvb=P6?vjX^D+Qp^bOrH9N zhPIM>rL8-^f3&r<1o6X8NB3$k7il_mbsiD#Ito zl4w-?hkN(0uY>ziqy)CNw}+R>EG#Tx&zF0{5X}dpF&D*xdu^66itqVKBJuNZ3*+k; z+D=TLObd&nBQ#b_|z_Io6UL`C1UlFx?2Eib$|Cl}YIvxZ*o-*fU5DU%n?JAXqK z$6a|G^sU}0>Lbz(UFpgt2ha18r(eJh(k3eG8t~|Far?%VZ*-F893$FZrcLIx=Wes* z?ceyu3z-LvY5H0EHifx?1suW#reDnR@}af|HmIwZS9#hoGuz*XG&PS;kq2O6`-50Y zc!KM?Vq3K2_tv4uR}`J17R%Tt@I#{5$YV`1uO28CZehO5QhcB)#!D5%_W7&gO z4A4%F#-VWMU`i@|k+6V%SidrP>O5cI{w6gKUhjW;{?(u8l4=YpcsMU(Z;jSA{D72^ zB~v)Qdsb7zKzy{70lEefIx}MFCBAWgon~>$mH#KYGTYPqMxp^1%^Q32j6cGM&_r$p z;1_w+N|&uzI#bd>&ONF7yw}dP!)2*ERi#{x-2*&qx2UxKN#OSG&yczK7?lcn_fo@3 z?8N)tl3IKPwTqEpurO%1texOL%LMYfjmW~WFm)D0ZD*y_wpjcb-cM+%nOPNmkz9Xqy9`!UGS--uH(@wSWt2 zRn4De$hCV}LF|QtGpnFXu^Khn?7)1}5)ViFdFa`~>SSc(X&4k!qxq z<8EEpudw{fV`pTi=gG}SsNIb=R+N!CT?Yrt8+vN~`>Ez^$VL;5*xh4z6+5dW{qkI< zXEgpr^PZg#P!%YCb&ZwyTr7lRCGD3XDVV_GCRL-98aDSeA2fExi^Gg#-K+c!=KE8D zz=inz8y(ZGi$|K?tMI2KBY4}rl1h1j%L6)QN}lrZJm9aYkna+drKTtoJS{1Nz~**E z^rVe`8{|@zPJE#3Y_#^~o3Q;j1bu2_Ib{5oKOHm_U@L}urMvFuD2;cN`Q)f{r?;3R zzpgAirdS4j+n15pG$Vx(F1pbSemK+Ic~VPeP&m?SbySLzJ!L@6qz}U3pca7{=D=EJ zPfaNTOa+#*$tVU|mR4sAtND_!!!|1JV~ni19BT3XH4<03g=ZqYqJEJ-lW=wqx-q|< zy685hID9o9`oc)hK+X3ZnkY-ubot=&O8|d>IRQ9SanRxsN4)quUyaA!9(Dj^-b zs2

z`t_LU3_FF{yZrXaT(0!LX4T5oLowobB()OdtqdT7g~{(Skd(wnb^!m7|6xm z%7d6R@AADoH!w4Es3-03rFAm*9qL{&!tDzmcv0)H)0OgD`fRL4DGbS~_F6LDwZQCg zBgN#djs3%9d9Vu6I$)3aOKy#k3x)4xoTM*t0iE($FD?SZ`;gz^G3wN!Hlz!I4vxr& zSm$Clo9F}`CTrZK*F-v(nCJ8Qe|?QyP0!nMvxi?sFV-T-))AU`4pKBh5KQB;L0f3l zh?Bajr}-E_I%XCY3O4whK=Y#i7rn4z7~e({9liFRR!WtKL13Sx@(a@Tc4!DAYdFxU zs9Apk8}`Ym5gPd9#I**~o7+{hQPU}oKI{0Em6Ja{K4vO1%p@M15DP*kA9V)zXgb3#e#8q6`<7>%Y(eU%yu(dpdisLW($!ZZ4@vIQ zWH`cmCJln}8?W~gG0LyGMT99B^C7ja_K)HDNwEYm@MV`J8EMiYbKdiNt9OtG zAvV#|f9Xbc>K}BcXVe~p&Rp9opw5``{=~4YNdLW_&ip#DjyeAMP=>lxbMWBpWg5WtBUmhA&H39<)D{&x7}TP5xwRBdzWEMWKIqL?%st`p!N-D^Wn7NODE=W zo{bDo-ATgnbGa<#j+9zfE6Pos{ny&CC4!O_5+T**EzDLP*W@u>|72}k3hfmH&z%CR zK+F_$Q6GK)e;|rkFM7*m>FV_L+fRRm_9?c=ns{7o80rqPlIgCzQ^<6j`tgsCVe!I7 z)UxAk{oOXc^v?0NZ|Zm7BQ$OqqGs)as{SVSJ-#hb@)8K%TTd?A)_Z<;<^7okmhX(| zGoK+UGqTP1blHef=zFsFcl8&=j{n?DW8>GLlRYg#Ck^I+MdpZpX5f3_|M%hQ?k9O0 zqS7+az+S5+S*E~c-n0hsm3&td=tl2^7V20@@#vlqak(?pQ8|1I;Uey2bn%nPxEXz# zkmHy#_|#fGqd^G`)Vz?%lB03Pbz9_qi}*Rnjk1aK=ATx^@&ueJ5t);N8AQ|a2r_a85; z?!hp@pXGEAS8bQ4T-&g1KGS?tQxjwhWU1l%dM*47)jgRY3kHom^r}uJKL{_bbKhF( znOmEvhLHce0QE?T$3ZSL@r4pM^?MBZl*yO$g8yB_3VH|I`N!)!$!k}JJ_DsSL|p7@ z19(1aherGkAPkY=#007iY7y8-%dzp2@|xe*Y-<>}N}HZU(?T`t6RytJ#9z`0)eut{ z#XjUj|HugG&K`Ux8AxUZh?8USz#}(x=!5_2VE@?%f2vCpLx5gs2FMnxx@QkKIXO2_ zf12*!e#ts)g#DJSYF;|x?y`{1wX{?c#>5f+`$z4bJ?QJYBXAuBW{tsO2NFB+$EWHH)V`QrCd0U}DIugK?>VN}k|HOo^wFNPWs*PIkXF7e? zk9YF{;@M2e$iunAJpzW%u=l%mmO2x}t_~pCu~1oVbrn3()J1yL>BkPsv|z_w#ee96&X&u_s}`ND-u(mOOm z!d!*R6IvAr)>TaN`W~Zhc;Uo8r7y5z4`5r7gOJok|C72J{{DLsJqsf< z`&Rd1Carlf5N>b6%x_>N6fkFqKU^zsAC`&Q-P?$pt!Km50n4G%6KCqZBEkh2QJpY?uLf1? zAP2J9M7y{!dflvWKX-CGcN?j7Ik*2?+`%UD3=iaR*V*Hr3(OS3*#$IN zM!lHz<1Sw?dn=Z&JNl`0rKmC>ryOUosN0j4X8{cnhnVT&EPxoR90%oAS8u^YnI+N~ zP^wNtyf3EMl0>b~&7jD3az$@0Q3TKn$;d5xEifQD{wNA5fM^F~$}9;|-)R&9s!QZH zAfs|Hm_G7ljnMsABVw07XR&t)D-xl~y5cr{8UKj z$#)V&;a`GHjR|`k!;Dz@Y|Sdk{i3j32?0?PU8S93+_p|Artj%x{)Jb_Se2RTh>@cG zod}@Ox8k-#JELkdBxWsGA84LsPTs{wJW9nA&d-@#rjU zookk`%Nq>ypY9pHz`AsO#?~A$Vh3nL`g#|z`^+3qXA^-wh>8`#N%w|*O1gDp`s?uU znVuKU#GM{z&%qCX?BrPRAd+SC8>?ZbZP}P~ULAa$N?^-cDfr%;XH?VjMVd;dt0rUz zE0kI0#WI2pUjv>ljy-{fKl|$4m{+(|Yxd9-E5MDd1I5hS>Ckr8^+8%5jE_a2tsVSs zs+*s5r=ck?$t@`K8Ac#Yj&0vs5R}Ao8O?Gj+N>tKyqzGW+59O%Ln-3;-j>RRIB$5z4nt0cX+tnib9!;qHAODH!tux+Ey zKn#t;d-0MOe7;|?M+q9^{y87;K&I}6FIBo&IjT*%*1uz`X?5TH_0_Q}N$gMW8ZI_- zynp{o%qg+gf6RB_|ywP;eFcznQEo5i;q zByH*Ftlx&|0hXQr&RQjsLZr4bq{}1D0EEX8@Eb{A&xF5vg`nmmn$RafubiEgeMsI6x#&e$3;;{TOX(C6j-#(Yhl z9g!GF9!NeBsNAEEs(g~s_vtR?yiR)dLRDdVg03S>*Le)v>=Ftb8-*pRpml<#-j6&~ zF$Eha-8>Q5A9~l!NY%CW(1^p$ZBI99d-+M!)TRLzKm; zmaYZNmrWK9RX-O9K0oUyM-U&8l@8^pk;7TWc5485Mn>YJ9`5DwX6u{jSYQ{7R zs-7lRh&+rOGF=0GV)0CN^iJ|3zt14ETsx!6GaWAi{21U(0T zb8++%B0XH6LpqHyQJZK9X%?GBv4dJF8E};h)(DlDYqzIOE&fbzcp?5zB!pAY_NR}YIvuIUsF=@Y|gTSijvqptCGkLOaE)*UmZ&N~k0zKkbe1+V!r)e=zFU*jX%V6f+)2o5ps&G};`4j7M@;0q(b@UKGZtwHi& zeYpkiJ)@C(BoaMi&~BY(L(PO`0}N^g3@xjSZl(WT7A|adWd^-BNj4f(6qD*PJs6x` z_t>Oo2zq(**!{;fdF><1@}Qmw?>?fv==VmKD|p zJGg(S>g(#-A@J^ONe|UUspaVpQcy`*gf76tS0g!Gl~s)#I+iLt7Yb7YoN3$4bmrp+ z(+gSk4|JSw#PFN{_Y{|Ue?I}}oaI|&SsK7#VYwjZCMt9Anc4w*$S7QfN;@U0EiYE@7w)gTd1!KG@)_?W7@kGAlw}dOa66izF&%#_Bc%(h| zW3#NX#6b@FLXb4*<~{f8d1k(oN+-@4hS(tMXk~*moinF_=g$|DmdyG zabhMqAto+C0hwf?W*ChVWQdL+;I45{0fP#HpeTzszt4H+*PK4D*Z1yy-LLzes&CPB zzjy9Ezu))%wzJ$sB5rYuTioInx47kTJ4$f0#W8I_KgW0C)`Oao{3NNdA~53djcOc%@_I&|nQf`62sR|{SfY!U1d>=zsq92Nu?{LJt88=v8` zd}lR%(3ku?Uof3(_}8^f?<*!#7i%q%=4fj*E)fO)o&5Vd!48KMQGsi$m23Y@{=I~I z;9k6Yi^sUiF|=$ncUwq z#?xDpL)_YKN4c?q#0oP+(7*D8+?+eeXBfBZ{*Ez=Mf#q~!OA3#k6LRkaYTR($&{;V zQOMmC{=@MIvS?05aXZpnt8v|E~9u;CfyQxg!jd>3;K{f~|wnj}`qkqR_CsXws z6`cPx_B1rHx)KMz>bf;oc0IC9nKGrf{wxBz)e&4?WK_9AGnw11&B?GQwZ;@xf@G0L z@VcGu?Cb?$V8 z5?h^)!;Os=iAdD~bli(u7d!s;jF9x-!rErcZ+{48COteV`dZ#K;atrXuFI>+0%; zxw6mOrUMuGPP!Bn>(-=IYFZ(%13u*(nzs9Ws+XL;SMN9PN5`vtE#F>7y5Vk6yFrGNY#@^ zvaK#ho{1AD2B)2NT5!=t7X{Z{cU|zn0}ljGKmBy@(n~J|@4WL)uzmaXX0dha*5I|* zUJIUo{`ugs#~usrxZ{rCvdbL(3u!EY*;XQ^ypyv^y$I;`SXL@Zo4gb;)y4MwQJV~AAkIDuzUCJVBfxd!T$aG zgKxk6HaK+XP;mJ0;TCc5;6d}bufP5}*t>Ucuyf~5L%P+gR|gM1_+W7T_16bypMAC= zDTER$oOVw+#sMKvARb{=;s|-V%{A8qD^{#9Zs(hCzG>64gbm2_)mL8yn>K9&`Np&J5+9m1zNLP2A+1$A2MSHV3cU==EObBkc;RZt-p8Bpr z93NPvPe1)MSiXFDFnjjw&Ir1VE0cI=ZQ=-dIxilwwFQ=-{B-;xvzW8F3 zL4EewXTgC32hx<*)d0D1sc*jdW^n)g_nR0A>*2#xWOkZ2Y<6y%&lYW9wnn^|XX zEGO27rxo-6)KgEHRN7ZeK4Qz3Ey1Eii_Aljqu5AY*{h;M4W@JF${g2qt=>>GHyJuc zjT#kPe);9W`t|Gc((1GZ>QT#=cJQP z3hur4-r)1kKTi{OcLgNEO<#HCl_t~l=f zmWVRN+_`h3t`&VJRw$^fto#u=PDEsdjP;R={Tmk*B1JY`f$t|^?g=qZTOeUz2?>+J zzMR4Wy2J|A)z$qv5s?)#)SX;$=0YcGE?`F zj%$(;*L|qOQep0HMZ&N^JjiMTmWBAT%N9;uXm>?L#c*_<2!lknLV2`UoxiXbip2Vm zt}?gPU8X0Z!sgAJ%~D)nej(uy)#>W$>RZrx7;A=Lq49@Fdu~ru1Y$ywjKddLjHVzS zV)X$f4qt}Z!f|7pMCS#L{xfbS_7SsoqI03pgJ;(BAe7j3wGXT*VlzMlseNNGJ$Ufo zv(SAan_$|Suw%rm{e+IAus#TZ#bB)G@dXv5c~BqPuwjFlc=hEO0*o6I0zHWCvvFg_ zd`UpnPl#jocSR9A6F8Hi=EGvJt^{_3EMB}g7%^f*noP5S>bRz+=ADv~k^#yCj~nf3 z#(g=J=g>jgPFBG(R9`?b+6GoglAJWTh5=idJ{JxoGIV2nsh2SFb~=or_H)7sCz#EA zam^<)uvmZL!i7;-AM*Bh0b=tIP zY4XhmPB!+6aDW}H9d=`8-b*?dkvwuh?+u zJjwE*{Y6F1zNCXWw!=_^XJQ{F2if%J3nWIzzyrvGICbjOG&yI9!!{1O94>I)fzOlH z8a}VL_(5LW7JB?cDW0lxT=xkFZ@>MvnM3sDoDDP%l63wb;DY5uyPD2{^p#G2LuX+V zh}50!EV26v2OJE+0~uyv5uFnUNjm>hA{7Uj6&X#K(n2%wPjPYaKRiH@?S+MfwaN>RE6p}c)iIL7@w#h0o+Z=(nj==CJSC$i z;;pydGRMmJvd$DjAPuAs4jee}WH^yHvWKkYW&`M65TPQrFyoD9a)g)e{@*#V3G@WT(M$vaCNwt@5= zaH3rVvLEUzUwnX0!VaKW%fiWEz5rrm2j&vjtXY#L?`)t2MIq25aH3rVN~B_-Liyq< zItiOVEJKJF%SVIv-g__9C9j%^Nj%JA`(rIP+H8F2Soz}r&`H=XjIBCx038jsZQB-{ zbIv(wGS3vMdr9SA6HXLcZnT=p>&$D3eA&E~AZ!A$aE!WzKlm8ggFyPyOD|26d8Tj( z^uBO{qk_%y<|d5s8mU^Zii(OV`QpcJCt-ovcV?0O!Nr zhDD3bv zh79>;z<>cW;6|bi0>QAptO1cPerr3536w{OfhLuK&?)w8Uo3Oc}d)twv$k^u$Vy6 zB4h$-8o#%sq+}Z0NVJDQ@?q9Oo3{*xO`v!gYjmJI!f}AU%rk{Upq)iUMZEp6O#+#f zh=qlPb;*bplW|xQJ1hOc$H*R3_;0@X<}{gS3b&Bhw{PE3a3j%17G?+}D3>q4>2?wp zSjrk#qN4#P--o#-NOffeX5vWANa? zEazaKeA@)7uC8X?M}PV9&$JW2<7~h?Mtkzft5M?h*Iy6y?T8I_Yfoim<)d)Ia--Gd z92{lG7LHQhpxZ&j#K$? z@yREjgc?9QRcIzs&x8|+Bgfvg*!UxPeo;X|LA`YH2isYwZj41waU2vbUViyyv*X2= zb*6Aq_^q}ERFp^+5nCk?jXa+ZSBn4pHJyYVNV5TsS7ZA^h>2Bht1j?flM!bvh53##CjY=@!6K!7-i0mnz%g@adKc_ldg^wZPioFz1Xz8WrAPPB_a8c3J+ z@8AD;VWPeZKD0Q9Cxy2aZ`!meO&Bpc1~wEfS+XS5m-agG&+g*l;*;P)q8$OWHa!7-2t>Vjf46Nq|b(pw)0S}5Ci9EHfE9Iyb}Ha91!F2V|1U$ApX&Y&oiqN1r5?^Bn!*{bs^r)%!HsXtQbwfL&j=` zIdkSjVts7(#c3SFtnT4JhvFY?CY`q?tVTNhD>~;Q&0IKZP#0pkt1qw^O~KhpcinYY z*awR%%-PW5zV1Zl#l^)Cs6*+y-!NT7;Dd^aiYAF~{DccdVTCxNmY2?L*|H@~Xfaa2 z`VcR&B*vFtwosi)@ce0EVc`krJdp}vGIC$qj2r9MuOI7S>!tIDu|i?bjVY+6E?TrG zKEbRRKpqYhzwp8fLp={#A$mPztHwY3NO_wRoJx=y5~FEYx${Dui*l_C|%p*1x%tD>|* z1codOU$<^uTwt_d69S9yq96~z`q;`di|2=0UF+%eSvQ>FfoKF$9P5D<8X`>nfdpJ%*_(*O3IR+u@4}+U z*wZW#(srarYSvE2&N9JtgO5d z|H;iXbAzFRCy}=t@}7C)El_@aqEM?fdd2`;oG$xRF{S{@4T#!d~Bx(D88#q(t$)<;`oK%GdLzhM%|&k$yB%|&YOgQu72kHw1@8zObpogTz(EJMZp zvKTDlEUO71kIlNai?03{oh4FpUXcgREj10OOVyQCR8%aGc*wZ1T*X5!MvNE{%$hYT zSh#RuuyNx?Q;h5E+7U4t7KhyvEP%&i=8`x-bs-P<;j*%_E76tc4C}*$Y2<-(OHExF zlWygG`}U;_K1R&rT{a$~${AUex-~!~QemptD^{#98BVTWF$HPZG0NUI_HD8CCfCFP z4XK&-?}&Tk0lyy|SzS@j>(J}GqiC)xWBmv>Hcm*i3=-wqmH8mPm^yW;$#8hDIl{-8Po#7VqYos&U0$&?q=@{Unn6Um$YAQeG)Yw;8A5K9JG z$ox2ykYnXI8H~f7*eJ;nE1hL+d}z=tNMBoHyEtb92BGK1)L`{ zNiwrnZKXOVMaE1(O^Me;5}$Bx5%1gLwD;z~A>N$B3;`hvfqR%|5{8U}HsjhPy5Ln! z=mg#9J}-3E>DEV^8xN5dQk)uHSXekiNc3)3Cs8+qR+|4;bZ{cNusT6EogVkJ)HEKV zqB+n8YRC2K*Y6Y|(FZY!at1>l2_Zf#Dk}OuIuKppx|k@{H!pWN@@V76sAv+PRcK~r zN%T%viix@-H0BXmzi-K-85f%(+I>V_XE&YdFx!DF`^ShWohc^uRR(BD)F~-`cLb@r z6EJTqC@A1eAIO93$+*x(&Za8DXi6fY{Yn|gNcnec@7}#93yGd5txTo}l=EU^cY`ew zeuqp&w!ak_Pes;N<}8j!2TGnUZ+*0BW~S*qGxrQ=j0|wnph1J4q_9P4J$7lCLuH37 zMW!o7w#Or5D{Ex#rt5h_9&J8}cp6M#Ed!l6aNxkZ*$EJnC^H~4WQPpP%gg^3nIc;& zW3@baOCD`5iSWY&b4kHi!GzM%(n}><_{dob61%iEU|p8k!!EMhDl)vnk_VZRsv~1$ z-DL`eVKj}2%&BLBA$|JvVZh_5Q%KPIMr_rMmESwWcFVYET4=FMV3ra=$dBD zw({EY_)RSl1EUtfL|&Z?9DhBIxJX>uVll`2oQc@j8XbWNlqrKCBaziT$PC%p2azSI z$Q0RjJMy?qi;Yx6IsJ^eGXlQxnBn5$;`1aJT;m1UJ(ftgD~)w*puDzUzkU~3mo?tX z4jCd#WQuINjoWIeK_Xqz$WlrIz6NWCA=2^kgxy?SUHvhssY9fmR5vnp9ezdzB8zPU z1`N2>W?Aa88m#P)Va`_+c6L(|X>g7CWm^doe#RP643j7BpGA0ITDJxc+91*wc(;HZ zn~8I5Mfpp4m>wn8ajXvWTDpH-gXJDY9&K)1g!yHbnA(MFjV6g(JHMi$;+JB=zfmG} zL)T_p6+bgZ#wug}cNzQaW~>e}LRQGETgN-?ZEB6od&&~2OoAtDqzG+-{5t_5mXwrS zEEefMB#8Vqsn19EruS}kh(a93CS!a?#yZ~;XM&Xhu?{jpHpmEB^+>DJQuD15 zYjyGOq^6^-`JRYS2_nU;&5ezyXOLZBvJoOxR$>5Sk(itAKrq+m*6jM#0$U-Q#4>brzJFab#V2YUh zx$*@6y(na(Jk9$dlVh1cqY|Scm69dtT+8{Jl4d{m$i3o{xp&6ESnQavIE<08GG@k( z3^YBD$5|Pv*5hL-m8gtJRESM^a`BMo%AE>OXd`ZZ(12<s$ydng1E%StS%Sxu~eP+FK|t{_BC=3XIe|cJ-OC~Dm?ej7#Isle(qHC^c;ZnaOFYSN45?fT0W7&(%jKf+Z{Fu8 zIb@-4uEDjqCfDX3xEGf+zO{*o)5)zRGT|C1yivI&IAyI2fhwEpum}XMD4SRW*Mjn~ z7!U#Aa)ADyzwsG9%Xj!Leb5(u(l^)OT3nNBa}P0T@~F9F!Zn~Y+yucXg*a*|SOVfF zB^DL}*Mjm1Xt5fQ!3DqLZ+wQ&@*O1#ebFa`6-0000< KMNUMnLSTXzPjkEg diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 0110c49ca101a303c49762c5e6cb52540e9299cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4669 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 diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index a2162bf63f4ae853b4953c4328c881b6b158864e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10473 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 + + + + \ No newline at end of file diff --git a/android/app/src/prod/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/prod/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/android/app/src/prod/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/prod/res/mipmap-hdpi/ic_launcher.png b/android/app/src/prod/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..b86b175594280640de188e03ee1636ce63e7af9b GIT binary patch literal 1450 zcmV;b1y%ZqP)(cIMFK}Bylcu-b7DX1)X&;>OxhImS%kSLPV zCg{O~ptv!54j9jZ2tH6m1yOO7FZFMxH?vi()6+9ncMtu+4?&pf|M#D&>Z4IV zaKZ^EY#+~RYinOb6Ud2A(r7&Ae-T9yc5WXA$jZuU$jr=qn~{<61N-S^Oxg^uU;A6+ zqLpK)p?okeFE5@A`kp~i#(S5`6(5*uDDh!^vVs2c59o_Bh|Q?KWBxZs|DNRE#IUTs z#X#zSQHGBhL}_Vht${h~3U!xf1AMOzrttu~qZs6NyQh$=5rdvHcYjg`(|Ca0Q4C5= zP5l+Q8ZqbvGw5e^FpUS;9o3-UkgHLHeo+V0c!1qe4Vp!+Mh%))2h(_f-BAsiL#~!J zh@G>jq@;vA9uHMjRVh?dR8U!285I^5Qg(K>@RdBLX=#bJ zwzg=0f1fTcF6i>|l1@)gX=i7LHa9nEZf=fxdwZ$8yqt1!a)j~1z@$%g`rU0GS7hK7c4 zjk1P8_4W12Qn|go6_O1HEW?S32`VZo5}v6Oa}C1g+SS!XySuwWa*^WZ=0;g|*x32! z>%csNU`}6O9~~bb3rR&9EV;F{HL9+z7IXx`JcBTEWSFC(?n^it@LC?h9D}guJms=_ z2<&k<66EIQ3Ys23zCn0fZES1^;$?AlbwxcrJ%X+WkZ%xP<&l0{h05OE9u*fC3)(c0 zYY;>o9v%vU&0unJQqLJloz3X z7tc`dR!`0H^0M;9@mftW2)A-xpxIzQtgNgQv`RM!^&FHec!6ev{jj;YSHwXoG6t8%3R$zL1TF@)qAe>lHVCThIfw8eML9cX!Q1V1cl^16PIy*ZBz0wUr z^$>L!UYyxnUtd#QU7es;x+;BHu2S}JHY#UM2G(6{16n#s(}Ot7x3JcH2j zM0bG~X%;BjH8nK}IyvMS1X^2LEpww^Utd@5h`dG)xdx$Vwz|41h?Nb#q_(y;L7xV4 z4FYHfn|Wx&4Sr!^A=uudBHtj)BD90i@#MwJ00-8Zni@gZ1IRZB;NXZ2TlRi*a&kf) z9UX$6M=-}AfD0_z!Lm#`J3FJHp&>n;j6lpY2%uMvcJNd8$uM(Zj)6a}GS?u0i!81o z=y>vpg$p)h>^WFgAlqXXntG^bqct-y zFrXCJQA0+V6qP^}yHL+T$pW|X2+SBBYa3(%9D{-o5rdrn)zAuO1_g-#gML&8(|Ca0 zQ4DgqT+_(akU`Ad@6^FG9$FMc|n3(t)xq3XFm%I;;#WThyj1;%q{STbRfYF41 zd2O*A-TqvWb4Y;?y^4*E{Tc(oZ44R>AQzU?zbv(a_!q6^Z)<=07*qoM6N<$ Eg6+7T#sB~S literal 0 HcmV?d00001 diff --git a/android/app/src/prod/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/prod/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..1392a3b65e2b17154578efd1b77c21b879fcd618 GIT binary patch literal 1866 zcmcgtX;4#F6pqdalA`F?(x{1)vRH|cAc95+RFRlq_ZAs`Aw0umJ>0up4+fFR9#nbPS$fBECxci;KWyZ4;$eCOVHJG{*{ z=pHBp0@-%zq}6%(`wsAIRg#abbLx8`5apextWI1EbDqw}`SzWLSPw#XUdTF}2s23j zHY@dB^N%~wxWA1zpY-{?>+q-+?1zd?+Gct|jtOBi+IWjvAEuvJ3!!-(A+AH!ygJ16 z8{VpUYlp>`4W!56^PcfjX$V4dYDLsw(H7O+pO|0eqgE+2B!o9TRKtHtSL3JeKg;7Y z_4!l6a(;d243Dm+!4sCd@N4|U#!s4})|>M3@_ar!uS;h~xssM>Wl49wNv`k>rTj#Q z_a@7wl93}c8cj0D@yb0qESnMYVGHYv$9oFR#SPM&5yppSn`1u+Xfi2v9&WKg=@egR0s7j+*NUi&TJ3d66ALsD3p=3Xi>(g*LS z0uo^NGn*;P1^x$l5B0|}N^D?VcU-W8?IrC;DpxdfR>J-O+)({SBC3_J3!{z#J&;Be z4@a}K_<*w*3LSLlGc`L?B=QVW$M#2nTR*Z(KW$X#m)je0`ixZavI^V|)u%dcXKdJo zF-ExqlwJ<*;SRs}M6(`6w_(vh3E?c?pP^B`Vg9$sF`ldl_O*#m)hXT2kzw<;{! zI(asutrdH;0LHjkDU!tAI}kX_04%e8`N zBiVrs1YG(nk`qg;N<(eH9yk97Q|#%)BW7?80q8sj%2FIN9sBk>v^)E_67=a9Y!(Wu z9LO_r!FT7B%R>>!J@XPivsi-< z9uIB;)V=lnNUYPYSU6>%X&EPflwp-Ige^#hpu`)Vs}6D;L-^i*VjQKPG(h)>ObgHj zNOXJ<9ViW$VHMY*PY0Sm|Y{2K_frMf^)LMg=;C^4l zYX--g47P_Fd0(M!203)d)R|ZFMSD|&jt(>4!|cqx5@@yr zKA>x7>=16!Gnk!+4hi427S))nzUA4}Qk|^+B#>*_iAGY;+@CQ?RlLm1h!-o-1l0>j z4msPE?Z9?fq^;G;4^BKQlhpE4KAb%vkhy%#bN;{kg!pAw(hiHuCQ*>g&RD3P)n(cKyT#e2pL2*9IFfj?2SFMKl6FLcxeqDJ>w{k0ud(K#M>PDpIKmqO_vo z2mVmiA5@_LL4Cvp$4#v&h0s5c_yOd|6(-mrv9N<(^KhnXjc1(kocow#-+O&Xx3uJ= zbLPzKz0RIJGkfMb6q;U{p^y;+`uYEj(AbyOu3bBmf9;2H#C+##M_7h3jvnEW1q&8r z)z#I_sjaQ8#C0vfYu@8CyS$RPb-pN~zxue8mzU43s;XL7U0r=J5{aC}->dlB1$+h! z0Z$Z$@QnAmRGG8D+kBUGm~~FV8>d&4!sFclhJ}GQfxiHKfS4j!$Dbo(b%u?mXV@Pk zXu_{J?(+EB-@@1b1B~c54aB`sJbO;yniwVU>`N2+KFjFx>X}JaKignih91-*SRQ45 zIVijqig#F~XhKMY?Ge7931*$vvktZ$O{eJ;Jsi_xpkw5MsdS95o=kkH+A!~3pf0w4 zX_pl%R%GgHe7Sv4?7x=MsU*gR-R1~&il%E?L^oJdQ&R|K-ZK<^7Df4VV_XN2)J7dm zol`ElAR)M0JCtMpO5ci4J^FU;`Q+Q3?dXYhpp`#xD0A(}tvr zW*?2ct`&$9AOiu!hJy~RD+uECCex-Vi*`vBb7Z$l7CBgJiPfuD zi*4JsiGBO_iNl8vi(|)*iK9o4ibIDEiCw#PiOrigi>9U~&%1tMki_oxP1Clih@3;f zkb;N`$WtX}<;s;}=gytt^y$;$=FOX;udh!G3=D|j;bHOQ$rJJH*)#F<=~FQ>G9n&7 zek}U?`$bPrk7#dimjrIwv`H*lw8&Gh3k;I}Gk^a4BGbmnihMcp)lfdEfQ(T@z@^2( zg9pX+>(?bAqobp~LGte3zb`IcyePe{zP{emmII^>AnP(r)43@BVvJZnH7oXuhK2@7 z%-y?pJqAw&^svj9FN>{Pw+eKBPrC`gX^E(;to)g2s~?ezJycSS%7$6#Wac@ot*xT1 ztxa|n+rVUj-S6bdlfL4Vwgp}^Tv1W6(6rfAWMNeDj;hp`_pnRt*s&w&UK0z9S(h$d z5-lw)9$n%J5yW!=uti$U=Y7`>y}uvW{pR;XwbId?>}I&Q^3|; ztHr3u*@M`vro(e=bar-%RjXEc^os&%oARPpO%9@p(Y=1p7yWn-19G}zP9i*i{#=|t ze_kwJyx60s4Q(TW^;wgHXd>OKw6t_?^;p8(dE{EMWQiQDY(=LN^yC8v4#;kA>uW;W zh>7Fp#l^)HCKnS#GY3ZBFkegrD!_S8Du?pPqPx4>b!21iTa=ZR?J>EqMQ+NW;Gg)C zYxi2de7U%N`?g29pnyvnj;yxcCbX@HLw^g!Nczid8uY_r6nwzKt{z11VV}1Z3knz) z*RNmi(c6SEaqOEjXU;s66D^W46j-NTavHg~@Z{RcRw_u~$2)%fxJUOWkaME)^72;2 z$yeRXh(B+$uxt0?s(i8w&vb$l$V3ZU+N|QxFF}Q86H;#ap%Axtoe5(9wv`DYm@;8r z$=2V5wizDu4!KaANYO`3UP7S{&BF1(WEb-}wlYBk^GrvM9Em&RYnu^=KLQso8@!AM zqihto%R(*znwdZ*yKH5GigV}A#qDOse5eatTrPzK}=XZdi2Pn zNKkS0>Q&L$*yyoC!x+gvwI_^v2F={hfLS;mm_ufo)K(;@=<4c{Sxwsx4Q(_24q~XU z_Yj1ebrF>ui#QDP%n!3~+lmAg%rGRFRZE-ULBmBwMXy97s6OI@AnraeycK;lV>XuR4`t~BglwBUmyl8F$t29np5nEk08y& z7!&8VB0KTb=}A*OaAwLGs;x*+(b3T%x1el0G_=i_DE=E<6d1fn;k5c2DD+3O za6E9Eg4h?NHmKqnyh2msP)WYm#xYsXS2_m>1Y%3E)3=Iv5 zy?gh1^fy79xmcYyZ{Bfo5pA(L6O+YO`^9+RTU(>8opw4vl9)Sp?hnX?!nm-n zWn^b(SAoS(SlA^{^B@8D%58;$270=!y9r|*)|-`;RYxuqCliE>6{65zS=gnU@stG* z64(j_2^?uT;@Y~K(6*M9mAwxRW+^Tvit2MY=!5dGf{Ou zZ5YA%L)gsio>;$6n;>K`AB=wAj~5Zlw{QnxI_E~rQJpw(B4O7uy$6faAJOK}Sp0F4 zY@iI&ZvHNd6*?cF;`tmd3~j~J0g}Vqb6s7XN3ST5$M6t)xSLw0Y<3pLqI}32RN|Z? z(%`JMv$Hd;JFe_j^c)v*jFD>)qxL%58ghs|69koz(bAHVl3$VOYVYr};)2O39zjX< zc_DrT24u#ZMBPe*wy;oVyyqV=+8}!c!KuVab3V z$`g%N7G&2#VEzEM)hZjK&wCt%Zda6RXeJ9q9RrQ31& zaP8VPv3vJ!XRlF^y5oa?44YQawvdm&996(H=LX?|f`V4KrHn_eL%#_gLE$M29wgvM z$7Gx9t_VqG%7STAE<8Cqc33`4fYuow`U}L?@6sk^+tdX^J~M0;=(BGiu<6{bZ;~{) zJYhzX+rb=lxL)GE6}M&>vzTBf85|9n31qTs&z?O_DT`<@$QdmvD%uTODwR!>?pn6Y zz+8c=-0Io0Xa7W#6!F>JY_R)r)ZvaNH}%*R8Qcka2y@6xlg7&gIzZ}3azM&{+E7?n z$gY(%avoJ7I~ zIZSdDT$h`hy8&P9J@j{}B$egpk;<;ey3Ns)Z9|7P=)xcHGPg|KsAJm6F=eLe+w*}2 zj1)h{0`Q+4=?st3|4xGUChb{#*C0g_&o^pN}*_P;(ueQ0bYSy z{}5mEJlwsP@xUNUuZ70{pGQ0x<;FdQb+Jy?%{ElJf=5=^Hg%YGuZbnh0&oIG*QT-! z+1c6aFfBNYFWin1rAL!x5|#+MydtFsbzNbdteb79w%8`y_8bBaqR4a!VgbKqCBPF~ zjWFoj=mu|5&(mhbRg))5->7S=gmwZR4F z3qg!699FZ`1e1pF>>pRqi-4tAFfId{X*3LdEhi^uBf)Fl!?Tqv!?NlfzRNnos!paz z(>8RcT4)G&4DvZA$;-IP?=U>BOvG}@L zt(I%G+S@3A+~5$#ZI=ZN9LIT4sZ>Uu=lO)|h~a|^ILRD$S#XmazK|n}6I|E*O4ObR zj$sx|7E+ochhNN2^1UPU3^IR_XM&`OVC!j|5`qI=ZwrOO zh0Jxs#Gf>2-c#cn**Qum0xo5)8zu|zV%h`weEx&Xb;EQCpwh=0jRtGATCCgcvR=?iw zan#sG1)$sUZDx&O5mZ@ z=2##u;u{lyF^W2_Ce{h8Bl29(DgY}f79%yOPGAv49wP#<9l(mJCe;bVM;;>ru%{8* z15-eJYB#0aZdxsuQSk#;OqNGwQUOR41^`7+VJbt5;&c z`n?cf^==ff{(V5e+BY&8R=*Pi)}KlUh;t#-aV$n*=R#Nnv5v&*Tu4PMPUb2$AMQGi zQ}-Uw1G=H~z(<*@YQaZ?Y&KhRUH6Iyh|LF%a=Cn+$z-aWYp4JiKHsEh7=0t>t)~$c zz=cM}cjES(bKGgTd6rBjFUjEtslFlSKhz_)xSkRsCpgg9|4E!Md@xGx6#zp6DD_gQ z)TeYh{W(eyhYq-KPJ77d%1BGasI(P0|q5rzSHyv)+IIZ?(;(>_M``#ENtVxY8lQ6ipN#B}BBKziaS+<_7 zZ%*?uAB*~y+Rm7au6)7ayLazy+P*#f+xPF%U$^c%KEL<`(3A&vUb)PfGiOS7cXv^F zdAOXs{OQ}bqbuv{_2c8?dw)gUzr6qMy?bW%tN%Z?=mZ&m?&-sai92`g(mH?s{8>-Q zLzgcHf0nA!-S;mBlO=KGI-!6!jZ5t%n{-n8k{#lKlguV26ZY_-vG5wMxpHgDdXc40&A zmw8qB&m^@$;gGy%&z_Y2Xm`mO**zdv@s)C_zn-n>F9nixzA}H&Qp2nB-9Z8IdsX+| z$Fr`s8TlFtBmx6$L%)+{Ot3!tbeER&NWB_nc6+eFkbr9na3}b zKrYD5^7T3`lkI%k%K6&m8^EZ^3Fhw1cF8U{b?$NIWRR6+TYv2in=<$KWi^QUlXYt| zyqWr!`+|(WeZ{VO>!LR{^UOfedS{8=ty?mi!=~(gf1nwp*Ej3;O(FHF-HYB>vB_Om zgQ!ufZhu!1#dPXk`G0nhk+aWmMl{9;~+iqTRn?kW^C4mg>aVi7c==gue-NR z{66>1Qc#e7Gv#;Akz|uek~6=h#A9*A=E8PWiGm()i_GA8I^gsW0Zd}L*SFYAv2%)j zv;F6S`EIL%c?|x6Lo9gZ!!7R`pY7RsE&Fv`!JFV|vr~Z4P>^MMdcn$tn)3daIxk(h zF@yc>A<3b!PC{xWt~$(698n;Aff;O literal 0 HcmV?d00001 diff --git a/android/app/src/prod/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/prod/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..e22fb7829ad74c3ffa3a4030ef82175f75681ad0 GIT binary patch literal 1610 zcmV-Q2DSN#P)6b8x&GoT0rhT(S}BWRsfAyMN7R&Lz5F@%sVj0+p1(P-E-F(w)pmA%%u(1k55 zSQ%NE7*nD##568R3h7!4hN|7z6nuW)opWAq@4Igp=7&yC^5wn0x%Zs!+w7+*zW~EG976x$`%xueTc__0>J&RV8+FT%C^2E=c^KPL!$RhsJlzp4i-f*g zwBfT|t=Qz>1rF6X64Sib1JtFC&<1V!IGj{$@}F4-?*;J?s0XN%y3M~~^Rkair4m&G zD7qpFHGW;gUZBc^g+jrA@9ytOuSC$`pjbbQBE=EL;#bhxmv5U#GShI@N^ z;nC4iS+ETqVjuQ(_1R9~N!y%>_iS#7qBR&DpUYbb>nbN08c-Onudj#u`};AX$ANv= zcW!RZ=yLVjw#fxfyl8Xui5>S^Dx;)wvADPxZf|dghlhtTa+QL8se`&){T2*|@$vCr zEspUO+X|gG*g?GaR-5JJLLTPk#^evmKEykna;o(dmE3B{1 zbE-L7^(3#LPU`lBlX8I*JAHk9PuQG|s7FC*Z<84Jj8{&%YrI~dZswJ1SD*>~y3Ltl zmrZW2*f%%Ie-Kn!4H4<9NAu(Ww^_7 z+{(SSG~`y|f$apBbuRC&p+4kr4{Rl{n4Lp|zim%#G|OfV&wp?x zc%c;erPWxs)4WmsQ93m3b{g@&39dcDxx`)b0Oj;;X&eh9f`^SpA82@Ja_wT&qwqob zWcakZ$4YZRNT<_dXtcvl6HR!e#OUvKc6R1%&XI^mow;1@B0Z(Yf|$aGaH!YO|BxKr z(N|HAa`5!JbdKeM;%$1EOu zMQQkoI8pX~l&JURuGkF0VU1jb)A5(PBFqO)RR9IwiW7<9uN*De+Lee!o?r= zWrQ6%fC3a7!W5954Z|@>Deb=qoP)AI{x#Y?~3qwSlI;k5rmS{_Co;Ylhq_tQq zQXy{w&SHcL$(-f02mCp%}Cs`(VU3se`(xle&+s^K}s2ho^xo@N_1Vc^S3(1126wZGqe_@H^u9 zPlE6K#^2b6ZP^EXd9y$rY0(+~!$kw7O%@g!=AAu>z>% literal 0 HcmV?d00001 diff --git a/android/app/src/prod/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/prod/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a2ace48c5aae2e56e8a69784e3232599f02c2fac GIT binary patch literal 2058 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 literal 0 HcmV?d00001 diff --git a/android/app/src/prod/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/prod/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..c6e5d43456c9400048e87f0ed3f74e0f8d560826 GIT binary patch literal 2835 zcmdT`dsI^S7WS4m%SqFP=BTNelaIP;N%la&%+ws;l~#mW(>SK0R-%-K_A)CfGgGf7 z+4Ws0X$S;_*0nUlB9Jg8pvH_>WC{w2=HS8A+;#t&KksENV4ZXJ{`TJA-upYhi%}85 zCdM|#1_lNuAv?D3)cwDi`z~Ij`@Oi*U14BgJQT9sfA{ftg}^TqvESk8m^Sv8M;nIR z#v+|AoIha6flF<_to~^vJca&K*_kT^KUx?joWjL+J1=pCU%@r<8GMV*m!I$bJ}xMHSMZgB`iom?(QWoGtkmDAI{I2>-` z+qdDKBB_9mX5=^K&#I*TLY7iA7WF&0;1Sb?=bJaZ8Jau!4@TY$O>Ovfd?a-0+f42n ze?PH&;2xtI?;=o&S-G7ohpyJ{B;(WN-eGL~bF7tT&b^J*e)$oi4vbP9$%W;sedjg;}SzB9&gocJD zXJ�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 Iv`^B10Sr^W_y7O^ literal 0 HcmV?d00001 diff --git a/android/app/src/prod/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/prod/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..9a5a827fc6ade34aca0f9f159de8600d697b5984 GIT binary patch literal 4858 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 dC8eO+npM*x9`LjNT{WNKvs~kL;xt99 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 literal 0 HcmV?d00001 diff --git a/android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..9d3e572ce22078f812f546f1d719b49846923ba5 GIT binary patch literal 4468 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 literal 0 HcmV?d00001 diff --git a/android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..fe2a50c74b2c8f17babbd0542ddead2b67d9abe3 GIT binary patch literal 7224 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 aS<8OvSwuROonpSh?j3>KtG@l=%>M!Zo%JIC literal 0 HcmV?d00001 diff --git a/android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..74f9d28d3114a7398478dfff3f08257150c8b11a GIT binary patch literal 10193 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 + + #212121 + \ No newline at end of file diff --git a/assets/README.md b/assets/README.md new file mode 100644 index 0000000..decb62c --- /dev/null +++ b/assets/README.md @@ -0,0 +1,11 @@ +# Assets + +## Launcher icons + +### Android + +Resources for Android are generated in Android Studio from the 512x512 source image as described in this [guide](https://developer.android.com/studio/write/create-app-icons). + +### iOS + +Resources for iOS are generated in XCode from the 1024x1024 source image as described in this [guide](https://developer.apple.com/documentation/xcode/configuring-your-app-icon). diff --git a/assets/launcher_icon_circle.png b/assets/launcher_icon_circle.png deleted file mode 100644 index ab23e263336398852de145c031b7617fb07be821..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3977 zcmV;44|ed0P)0&m}&WDGi~4WO35Fv+xF)j`MPh6`EIS<>GN-t0;m8A zl4aSnIC=Z$w5R4Ai69_`ulTdIcHdK5f3n0s~Nn_0YM4Y}KP7IH%wO=`# zST9KlAj`4|adCc)>i-K583qk-o>IX+K(O`_A4Fk!t49oLx)%k-0wt6eJqlPvD$PUd--Ln%s zpClSk?mVT809lsJ$$<`a{_uefcf_W2& z1R%fohOeKm(6HfC1YQK7&aZUgO$3eS09lr8>h@)&4^OPMjS8XB2%yfd4B@W$NMkf6 z010vG{K_!yHaQ(?L;yPHR|?WtPEfl5)cKW?G$MjplVDlodRyBMAmr@Xv#rmC3m43( zQ>V=N^XFTQ#Mklh@mvl5`SYjw{P}b1&-nV|#}D)2!w2*2+qc#yG5)D@v8*-$$Wr%C z?2B9%FJ5dpJH8fi^0GK_?CtHfM1il7Q|pRxEdr2@ZTm4EV!`Ns?bU&gpO6x@D%OrU+WppD$m&m=`Zz#3+VcYwb*q zzgLLL1t5FAqd2(koF1cnh#)FBF+{?ewf26Mze=S7h@s+x#C3jt-rT-@+nhObhM+~G zb9i`YHa0fQ^XJc733cGiTWc#@EUQcap(nl0@$cQcS9>Ds3nb8wA3tu1Az&d?niN+l zfc+59@TTDS-9#XSPuAK>4%Ad4fKccCnBzZu_%NEOPEjy5T3J~MHAko<9~fBxAue{I zsj%44a%rXOG_bEjs6|=@~x2s5MsT5adENrQBJb9w$}Ot#K`LdqwWP-4#oK~ z>c4*dTAhCY=o|DA`YI64i4T^hv;bu46NERRqzS{aFJdu(K0;ri&jMjle6bXzr$AYj zeGOssN0N&wk5U{|iI5}*z=5@PvP?5e2|ymF_#bn>puG9)*)tvWM+93d?%cT(Lb>$+ zWgh7$EC6|yXrFn(3%fGc*VmIRZ&nS;r3(uSf3|3oawG|Hq34>)wtWfI~-5rDns@0>rC72T%63NofcH9Hsur(ay;A3|5%ewk zn7l$%$VYQW0Orvjr?H+seM-=hbhv)~I&&n*9R-R+0LszdCA>Zf@&H?4%LySveRrS$WYzZu)9-~691f~0T)1=8WZV!R?#r+UKsEQr zHeJ$@Mv;w&gj=Zx`f%TM06FaPm1*09ZfWKRo9AX{XPMfGJwlWH4$TaT05_SOABQ#6 z`T2p3$POKy7GLhkpa?*7%LBsdyLayhTB79T^5x4+XN>#aBGEGfNa8?q#R;lDN?4HD z?C*ZbaK9-KP3aR?m+0*c;Q^b$c0}~_>3#y}J7;PVtT1ZTCtP4VqE+IaK7B#}a>XIV zSzpwab+tEKU^}Ao*yqHzJLnYwyuRG+z{r8?3YD;d4T++_3E%D|0E+1kMh@NR7Cx{c zQ4~1g+Z|<42@xNgZdErJG2Xv_uL6h!9HqQ;=@QG$5*=@jbw_~8U*ISM_LQje#{+Ch zv`?tR$GZhUGyPHGf^{0yEdcNP{!u&D%1?a2rX=eE9X|d?0HfTmSS7mEIbK+7+wSY_ z5x~0uu;(Y#2kDgIz_ujYr8xyawsfx40Evxz3c&mPU#CCuLt^7UzTOf*uO;H9L1@(d z{_z7FGfab=&$|fVT>v`$Ne2>Ja|u9`-*h0cb?bZpjR17de>#xZx|Il12mqJcDrrGr z^NuNy*Te5R`lknh&09V{#;^jc5g2_TB}c32?eF*nW)h z^%q5Hh$|Wa6mPIZ0Iz5XG+h{M?_B_j;u95sk~As+C23RuO46tRl%!DsC`qFNP?AOk zpd^h7KuH?!0>I-5N}4d(-n#%kfBx*d35q8eY!3nKdT)iI_+eKgfZ`372;dcxhtm`f zFxVaf*zwtb4oW6$6`+ zOn*9jyjuWU&9cbs~&n8l+Jm4q!vp>5u6nfX!ywG8l~laX>Ws zn_j;C*RNl{PW-Jb%dk=CTvM&;2i}o={ra^zbLNcirYI#qO*wp%_nQ^bg%z0=w2Y2D1eS!TU#S&iIN8-zGU}3_4VaJ z5nw`2&77{YWkouIpYxj>m*Xxo{VoWrS{332wjsRga-a_n6o9oBQ=pfXH)#a0r-W!_Q4wGh!cB}X z#fSUSHwSQJSvF&gdD~EfbEEkH4}|l6$G^kQxeUD>TD}3@D>8TP+|hFb1i%Kc1tGh6 z4teFh9-S%|FtSRlNwHsC(o6ctNiLtwB>>hafE$J}`ltw+2YrsdC%xG_*XVBwK9NKh z1x%X=lx87zepAF(a|?hq3K$W=g9i@?T9O9nYhvfmJ^GsxkK|EC0VCzn>({UAbf`wq zx9DT?GuwrHw2%NqSx*W#sUb8cs1NcvzvD^K>wU^RlDF*pL5)E;5on3DI$Wuf-1(2n z%uosoKvvdhc8c}_hQh*(UbZ_rZjmd1cibKgTlMWlsb^BHwaW~*M+^eBX&6qoO_T?H zM|7ld5C`Iug&F0Y;JI3VrHa4?EmSQuFUSx23VjyP#>3LSICL-2AhImORA{mEH)s%? zDqCM)*Zo67z){AfrKOM_FkiFQ-Y@%)M|~-tek$aEK@raNWLbaEH%N8^a{hx+OY-XWAXG0zY5 zVUm%iK8{KRV90KfC;~3unxCIH_wL;@^PS)zy@AFO2F-%jNMFuz5BsnC_mzp*D! zHF9ELUq`^!1?ThuR&@q}ZO$`Qf77}IFd;8-d%t12YMdAl6C+CA>ixz^XF?%ppnR8W7^){Ud!?EHF7FVdb_Dj0OnW(A8Y#o zgdjrT15qHMhA2Q0aX2S8va=P5E1Vspd!!@$ApWV#`AyvdFp*S-6mL{o@#)2=dx3@` zzrcLmKSzm<+MVAtApoNyP>R!t^P8pwV2(vVd!AUK;Ym}@Z<-W<`7MGu6@fBm5a*Q|UH%+Vq3?r2lW90<3uJGo? zTLf@O2h4?-T4i}6sVh+&J!pnsC+;Fs8B?J zcBF&mneQJ}3UegME|v2e#t7h$6?$@;mm~z>kUL9nN>tE2MxA_;_n)`wxPz0Gqy*58M1}hzh*THV4rH`1 z^~iJ#BrAY+WasHzB4Th(zsb5ovq@9{U5FTFL=3T1k#@!Dchu=SQ2`7=DoO4WiXe97 zqJf>5D>zl40w{GT}So`Fvk1`Qg-9=ZH<{n00000NkvXXu0mjf3{qg; diff --git a/assets/launcher_icon_dev_1024.png b/assets/launcher_icon_dev_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..0923f36f7beb4f33fa854a0773f04999205e928a GIT binary patch literal 21938 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 literal 0 HcmV?d00001 diff --git a/assets/launcher_icon_dev_512.png b/assets/launcher_icon_dev_512.png new file mode 100644 index 0000000000000000000000000000000000000000..1c234a09396daf84f20deb51fa245316d837b820 GIT binary patch literal 14568 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 BS=#^r literal 0 HcmV?d00001 diff --git a/assets/launcher_icon_prod_1024.png b/assets/launcher_icon_prod_1024.png new file mode 100755 index 0000000000000000000000000000000000000000..a54026f2259f373ddd90df20c04997588fc35042 GIT binary patch literal 14418 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 C%duzx literal 0 HcmV?d00001 diff --git a/assets/launcher_icon_square.png b/assets/launcher_icon_square.png deleted file mode 100644 index e8ac5f8bf740c2796d616aa577746064cf112bed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2256 zcmcImdo&Y#AOFqVHkU{z3n3~hm%`lM#gc|c0?>V3I{hrVFu7|sm5?lig08nyq zcJz|O_FpD1EAd{VSL7rC7US$s0Kn+CUj|7`iE{%${+5g537@3G1un%)%OBCbMAh-F zs(>pUjE#YY-hrOfLhMKUbC-3ESEgf^4AcY>(?NuqkAgfhB!>HUGTVCu z%f)NkFU#(@4n*6h+6m)ILdKetmz^O07Up&8n@bVd^1w?UINt}l$iJfy9T&k6^*kPr z|9Ny2o4h5Ae^ykqAl@O|nj3uCDsIrRPkTH+KhJMl5sB7*OwY~LjE;>Z+&GH5lDp)v zyu8f47t|(4|4{N0=0qOgWjVAhU6&3;Gn!0|jq|#?y7-wt&?l_z?M=hO!{4bu^*}1l zM3|SCXJ&4GG4+*|mDTjrRK`)kU4Sa3&&D@AaHcq@$)a)qiga^cC`|DW3NrTg_V)W@ z6`PotIK8;|R!c`GQI5SX2WcF}u4`&)>g#-{KLwplPfw3R$ajYH%jv$)+*UcU?lcFg z9<))Z-fm~ZJ?1nP`20$3{R&0mrTEp=)hm_9IF%7>3Wf5Ris9uuTwh--#bU8BOKU7T z%chV1=Rr3GQj=ILZrwtqaRgfD2?TSu%eiGTtj9Av-XZlHI&nF1uj80z>ycNl{=C?G zgDgwua5!NXE_6=dF0knR@9leYt1tUd@lEK%V|{(9iCgMkPjHcul&`%0!%gUbJeMco z)&(Y>)K^WGgEHvM{v!MNQL*7HcCK&;ajQm(h28Wop3Qm0jJUtA>L4hftqWIj zM(4DKEl&D$>7I+en7Z+^Yr^?w(zbYO{7ocgcdLxYqgQfR#G3%d$xcjLYDfpwjlZg?EK#rXn%lY&rMSZG7ng1Jz6gV&#OO%(mI$ho_So zUc<+=VC7tKTAM)&p5EN7g+CNuwVQb2O~WM*EtjWYHu8XQOYBqb9G#yzD^)%3En*11 zHeXvaaXf42s6g`9`F-b$OREqT*){3raqYp=G(tF6re6)yD_m?paxgW~nd-ode&pW( z3Ib;)AGp%Im5RR91BNIhIM{4qPhqi=k&)3zy;Qw1k*|f_T&m7uQix#+?c6q#|0X2l z0qo|AhjGv_%wM)Wbt0pKKEyTw1^>7-L$<4_{ziZ_fwydWa1M=8GAM9GcK+l*)8M zCMIczs)8v;fB@tf577`*C7B@8oPBa3a0h@+NEi*7c3(ob;UFxH0HTO@bZW}u8Uy`* z4xO?BaLdvXn50)sYASbiAL)QHjjWKt{$CHTS5}_gI2(5B3cv;h(Ng7ccYh6QUs#Cb z+$QE*v&Zzn>CBn(0yW|_#f;_HYWgW)Ta?q`8Cr4b z9KeyD*xVeQFg&XKi<9;*U!F;O|?|O-fGwQ`xM8$8UT4 zHdGUEK9{lJ?2Zk7$Y`5FMJ+IQh^$|-#Kx=N|ReeXmEKEOrG69)B_ThP9#+d%; z5X2Down}yhlg>;Pm|nX*zW)sj()}{)UK_j4wE|w-(h?c7-)0s&Tt_}R;!pachsn$@ zFV_z)+w(AhalEDGtHIM_9kcADr6(FzAEO-Fckvc2yo-=gVZM@`JN#I?XR((1>4 z?i-sM1h*SQ$c5L;6k2^sbN`M>=bmm_ zBS%0|s*xic&JhBEU?(?Nb|rBu_z;wJE+AlTHJ)5qiBiV(SXlPE8a=Z*=(3l1bsN^b zva(WFTl;VZRwqkOi4CHnke?R?`l&!;&#m^%?GWh+h|Kx;c$#Kb00Yx&0AKm2r!H<& zB^uze-`3T6?N(Qhe6V!r>mygr&f1NM&#FW_+)x!PT||&J4w8saHq|y=4?yvqB)^U@ z4c~#M3=W}hM-FJt%|B--FQlxgVvZAs(0&R7wngr1ox{;69SFjVrXut-v>^Eze%$(G zyOmW=|L|$+qn{EszIL9^+?&=Y5o=fKZuuld2pTU9s#QS+2IOk|4MlREmsq-c{yYm8 TR{l-$q5zju?vAe=LT~*Cv`8kQ diff --git a/ios/Podfile b/ios/Podfile index e9b0728..462df98 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -40,6 +40,12 @@ post_install do |installer| # Start of the permission_handler configuration target.build_configurations.each do |config| + # https://github.com/CocoaPods/CocoaPods/issues/12012 + xcconfig_path = config.base_configuration_reference.real_path + xcconfig = File.read(xcconfig_path) + xcconfig_mod = xcconfig.gsub(/DT_TOOLCHAIN_DIR/, "TOOLCHAIN_DIR") + File.open(xcconfig_path, "w") { |file| file << xcconfig_mod } + # Preprocessor definitions can be found in: https://github.com/Baseflow/flutter-permission-handler/blob/master/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 73ce339..0b4c62e 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -44,7 +44,7 @@ 8C539F8FF42AB22E298D5A5E /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146EE1CF9000F007C117D /* Lightmeter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Lightmeter.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -95,7 +95,7 @@ 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, + 97C146EE1CF9000F007C117D /* Lightmeter.app */, ); name = Products; sourceTree = ""; @@ -154,6 +154,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 45F53C083F2EA48EF231DA16 /* [CP] Embed Pods Frameworks */, + FF00F85CE432774850A0EDB7 /* [firebase_crashlytics] Crashlytics Upload Symbols */, ); buildRules = ( ); @@ -161,7 +162,7 @@ ); name = Runner; productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productReference = 97C146EE1CF9000F007C117D /* Lightmeter.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -242,6 +243,7 @@ files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -282,6 +284,29 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + FF00F85CE432774850A0EDB7 /* [firebase_crashlytics] Crashlytics Upload Symbols */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}\"", + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/\"", + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"", + "\"$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)\"", + "\"$(PROJECT_DIR)/firebase_app_id_file.json\"", + ); + name = "[firebase_crashlytics] Crashlytics Upload Symbols"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --flutter-project \"$PROJECT_DIR/firebase_app_id_file.json\" "; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -370,18 +395,23 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod"; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 489Z6UQMGN; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Lightmeter; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = Lightmeter; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -499,18 +529,23 @@ isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod"; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 489Z6UQMGN; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Lightmeter; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = Lightmeter; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -522,18 +557,23 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod"; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 489Z6UQMGN; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Lightmeter; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = Lightmeter; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -599,18 +639,23 @@ isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-dev"; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 489Z6UQMGN; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Lightmeter (DEV)"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "Lightmeter (DEV)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -674,18 +719,23 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-dev"; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 489Z6UQMGN; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Lightmeter (DEV)"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "Lightmeter (DEV)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -746,18 +796,23 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-dev"; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 489Z6UQMGN; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Lightmeter (DEV)"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = "Lightmeter (DEV)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Contents.json new file mode 100644 index 0000000..c89c0fc --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "Icon square (dev).png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Icon square (dev).png b/ios/Runner/Assets.xcassets/AppIcon-dev.appiconset/Icon square (dev).png new file mode 100644 index 0000000000000000000000000000000000000000..0923f36f7beb4f33fa854a0773f04999205e928a GIT binary patch literal 21938 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Contents.json new file mode 100644 index 0000000..e85412b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "Icon square.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Icon square.png b/ios/Runner/Assets.xcassets/AppIcon-prod.appiconset/Icon square.png new file mode 100644 index 0000000000000000000000000000000000000000..a54026f2259f373ddd90df20c04997588fc35042 GIT binary patch literal 14418 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 wV2sfjc*lSL!_2=l_?Hj-!T(J* z@P(wI0bf0Tlif>G0|#HNfBWAb|F2E{*CGDD7!BcRE=KIClc!F7dJvLe-$`hz?TF?R zXTL996+5}Vvbx&e#KJ>zWpu8GSp zw7#`U7#(m48F89s3*T1Y-}O}OkJ!=`c=2LqnLxr!;Vq5C=9&l!3JWK1Mi1nf7$Q3R z*HtKD$AOV7$%z*jhgw!vc2V(T!>8m`iljJ?!TXzQN>!V=ltK|#pI^(~EE1P{lcs4w zA)^x$#RYTZ4$h^f2HrD3WBc%k-sIO8E}UVOu^hk9x{q%6%zY;95biDBQ$W2|Tbtlf zHac}{`7Pmf;^8e_u8i1<=tBQd5&!0NUX`=rYics~@J>|gP-(%|1Esyq(t8#w+)>Yl zIS4&y&KfLjly>!2y?XVk!e$OGyxUgb#{idAXxcuqC z=oaJ+(gt(1s}rt$nxzVVGIlQ0Ir>yO6Jk_J)}LyTI-z>VikiuzFWD05K*GtZ-Ra+3 z=b@uGPyZ|mR#mQ2>vp`0!MHMMfO=h6`lTG~`;)70_@4xuTU&$JRbx?Xd-So8^W>l< z%L(T+MQ-R_FQ>r%;x=EL-uISWh11*sSASS;S78!{nGr%aeE<4@x()08OL9m-%V^UN z?uQrp`3-9cy%nqv+}PEvx7~+_v4ZLBk2Lbv_E{H}$Y#jxYG`1Fh`osZSqCBAmMuTDohQ``S(Va&_rwzM3+IlC)z`Y;XHv0o zcl2>hPtulC)8VghnPzs62!}1EduxS-gaf0ZlWUtl30mB&Pn&Gj>|NhRWbox!Zr3Mh zVuKB({?#e4z{x{hi#N(fm1$&(jOsJ;PtmZFZrJ z8RlW<5}tL|h{aJeeoLdck)r|qt>!O>wYM3CpWsz|vYe~lsdA&cOk!+*%zg`$t6vwc z`ewA>Hz=sYEsD_JIZtlr3-LrIp{t)(5ojN{c#qb?@Yi|vVXaN=0(LCF2BX9}i&{f` zrKN5$ksdtWOoxShrdw2Btp2L0iG9f{tLX2r`;SxH$P96 zJ`6C4O669hwiDTr<56?If9H#;5p~QW;(caC|1L&(xmg?b&VpE5vZ=W*xpTV$t5x+% zKDMO}C5RT!ML~xU>OVLa4e=UmAMiR{siNMi#t&#J|ByRGG?T;}vp;jH$NQQw!}mGW zo2w{e&x`fUw(+qafg?h!O*`*Lps!kQ|FFB+qnEw38|9xO4Cf+iM4DZP(ByM1)af|N zSZQWv#?r1nlX;Otj^vLlBx-j@^FI|;=^CUcPnp=^8+TSKmfgmtrly|%oS6v^2-u1> zcnw{e-g$^WN>KESg>BNSyu-p4*7J_ETAa-*$dy)9R8%u~4gJYiY!?S{&NN8wIE5>a zY*%p7v1aER6Mpu?GUB56J zI|7cqh_Rtm>3whWK5U<)#vmSG#oVaUJv`vyr*wO#y1Fhm-Mf9k+uszCyD9|pv5Kjt z-HnCQ|CXl)1~4Y`)1yz_n2*A9@>gYaX)jw#ubtf7_kT~zos zL%IX_-vJM|ugtO-{kWifVs6Ek0hhA<)P2~=h|3GmdXJ3xVG=8D=V-emgv^)AHmW>- zR$+uzAtW5dGWWlu-&upuKA|5vw@_G;6Bf4KggRnby&)(hu!<0xyhK&zb=N#b$9={wp8B{eH(RsT&|9LPEHUdgVdwGP4$LeI)-uZgllRli^1m5r zu^ArykGzdKj0+OI|4FH8-z*J%eIiM|cfI!Xk_Dx$f8;Mv%(#b;*g7EfU*jV`zMrAG zZ5pqR47!mtx(wGdTefLmz{sJ-taH_hZZWx0rI%dHV)U3wM|`5>`(D3#iv2;~sEp`= zf1&snRMxB{;5KnowUF}Slv`VY8*69nKJ2?@I*%B8(&RMuZ+CE4cXw#vNbvVii;P@R zlFx<`4z1;y)m(Ee9GbajsE{)f8Qzi_v|v`}gl#5~XQ% z7e+j9J7P6XpRL(G*NLTH}P}j#g{QmnFXWV&U@Iv65}KC?iLD)dL{IgJueL z0OhpM(iu#Pe=4SKOQ)uMiyZ`6`L}NDe-xkQ?}YKgo`xw~jb@TI3z?N~E87W)d>+5= z^XJcwn5oMNMI<$rZ3CdjqRjmK{LK<|c&Vus*PC!GTce6k9x5LrhHG9Dr1d<-E{*+V z=#X?t)Fww_PGy|V`+;%YB@Ks+GwLbWZKbViefNHeCmMJ*LdI|@omdlfx%>*DRrA=V zY@3qXQptVR{q*#7;ojPmyo<5cFK#jeb7_kh42F|rpi^zx$B!qZx4jkJd^*Yk`#V`z zcC7bN!V&f$RNKt@o*k_I{gZ0H?NHs$k`yCsg9%g6+0y+;Y%oPubx#Y;JQ4en=FAVv z-aI2TXd_C}JDJSStMkohe; ztmMnX`gmb~oZC}_y#XfqUD-IqL+DxiR)OmmHY+PA zFi^iQ)_C^(#94*wV%>nmv1X#q;|=QB@14*&fzz9?r8Dg@S^(6f^Z$~qRT^Ymu%RUl3L?A)n!3@;Bo_%A>H5 zki_rT#ILE;^q6paJG;n|TUD-#-q+%<-?;iGLT6ide$o z>p)6ZuP9flzinIb-}D7%tPttT(8Y;XYeZ=$n43pW_BVXDy~ycw7L<>O<6@&V@5Bx5 zHX?RDV4Wp#eRiiyqxwBCq06)~#~Dlf#$AtPa|ep=-O4yb48K~HcO&ngrrEBO>$>`9yf?6gc`>1(?e`ab-1N3ied~TzNj5G6EPChV z$YkqOBd_5!wqkhkY>^gn#KwLP5hx!*IkdL{iI*ybO%#&eqQ*UM2L=XQR^riJ@QOQn zI30<^G}oj$qCCJN&+we9WUXfD2;}18E`2|Tzo)MXx?3D(8eZR(A?tw$@ zS<}fobWuQD^X5UWe)u$MFy7-d<@?Y|GIDXl)vtt9{y+OLQ__GgqObASMID@M%2gFK z+D#RWeSarP5njrFrt$~xuiy6*YA&&EzMb_?&ENZT;xIV8%T9${sS%%e#Y1BDUdwtv zB2_X*o;Mw0UuZqq&R`gQrbURR0~AQ_-n~17kBW+Nb#;Z~Sd25UiPVss`Mv2=Puf^| z;u~3_8TVb9DQs(}s>*eD`FjLiG0i)-fMSQ<;iB?A@v3Ogr;#0$vasRV{fR-~LEVO)XVT(U;d#lr18x z)4uMog;6x83M$1&%(3z0VTICI{QwSnC==S5NdS@#zI#*xM;-N(<(^cG!M{N&ji zim>T7EH5u_g>pP{FyZI@s)zi8#)?Pyg)yZ4YY;tcD0C=s#h_LQ`9Ah?N-{HkR)M59 z>VH^rD>k}kHk#XZf#1@5&|Kd_TlQQ_hg>$)ZyUX}@G zuR{PXkbCkJlc%#GC77RAiZ(8!eN_`Sl+`vH&n!ixf|u$Aryx(Wd>ie{G~vkGZUvht zf7<(fGK&8|85z)IcMcHUFRyFrPBvuGs$U5{S>VuMowC(oJpZ6jnz!B5%q$O$RsI|t z%(2W3q)5+n&p`(ERk$9{tbmz?ru`-7qr}W1?ZJaAvVYlPK)h||E(8R)d3gBVvUd`9 zEX`T-=KXu?(0K)gZtm_rZ;(N@?4DFK#$#2#6a;{4#>HBDT0Wn`8fV#yQD|7$aY?qx z>KF{dlm9cwa`RZJSmD;v0Vf-(H}etOw*H7cmTD4s<@ol@w^qBQBdtp2PxW?Fe6oMH z3dJ|rKK&$@s6y$hv)bdjEIKGCh_QX@r<}|>pIhvv@70`RT1)xwS!_0&$z;-!6A=KM zUP_mTheu&jHU)dRB*z?}!pnu{2L5P^@g_0VmLYdN2-~F4B9~rz<5!`Qk`n)YzTjd^ zOF@8{4nTra0rENt>OuFzxqt53y;~SuSewGbs_cAxlamRy<`leFS~{4HJyA zwO6gWNX*R_|iA_f4~4Y?hQz?VTmO(NV^LzrR0M06yz^#=9+0 zw0)&`DC6VrB;Gik&jhF=d>Pe4=LVL@RUob4RaaLt*Gp(bthS(Iz<0#GJFB7jf%@IU##$dA(qA}XrfS0gC-TX^ z8@kTxqF_V8yQfOzFsPdY?cJFn4Xe%g!VAY^I`5N@zR|gJy>&dWQ{CXNIEh-@HZYv` z^~@@t=;ths==$~Rp^YwXMzg-~I(zo4xA%(? zwH;H}<)%U^Ru^cOoEhZtE+&fjXP&$sKDi><;}OntBOaOOsUZH6t}2(Cu^j33C^I9l zRY8Rho@7d(-)Xamdyco->EE$+hv-K6zQe_3;~n)wL+2&e7caPS!C*`*kHVczPnK{* z!(+!=`m{sX76W-p(XH4}lKyiyzr%RSU?FOLL}Y?>#a58 zWm`T@D)x3?B3c#dxJpxq!^JumMy>Hr>kNb}c8X1Owm8De!+!oeo4(ut;wr;k@Zy`> zM0HiwlPZF%?n^bu_vw-U$9C;$BX z`73W!RaRD3R50>qxF24k0{?PRz5Gd8Rj!L9`LWjvK9gb1 zJ7d}uV}(;gY$JZdigoRFa~^+0V`iIn_54}JA#nO!Zc3RIfrMD`%=dS3DhL4TW2uO)|u==M!UNEz|9|RaB~*$6-Fk z@F14i#S4o86ec1>qqx5DU3fQgpzJ1Xluaw-&;kS}&t#7Ld6XgS2hSgKjV|+eR+i9) zvZm};y?*`r1jxL8J+?}pj=pibF5cw1dJY;pJYjg)msno&tu{I6l4ZRk`UW&YIXuQU z!aA8?u=%_}-aOl#5|xb(>F&2fFSvKp)0|SE<;W{Y{>NObN3OCHaY%F zwjdV2A;#2JR;GAg8u^0_o9>x?Ubwc6xLNAA_PE4_dE#Dgb_xJ4#s>Z@-*#tWNP`e) zmVA+pJepZI)ck30H>kkFv&Z{lnZrci^;%M|7UFvqkTNc`c-rw2=p(iiYuBOl6i@*Ki{pl#p3 zq_z}QjlUu*pd6rggCWtS$FJs%*Hl$e{1*#Dj<;dKyWza^932?)x6;-PKQ;(o03mJ{ z_5gdd4XYo^<-U3IMg*0kHYRl)EdaFWSX^XhR-LKht4DM$qcCrAzN*8z*qCsD1WrjxaXM|ZgBY^Nl`^L>P)qc7wGnqd#e@u+v9a+2 z^-jMYKw4Funu}s@0%2}-pbc)2RR9d;+b)6Z019C*yxo;7ivXu zA8j2Cd9+b5J!L!H6b`MkZ7BFjEk>E)N@r$vT}S-BmvdxE=RSDct^oN=3PzcL3;;Z( zWTc6J%{HkZR?wTyW@BVQ&3KrWb*znOCq1MMa#F68J9+2MohiwNIjVvl0|6Y)Ri1K) zn-O&br*^YcR)trr0Eyc|N+qLJFSgEYe4wSJ)mFc1)hcJjoGKb`%bc`&$Fr#i_xvfJ zBu{?^?kYF*F|hdHzf!66O+A$0?%Ehv695p4(O*(T`#Tl408vu%7Z4$TKVj3PLM{}I zk@>Gu)o>^_10i;6dCq4FyXGoINDR|I;|a`D7i~o!!OV$CMsu%mYw>hQ^u`LGPHy3H zxj?M+^$X!uP|!Jxk`&%GEkr#^k$JI3c!w7lME@)}saJK=G5zdrWs)iy+nC=`|2ta+ zIkmgYO*?Xx@*-a(tf63#4#A|Oz8gK8mEuex=LkwQNb;n+HXD#5A0tYeuw3oxpK{I; zy!bXx*-t3S6WaR{C#)#gvuDo|5)$fOj?yT^xR>u_7P#5Hhi1z0&(l?sfSmv~xbQt_ zBe5QZ1Uh@NNK(Iyv+R1l!KKTWkIow%8iGQZFY>#xWzN?JzDD3CMjy%e{%Z(%Nn5Q%-M@oc%p7;|JS0a6-RWA9LV|Gzp z*oB4QL0j=CdNnT7-H2(#zXn8T1pKhO+dt^4v55&&nf@DJee7%1h+mta|30s4R#+2%i&q{joDZpJjN^MNw0D2KWB& z>Meu4u{X*kp}?Hd6_Nt3EkK+PDrn1=EvBo(4VjzH#Sg?SJ&ZhuiyMe$yfA`YW-E{meWXRmcQ&^P>we9bf$`&>AKA7P4SxO9-@D z9@z6qeyZ-E0svCo{TM(5)^onyzhn+JIJog0zC-=%E7ZIW8H8>{7wStlSwV%dM<+&P zJDe%J3)HSqGu|8JN(n@1O=V?7L_~_hKg-r=3M0NNXdun%i|AWt=ch%Pdg6TKz<8=X zpH%p9IjP0+d>aOE65yKhrKl)>7l%Q3bNY%ctpy!p*|(*v6fmQ2H<4Eq~`pa-1 zJK6P|(;gmBdtpoa@geE;c8W!Mk7b|Py$qMbAqHd}5n@2#3DWTge@XeBImvOGtWeO} zBa!WjUdycRE97vn;bFZEa$gySiwvgTy^ROszqp6iBF9AXCaXYp?SJGl()VSss-y;q zU;4E{4T_0z+ZqiVO-R_id$*}+O1mlIbI9dR0L|f%A|@eq`B*lYmSn+h?~5-wxT6JZQMHOk>{&pbEA}3qyN_T7;_9i<;IV;d(#tso+9t-vmNCMq*~tOb zMP8dOWyz&1`sbT6(tFLLu!}1zPvUyU#)@uBFU$lP96yt}6iqa#NoJri+$jzo@I45* zr>(8+<)~j9_V2&{@@*x$Aq^xt0F$QQkmnn3`OG82!liWZ2D8D6uiP^bECu{Lp0xU8p|Jp+xCC{iQvxXhkk(z~)dab8 zlI*{78SZh86xVaJqZH~45np1wC{05pOmarsReke|hn@|w?b?GfxtlsHHfhb}(YwseyE-~@?J0xyTi7EaB~R5;Y==W)W6Nle zRnBBSqRYz7>7Z+xAXJg|C)^{K4A@5qcy4o1%6O$Y=>K<*%te(=bp{=aax7=Lg|uRQ z2R9>2gQ>~4qiaynxdli~O-)wR+pyHAwoicTnH@~LZEie&&k)$fPNsCTQ$3j$r4Zx@rB{MM^Iz%lUNAw2&Y+^~Ry0gS+- zI}Jp3eMRuVZ&`vBPAfN3c7$Ujw*F!;0V$;dIZnY3V|Fw+E@M`@Y zY_Q}{kh(rM2TY6qgd9nWn9Mqay%grR(6)-(#?`G7wmpxuDLrzP^Y6oipCyW!hG0hO zYZKUBf(CjVc=+&PrynrEG1?{59)ZXNwFly@6qNuGXXaI}JJ&A10i|VRII}#oGt$z& z#<;=U2KcA!p8j_#D0P-;b&Ul6S-e&1ESx}dq6VohWjjklH3ECxPMVEgoFXd-L684ysRi z@#00|eOu`ekLmD&s1}sV=1eH{Y-kg$OFsn7#7*P+zMX4&xcYUdULQv?Jw9)W!{G?2 zQ<5-m8=$5no4Wf}`~|t6EVVwo;E@~C$mD?!x8?bLsi|79Fere&fCv9+8h6j<1?nPy z0H7$=9mMgMO-H;*?r4{p+2_B%+s<1Kg>Q5rdThi(MI|Mz9BGn#5+DT>dyFGJo%c^+ zSi@BJtZkkYwqN7%*dLFAvJ^;wdmt@Hly1dZq5fl$_d%t609$3%g66~%NxA!Qq{{Wk zK&gr;Ep5TZ#>N@|uY!qER|u<%f6#nUhPCk%W@jg~eyV}rQK=2}EncMC^2Q3k$8LHY zK2*FgC?N=%|J@BMR;=*)3{gPJepG42f1i7Wc3Zk)d9$&ig{f(!;DBxifj!9#juns;u2}9t7>cQ*jTnb`AUm8cz1f23)U`gfwJDF{1KLwy@~QPiNtWX7#!By$8|9hWGE^122L`U{>o8)Rq4J{x4s?K+@(` zxEO(_iuG`$aR?OQhrHC-l{XU@(nFgGzV^e0oTS-AxQUq6VmL%W1cMp1o zju;;gl@rt+cWVQEnVD^IpE3x*x(I6O>J_8j@}5`N2j!4`4)yev1Pv0rUybrNp-pDF z;k|F7$Jtx-?W$Z)WlP)J+rd`M86vzS?mJ(@RMS{#WE(WGA6-(5&FdJx*TlchZMKyZhBZUu-#8b_?Jf(8 zeAFDOK&`G`h{Ee+9|R4bMGMl;i-o%VSr%p)N379$!9g8e1RV}1iOUxv{2v{Cnw%$% zn3a9vBHH!1Zc(N&-T{|ceZX^YK*3Y5^NVLl{uSC0+-@^7h>0BgD_-CF`d+y0iTE!2 zh&u`w@L2D5qJ0EiboQ@+4IuXcs#=U1o0{^3G^h-3*?{$h|72O!T$0LphZpXq)COLs zI0wW zzC9+XIFbj9vo)|yO<7C$@Vjg=?Q;=zCjxjefwVBWu`6CSnU0tf+vQ)6HjIWzMk8;^ z9Lhr&6*1nTj8ygZ<+M3F%bj9Ci7OwD23okBC6n*s)FGntAgw@K>d~_co6#^3r!VCEkt+scb#;GwqZ$xe<@{x6bxejq z2(k6SnZqK}sa71_zD`-DynryJd4NrXgr|3IQ0WE+d7sq%g$AzSG&MRpN=wPrF46gR zl!NN;L_YK0zy+=Of?x8!H=VC!2rZ$b)=Ev$=aPzE26KYyr_B`#yQgj8VwRP$c{F)a z#KRHFabb2XyEa*OggY11GeDK5I`vOH71yG%t}8x=5@#x%Q@>HL3zAA>D6j@L#aqr% zJ0W#SAY!PDmO3Z>YM~hN?iFi(Q;|H%aP9m6DQZ|kj(u4Az}0ArEMWQ%Sff)52A#1N zx1~eDr#$jf@5%wgxC^!o`mAh~CH3_zHBmU1dlr%{iTtRFz_^Wb>KmZ88(J-v@R^R7 z`z6)GsHgIUhu7J&x*OJ8szR9PAoEj)FkT0pszHLtfQ?gRz2ae&PqJm~J5_ZWXg=jr z)4`#>5oQI)4oQlvY-$sYAoMDbswB@|aw zgoTICT+G7%lD-m$L(>rbw5yw2!?6kgHYT1>WQ88Cu4V*6py=u+WNw5b4aBz)&!6AK zTQ&D95}{8-#70pw?12g#-f}ileafd2^eL| zYXMMH6^0h!t@`)$k1Z0dkt;Hoa6gPbt`Fz`$P;){ zqZ0?Hx%mO+<~G;enxH(S%~x%DPrPJKZBHjxKIoXCbynX+Uw5*wwnYHwJl7U)aBozs zO{s*O&LM31!KoN=^mM&8Q4Qu>643th)2BnO)1@?;2Tq4caz;6zQ=+@SsmbRo{XJ2d z(4pb!B+=H^&bE2EQZ-HgGZH)Fk^OKR)r*uSPV}}MeET5>>+jEst^fOVxuU0Gp0vcfxmo@5H7J6= z4}CvZEFdm_9XuO%mWDJ_yOkpj$Dan#R4JPjDiPt$;$K@Tu(}Ge)2NQj&=Hl zp8?lho^Zq(75gg|z}2^+(rx$dqTn#o$L70MDIl2Sm1k~?Fx@Z!ibe-$&Ms@A^FUw7 zT@`!`*VEIJ88wj{M8s+4J4@_q)9{Y^pFpd1ly!T{>-xiBQ--W1Tiuo`!9XA`(=vEs zDSFlxCFfJu1>8V^M3Dl^fPrw}*8p=MDg-0S|BULOG5M-iVQZSxziew+3wevWBWjkY zqlexo;w;D;WJf;nSG7$;@nvtrpxNoZ+#lvjA@xqazhHCy$X&UyuZz6QuZB*z7#m-N4@qR*+-LsbA4k+e;=a{d?kv!T~;tmk4;b<*$Z|Q-$wFJ4}0KYGY2z2ISg+$2~ zm)36u-AE@nz+z$a-5~6O?bK*_7?B`ptLK zDiYr$h!P>^8s6E5dR)9W{4B1mb!V&)CAwijSqII8j3rj6IXJGF`@#4|MgorVg9eD= zab@~4VZ_N5;G>&yI#g*$z=znfowkrW!gHYW%xc;gNwxK$#k%RYQf8VO8#!}B5-y|g z&G3Fox;XJB4SL?VOr}I%4q3UFEq_^kPeyNeO`S3z1jqT5{MSv$F?pTJR*ix85q~G|i`&G9x zy{*m3Nj8ai(!r!Fp_n9(Vx2F$3CL4f;;0PFooqj^9qN<$7r5Aiw41 z(m@u>&AoW!M#FSuLj;|F^K@LSd;eoZ|LK_Lm?$}9V=S>{{zb(~Bs7jTkV%fzm_>8X z1>*N7uF$uDwqv-}kRgv&Z2*loy4{y@kfQ1U-Sfi6=aMT^`bb<;W3mu&vbsz77eQOq z?~o@!afO2twgFUvWD*T=msWqIzRu(5kz>{fBHtd{3D0~H^a~sRAwdC$gJ^7QgcKe7 zLPYie1aeL`!}9Z!kwT6c-e9&92aq(Zw6>&bJqor#cJ}sM7m)CQOjmuIfeFtCty#z^ z&vE1nv^k&x;8E0KIXb&Jb+@d)t3gshpkqOGOH_fw*`}`#(M@Wq!$a~)0|ry);UpX# z8R`30D12_o=u=1bYf|yvH8Ejf6}P3q7~@{8aqL4dRj`~@qSRDS!BapeeD7jp_#JSO zlfc8>9ni3uZ-NJ)%3V}c1l_q!R{VpZ(q+(v_S9I5zH-ZcHDG+Cpl1~1=P$$cES&?* ztGTEH`=AU%yJ~>2-HTy2iveGN*b3enBHL6sF5oz+b59>w$~=*`D6?K#$RX&ThG+*1 zoh{s5#a!Tfwm1!+G!59CwBd_Ics8Ei*XK>W#H}5vjuE_gN=}Y|K#}W6dL0qI?O^C8 zW4M(4#%k1NR&iStNrey*sC8G4fF%~;NZN-LPh`|xdv1HMzEBZUnL}L7dL+^#<()X4k|Z<7uA@n%~Nehejg*@`BaKJay`W z_X1V4)Bvjkjv4SdFP{=cI{*t?&!Rg`T8KjqB-9FS zo-edV8;2gts1*sstwBJ-ju@1SUI3oCE5)`LQ6T<9`4yOcX7& z`oFJPs;miPGdxkGuP@{Upq+x9gncNpknyaUrT7&RPtAOmh6r}l+IoD{KlTx_BFj#$ zk6X}DU0G>rYFhUuy_+G92m1wT6uFU5kAh$Iv=g5g7Uug;1{oF(iO$rm#t>>>-k)DG zWlcXph@q9_TQ>tXxO;fU60EZXU0GyRu?KQV&&_kA+^WK*rLYcrSceue#K-f9^HfmH z3Vv;YOAxh?J963tzFk@Y56{gy{SW|frd&8;!R4=ReQ)Rr$k6Ws{S^k2}i{TN5 zZkE>A(TMY3L(e8lr2t`v*Q8zlCuB7+z8sfOyp{3z=kEweu?e6#EBE<05_VCn4bZD& z|E{xt>?15kFyHhn*{z1_l=1T_fC6r0SQwaO9lGn5C3y)iw*P?gli!rl$M=)g$)S$QFkuMSO7|9ML4##rzr|n`#{|Rz_lh-gx_&=9M^2 z;TJ#+EfB3sBlDyqDu*6G2Xx3_FhCqABiM%nmyYV;LCpX0V=u~-UD-YA6_pw=4<4>c z4>hh7BV(Af_pDqkBqWYV0OcHQW6%?Ha_xE5amZr;_gIs|KFU%A+22M^5LP=W- zn`bKInBYA%3{d^U&;^$oaUav%;nt8O*+B>*Uv{lKwu2*fI0~rQ@bmWtQEEU*tfFwT z1(+iD!RR}1hc%#%>wFqac)@EWKHvs z2K1A4QGQcqwNg$HJnrq@do#n73Mu0x@-!#^T7dVyj@>#VH^CJj>joV4p#B4MWK~hZ zh^MW(=q@WS1*pgOy)v!Cqcc9XO%lS6c^Z`pziZaU9SFSo>tjQWfL0DKFu==_+0R5N zX=+L7o_BtFEytdVJjgh(6Ntytg3mX)yW?Zm-8e%|NVY9nDhzvZpiW2i@?v$q?T#9PGvha~KU{AHM`;K<&gY~X{ZYldjud^w-f zfYmX)WP8q^TXnVIK-GkQX{HYHyW$E~Hgf))m49jBuWJtEl*VnVbsZicquw9h1PMYZMEtX;*QW z4jD#|Qa=+QC(V_vRIUFFX+AACJHcHrA5P~@skF9yz=ndAvjxrSALHdo+c{hDOW-%- zrEWB)7B(@_!i9l*gT47O#fAAeH`Q;^BUmM5f;qw2BH(BYt`zieQ2&;B4rZVAlvz+h zq?mq#hGb{wA;lcyy>}3rtBcEYALm!GySobzVAd+JD*kR7?3*7}%U6OG7R4L(u&Xd` z2&j&r0nW}=p0rX%&sqaCjD0!QMA*V(a0?XAAq0w_YTvs$2R%#JWYxAp=AHZ7xT8$C zFo(t~nT*>;d$K(z=m?-E<4T&bwaMY2$~vU^vV=TXYs98>tz1jk))Z}bK9 zoHesADxTY+go->nUETTi$;iN(x(7AjkX}ZdB*tBE0~V^DhqbRcw+KNKG`V_~Fr|#n zeobBU?bMB@OS3KeN~a%(GwJVGT&IC%C!GyUS7 zW<2RS9V{PQfn$C9b}kMLj_!kB)GJ)jMQv-I6Rc$BdIrJhF0e-D~IF8pl90+ATB!hc*6E~D1kx*hLYA+ zrwCs~EhsXPeuM*SO~?Or(rSy5?3WJ#aRPPG9Lt7VW}Dz0T9(L;^5z$zs56RYrtndV z*bAHSt43R!zJWh3v5#U6e3-7%p3V)QBTstBxhO}OQX<{_+JHhOS+Z-CDQuNHrv{GO z+u*J*)B~($0|9V!RHvwY$vN1{nNmh1%Tdum(keT;c?e45K7tw=a}C}StBZEv=?BWT z5%a;(GU7(Vo=JB6GTR^jPqV>K?*9Mr$7h4XMnkhKBlsMr*tUxxs5=GD#+hvI+Bbeo z8R>>Fx2Lp8woe7&kiBkMYz4z!Q3rgtlABZB1Ay=R`CN&!qU?P0MXlTo$N4_N1V{4))LzY_aN}p<)D?aTmhXhU@@o~XgN4lRRXcV7sh@ztj7@jcbF4uu%(W3 zH_O3AtT#67DZ>M014;sQJtQQ=yN`gab5uN_2}Su7_{=>I83+zgG=9~h@t8XFX8RA21HYVi!=In~ske62BN-gx7LP=vj>|e4 zMvHnvpziNxX^={lVE}QT1c!zR&uLr{7xdz>Bey0KQ6|AUrjjALV6tTg3sP`Tl zFS|4yki!4VpFZ)t+nL+rV#F$W6BoM!^_=f&^co#qA(vJ`V^~16ns+I}26u|CotFh> zZ^-BhRC@@vv_if;Km(eKzm~6r%f$c*@S z`pPI@5b>)hg;{$B9_wj-poq+01UAg@TeMAOHFaUUg;kU9l|`hOH^0I)W*Whibb}WA zzY0V}&`N8+k8fTBn>jZS+h0$ft_qvlun^~Yqjot;QCj>mN@IF$8f6rR&(1AjF-`#%LhHVrp zo1s4!acl~sz$br6ckx=+5(eIUbcq9hYsoOc{=Ba?dTuJnM898j#IhV))bG-ZusdGqm!YZlRLYcWP zavk^*a9yDtG%^+12ml+CaHsg}mGUxv`3s|1vuI*y^~jT8V$=h=DnZZN1gv>h|3%GQ zaD6v{LlMN{WI zRh!^PPAx#itre?dA^{9@Gv+wl+pj>Xm+CK5l08L0(*E2?Fr6~dpW?NX_Yqd=Lzm$> zbgT?r2TPyd)?;G-1|63yPIr|=g!&{zx}VP*WK__t+ zV9fr^|mKS#^&=JYvhN7uMh)Yiw0qPzE{?Hjmx`hN}Pul3jN$o8%OA zIX1T2SWW9c8lr`R#^tY11u}}@W`6pHcu$r2fa&A>QRh*B_mDBZ_30D^-UGKr220^_ z@CwDu*hMJ(0P<{Ei92!fBuEjel5>b|KNKM6r!t=nLG1?O%9NU~#S1RwgmOh0&)j8PoHJ?RQt zC9CU|@JCC$j_cq^;IFR^M{Tbxl$L}ahy$RW95;Zv>bn{tS=Q(QvnW+Ni5y&H=s&D; zIq3q&jpwtzCHjcCZkF3!$LzMP6mJbDKzsw5{}$9*Lb}r-B}C5v?WRSGEF6o`5Uw!vs*qy4CVt&F=f zo)x`%b+k>^Ir{a6$d#eiXeI)WVp!MzSqR?5c!rSvp^A4rn6}61jQZpLlWTTvbdu0w zC8uPP#-YM@1*ItS-Thw@iP|QRMgsx^wT{V?lGm>c%|hcQK-xoW5H#Vda8?iSpjXHm z1E8{jd?gby?jb#WeOe@+12cxpj=fahxe>INXy17xHM3uf4A@d$TI#s<57`Q@Mph$l zEeFs!WLAh=KVmCX=VY1T<2By@ zbDbhhPD+xEF>2l!Zh6=!y~yrrqt?96NBuI142r*7-lxEPTYvxcf;QrNaCY|Al|ccc zSmdT`mjW|<^Lk7Z*CSeVDSCg!>^WQyJg<5o%Mu=UhYn3u)$XYTJpIITq5TlivenS4 zA5)c(>gUPCN1x1*w1=SE@7N9_dXOg}>!G`Q1tDoi2tf|^PS_#hDrm_o6*r8*SY&zs z;NUsCiF-Q5c~9(UwW6ELn%68T>bFl%c=+gNHi5N8AJ+^g;go~ZiROFo1Lh-?0! zn^XfWvib0fC8*_xBRb*gn#W;3)&&`NiEQ|V8zLTR%}z*Ih$GQ#;D((Cf5JmlAcW>h zp?9?PmwE`pDf6H!yjc~})jaTuc(=ILK8IzVXU{%+k^ut;xpcdCAlMq>o74YtWz^gc z5{?4fG?%UBB7#(O(!-;PboNx*FJX8!JP<8cdI-})AGg6pe@U_Dm}-t&67mVI$N(1I z^bE$tKOdL5V9LWS@MMHcN0sHy!fEf2kg_8GS?R zKL5h!hxboC9z9%hy{>b;Ugtc|^E}VF{`?WI8DhS!tT7sg9W2Bjk2HR=PI1v69(LV_ z9Ss)fz^6e@*a1^5oYtkU#93$XNtfZ)|lUD9C?|mkI2-hbKuhI$mKy{J$Af zR$dvB2wB4%V8lRJc_567*&_o^E;0b^TI!NNbA5pr_ z$@x=tIpGq7h1hn4DtY|a0^(w}%R_XSA<4g!20=(@2ZT6?>2AF~b_r@%g5It!2!J33 zl+D$f9$TF|57Xmk;5$P5L+m#y_Ald%;VHFbvat=ceQt|5qICP%Kw;6fro%VKU#m$fQ+YUa(YN=aJ@aqAB`#1PsT*Vo+JeHMA0~U%G%Gx#yNTAJTZ*%5BI?1UDL+dGX*Fbz7(U}g4)9?k#9MG{}f3bU?ZmSP(M z*F@9=#m;}cTO@3eCQj`q+Ma@xL?eQ7qKkF`_lOAiU?S1TXrRn8~ zwC>TEs_s! zaxHtg?Xf#8XZ5sdCkdglxt#FJMq5#X%2s(0smgpFiduSgo0nwdkP0FfNbi*2_VymB z$Ep8?2QT(@+j11xTx&tj(k>b!pa@0CtCef=acXE5ebchJaOLTv1S zDSo}Ud84893hFz;)A&ZZ1l~U3bEn4hZ9G-%cd4WD zV3yWSc*mrnK~4Z+ecjmA9j2NE;_%IZR%->}~Zem|<^w?+%W zrY`T#1%0djEhgc*4PjTVRc{s7RWpo`{u%=cw0D__ct%DjP61xZJhX6n zqQCj}m!jc&REh6yfhX+D{}xgtbu=zCN88B_nr=c3S<(lO+I@O*t?Ef?Pb?ugJStE7 z^UA^YhelQiU7yDg^(s-tqS^qPW;jARKf|m~b0wXaTn_h2@HW&iR*)c5=x%HOy2~wY zJtTek1E&8CFJLYLCS&J~Xr?=tRI3W_*Zi@#4m5DO!8bgC%;nEjY}`xl)k0*x+VLM= zQZfwK@8hVer+K|$ z)*J7+l`%kCa5^hDJ(DVaj}S~`$jlq2am0$~!_Pfsa}&7nldwbgSN}M(1^NB1l@LJE zIQ`}5`nwo6ICrQaay*a4o)`x!RtL~YC792{ESp7fHsGEfYh#KS!;Z1iUf}QObC~t8 zoC^sxSY28``#4EzS4ZJD`!(@!R(_m^Woa0p3jGE;>0^9YRk!$o0){Gj2Fr1gMO@)e zQ@j<{u)+k4$W48$T=QOBGzir5Li%N%*eK(;!2;Y6PS zr*@(sD`nPY;2IwGX(p~rDIx)~MTDGRbr5}YSONy6;g;+z1zpuz8T|iT(c&Z{Yk~jkvfkN9)3??;=qhF|9r)OnjcIhQ@#83HWORsy4x} zIweG%aWK!Vs{LE~d+^RbGg~nDXi1#Cn+!Qt{JZ4_$AC+LUBc${E|Mzf>SSH$w19~x zAeAji!6MzO+87Te&in!7KSFo;hK=xUTbiOYRh=Tj|L(glD+6Ee)k@%LgeI zR8S`3N(`bGO)26nUN~X7mk>F2A;T7@9@$Uw6N8hW^%8holjYeeKi+K)Q&vW{i|bpO z`h}eWf(DHP163|#CTHzq#CcQB=i!Biw=LMU1dp4JcPP8&yLhU9Xy_5^cN^4)0wpi{ zL#C!985<|}1X@bGd0b3Ht{J>;8$X^dI@VOVM}ua0g(|Ky3CeFfYMo^Vy)RHNK?=*N z{SwyicgA&IM(hv?QRt5FmC_sOV=kt*E8=Or;Z@!KOLl^%v0Z#}D1Yu-@TT)bS@OP3 zChDrUC1-&S8fPUYP3>Mmtm?kX=}pL=`LC#I=>qYbEYek`pdtaIF09hGsULENi(Q-2 zP_FOdy>a37<4w;7?zx$iQnImLtEiGAPu}s=QN+q1*}yvgVgX~+Jo^L$B^%p712yDP zF)$F~x01P{MJL(szyVwRa;r5cFx;uiz<@b*+A+u78s2-H{nu42eies1U#N;f8lLE) z^}DOvUQyhSIq`ajc~o%>1ayz;^h_){Cqz0(1=OP~R{VfvndopkZW@NYXh#5cPMr@IIOdcx%6X|-6ssX^psJ#$zl}M>Z=hoaB3i@bAmy~ z`AI5r6j9ObLO1Gv{7)AP&}S|`p)Q*OdC+=!IW#g)0rftypLC90%?-`p&Q_49AmSHq z9$!wJ3c+}`?P5B4^~35YJ5)5rjj}u2*f4Jsoo1tiQ0^(Sv82|2TaHwRKtOtBDTi9; z`28d*X#@hV*{=_IIX8;lyE_A9N(e!?IRdYBr5OrzkLzFB`{Ygk#L@LGGGx|ehnI?| z6MU7IC39z6R*|LVm7yqVUO)kDPjV38jxqk6z8mjYGL)`dqL}~f|O(~ z%R>8g^?nH9$p#Q?Xs_3jyTTrFpo3$W=Ti*5`is$&V8{2Uv+%;=46F*8?GMuF62C@( zc^c(6R!jrHnOm{V%bPz}+Z9$Vz~OKVZ+Z(}=c+{Fo(W)K{A3g%o=A)dH<{Uc@{?%XJC9FTN(Kq zi>9y0kSXBNf7Ta6%a<$8C$!SHvagF~q6klbK`$<#Ik}&JZ34uT`J?(?R+Ze}-+2sJoxQmhImGe?y zNaqjpd@}?6j(LlQGkl7F*5fxop`*bqsdxOvNjz(Uu?v^_>OQvN(AwQ7@RO>_e7N%% zbUtA48ni0EG^u3iV|VJAJsww;5$b&O7F9D>N|Cj zz(14VcZe74C9#Xu9#09B-cH47h?`%COu?~8gtJemk~7Jscw1Yr=EgEiMDtIu$RdIS zG?3D5u$*yOK{8UQf;t~hP0+?1v#}4Vdoh9b`ein7j1MkDfxRz&rX*Mv^>KOemoe!n zTJr1XKlX8L1_c{zcBCuAjLrKA7usFO;!Ig^jp=uQSa?OQ;i6izu6fJ_~lxTKE{LB zdvv|9G(=n^2w9+s0tr#1NCatyl2i-v9swvZLPM)D-lPDwjT(wT?H`Im4t*M!jISFb zc!^@|?h$D?ZDlw~AYy*!szFLX4a>G?5#zfpH3VkR^Hw{WNkDK~>BoM`0kApD4u`a= zVX(dAL+R@JtJ}6T)dk_Jy1mhO+pgp(A6?L`lLPLjuuhN?z3!7}-^IAe*`9RL(Ydo* z;5fmY!QA&O&$HEX1WEgjxPKv9k=~_?2|7=@KAtA(q96D1s6jo~{$+9`K)*5~);BO0rr;tWp-zP94;|4z~ zHfLVOT>j>2`CN{r;s}heO|>}D@oR}>NNB)ShCtHy74PUHyb4F5aRI4My8wn3G9zr$ zl1L8U4!~=R0XXnVQ>XH|fd4Si3Jc|+Uv8VW5j+sygPHS*W4b{EP)11}!VH}Jz)VvKmb!9h3{F31~r%g zQL7HhBIgTmzhCO)Zx02G%I;R_SQy|_2*nvM@m`XWE-aG$6S0$Ci%5C16e{U3`RLp$ zMRZO2U@bYS$w+__WxgK9P!*D+(W`R zkyiF0o|e1n`J&AwvVl7g`tiz1$WL*HU9{XvSH(I1My!x`AwarY9>bms(>E}P9{uXn zW3efE7tP!j#hI?zm5dCx6g;f125)ZHgE}Fy&&#G zdAmV~zZ%j_ZC_J%azXW`=k-PEX@<1*Yo3*Y4LS1-y>Z-}#p zjyi8<*>OQv*PZ3b*Ww8n@-;k)D9QWoe&UH=8dca7^!e<9JC>r9% z1Z96+zlOH@771!(!XZ8yEe@_X8+5>`(Iv+!FH1#bFY{&N83v^SV0L3n*WyhPOrju( zg=eg@S_V$*F_$lo5w1XNNFpNc_AMXVfT~NtgL?Z9P{j##EJ%P;JxJN5xhNvB?-DRH zz=nwiaFTs1?6Dr;xmoit$oZ3BPV`~Emw}&1Lnev`IOQbf%Z{hrC&D!jbnjFM0)j`y zNg!l-;yV@w6i6~H11`L}KPMX2a91jra=rjIJ2k;>Zk=KB_Ei#}bd_lATJ~xF*+#s< zX`aD{lt*F=yFAf7PN}GL_DKqd=q`fHSg;$ze#EZNQN|jr0*n1kL2$7DX{cT@(?v5- zfx!h6&>0_3kg^ET@`1b7Al#u+_+LFN4Xnj1a5S2?t%P zmqR4}8te?@uUVp%)$))b%dq}%u~-aJJervwPv=DL|Czc2&E|zVDv0!#HU{q_UB5nN zyhG1>lEq}YHhPJQ2PquV8f|+A2LOhWMu>4g`SM8kFzQ{I4A~ihAk2{@F3~POu-ZV$ zZZ`rR!y5fKi^%2=GUJ#FZ^_!5m;0B&!2xzS{=8dZKEe0#KSB6n_6t1VpTgqm((&pv zoF+hV;P}DKB^_LQr^Kdb>Ipz{FYr6HuhR@|_ zHh$gSqJ&?qarXY^nkw=Y{o#lG>HoL;2BsLITD3~=YU|LLgGgb z_=(nhdtOsBsR+1Z;%-j39E_uY^S)vm3L+ta;I|Airy`wXV~b`yweP#B1Z5|+6p zz(s#vu`)zT6FGQIQz5d*5E*V9o6gOj6BSCQThaAiwu%+bCKHrpkjmyXDd1qx#07ul zRtGSqoeoy|7Szaki4G^5siW)n+6yG#zc&VBt8E59-RIDHxy91KDQ8b=+uD4fVW*T^9Kq8Fe+?nB79QeP$05x>IX757wKavkW+doKI_@2MM z=q2~P6O)5z-{<>)gIt(>jMP|!l_8% z^k{eRCPHwm5Qg%+fKK`lF#sTU(ZCJd_#&A74e9b~!HQqlp(b#Oa*ZK!N!$KzoSXLr zB19mg{gY_5ppM1R!v&WGD3A{)LvpwRZoOF+X^H&x*@UPMcXk>>`>YV&BJ1~;+|K2> zQWtmcvgyB$6KRsRqfsOhH{V8Z^$u=0Wj|>lNNK@DmbTIpU-#EzX@JT6aM)b=Go|H7 zN3dLFpTCnlBI{jNW@m#&3;ZiMX-FRQ)o!;Oah&}JuElMFVT2JVV!$AD{nAn~a9UMt zi&u8{u2D%v&C6Nw6gJY}jFA(pc2N-k)$f8{Hy3>RI zG&9@Uj_s^WIy`Ps9Hr3AZsZdKhdXEm^npD)?MDS0?H2;_JRvGMtlg+sjmSp`9orUb*1~i1a9G4FTL84@@bf7he2rbPCnm@Smk}&_`>$0VX9x=>WGl8Z&%;Y279ayP!zilKFWe zF0o2oL|Tqsr_O^i0N9|nA5OTtO_aWf%3Sk>PHV;-%c=)9Fcy-|w$PR=3(i97DX7l> zf=rRaalw5$^5o3H7YDX&JOYllY%AQ^J#F8dGp^pZjKMO1KI8aj0K8)rqj{~PN@&j? zGX22z)K}l3V?-jICgY#ig)4_>$@T_=WzIU<+wYWSH!Vk=_>2Viy3X+SF8b(?0V>%q zBgw0Ywi6nxL1qKh+P0(Xvs!vaoe8_$1!WL3onic6txH-!@h$!n67v-xWQ)_e_lTLw+`n??|2p+z z$`}xr!Sg`uMzErP6Mr4<-kuCD<~Xxq>D3EWveR~f1Zh8Ew%!8{4j$#uay?AMz)*wM^ho9NN{`UVD!qZ*I)>21jPQv|72khBhF4-XbYsr^EI{x%tEc zWeh8Ns4m>tnDoHY*jhsnfoEdE$Wr0{GjHPGc@7VxoD$nSfqt#~pU_7z)>xU{Ghp^YGc%e&ky7y}*l&O~+&#{b0&?iGb@N%+_H7 z3!@?@70G{KJ+D5S&&^*=>0MYazegZN^CMH0jsAefup~H`KvS)vEcS`1c(jQ11$rSKE(wK18|Ox zj-~U9Hy?ks>TI2PXEctEBPT6#`1~wWxLR7NNXQgBMphZrmBxntmhl3eZtW^>VYa#s zon(rp;_IMz=yQL_5J|6^6s^b*!{;5U>(BTCn^QyDQ3m!+!ZREm3Xlf8L9W?0l$e)w z_?CDq17T?8x?H>mM|obdq;-M5r-b!6T!skQ<4_yC4-4e4JZJ>@S0F}RL>Z`#iE_9p$ zSd+l5sXq>%evhh;$Jd4Dw|O*iLqgxnz+vhbTB$lyWPg2H@pmm$_!V{!E8sp|Jin9r zJKW|L#%rQ=;I#Y9{T8cof+E6aEQhenaM*LWPD>$S9y4%_?J5|4G~5Z^@Di2gNKPA! zFDOpenXWl4399h8L|gg1i)1$xfaBPKE1gyY(sj@JPsJK^T6j8fx{MQG(*~&=jKfM4 z&a`#0r>36%@kPEBhPRaw+d%}`cm1Ik%#e@c6PL`0{MkDix0He|!rqY*yB;eP$WRqY z`0%j^G8zA>ZV|W`f5=Znm|FAO9D|09u=%=$HPOi&aZSy}*4ZU0snrp)H)!4D_z#m& znE@yv1tG6@FwaB8{2dUxD}0eLM5h4(xmW_Z_I8g||6(5r3NPuC`9C(G?8>4(f2~yt zi%vViEi%PTPY%eTkQD-sOL%oxCGD%u~nRdvR_`FeD{*Hpr6*<~U#o|mtnkl43| zo&VWvaYN~Im}p6y<}Q&;rnmvvfFx-n(M)+TWAOJoPf{RA^vR+=#Qqy6nE3wvAo%-s z+SsEfT_YnSCB5976LGl>&cEa^oy%0+-fT%~bxXS>KFJ?CBFP>rJANx4OA#hJID?I^ z$l&h|UmO0_RsDpcS*$af3lll-=d+-g`(8$0DZ&kqS44j6&r^@CP(n=J#0MCJ=wu7~ z3&mqLmX(Nng>8s=9hhT(Tq4_`Ext*LUiA7NA;zA^r*9*%5Q*&=YhFBsTz(pG|l9C# zeO{9xI`5BzvPP7h8Q+gT2UE8dm<&HrLMDlAipI&Ur6w@R7!V} z;Py#uZhnraaBdE3t0H}%rmJ23D4S8U*Zja|o2-_}%-XGc!%g+$cHqIXFB)Zg!pckx}>+I8fYlBZ<>BoEQ~tu>G3HPmHuxPdG zLW8=&rh4;9x&PqEUb}NViH@lZx^{j4`8VtDzdN*$nVh)%hQhHXL7)O!DvOyj9sNB- z`WD(2;QMX=zvKNG^(Xl|C?rEEpuGKJvWg(8w!Ii4>7UqpzMdlnw9T}#o-8T&ot z3-7w=fMlv?SA#ITXKv2tcLJse3RG`h?aiksZA(5+CbpZ(nrW?Gy}C#5?eP?*@%Doa z`3i1w>Og}gS6yE{84c4kqjMgdn5+93yY|lOHv4W9UzxT^EvVSPb^90Ng)cf9!Q-w0 zUesPcVPAQTOu>niJtmiyEOX7_wF#gt>=22*JguDMz zO0ykoLJ?_1=6b2x=XqIkSje!h=RZxzoi9+kl9cp2(&(W&16VRCIp|+vF&+1EPO`iq z(zRH!9u@V$wq&)~3`R2q7421=GSxtL(CO8(k8P2wD^_s-8>-`RFUJiL`MeACHz;DkcemyhI7sTQA}t%7@ARD zlU6K-+!E9#qcJrdL$BL<)^1-clXrS$_dJ;uLmf$xgq*0pdT~=hbJQD}yQZATh@Nwm zmI`=b0Oaic7rkHF?S5Bkw$(Y)*lcZ&(aL|ZJfiv6B?)+PyFsU>PMnjGyTCb;21Hs1f znkYPx5_G?ubyelQeTM8a5Hn>eS7tf;+ho3UCo@CLfJ(>GUA;bbX@B;IZv=-*nMRi+>t zWE0SQfl9)m)XSiuta38*nAc~$X>2JZJ10EjpiO3&=TdyG;~)61#YY#NGwOe{ukl`D zJIk?PLp`f|m9g;k$@=&YyF_O?RRc}HD#R^b`k#>5VXxy&Jff-oIL>=JooP&%9>egOP=~0J8h1 zFFCTWp3_;d+S%4x<&D1P6{6$Go_%%`R!3x;F4PZ2V0IDFh*InUL~G`y4sc%kzcf40 zen(WX9nTZ(d+CspnD*=^fX7b!zOzP)Bz8TUV;yq}7YRbnpINRy+3ZulLVSES6U)wk zwTrJE-LThp#ew#rsJtmk*T?KuHOk)(4&P4eES3pc(eN&3Vz|I)+_7CHD^jRlH@qa$ zsxTn0fIg2w{skv^@MUWe zr&smNj;z_io>AK^Q3GjI zx3$*z+BQEWKji3$t>$v=FVMb{FsYZ=bTtWD)eJAe^PMboq>8A?RwD7yO_x7yoZz!f;l?^MIFiO7hMUwgGfW|Ij zUaPyknBVU2K1LCXyd~9W97sFl4dR<(tUftlgCv;k}aSeEr>F~P@;!3h_?3d2g)_}oc8?N_FN6fv*j#zP;e7I#YsJEb`6;dg z-6q|~obtvq4>~n&ydtr0Pro^JDdBE-&g+L?hJGFJr|B^5gJ~?=HxK3g;8UWhnUqhe<{Y_*LD)SiJ3{T8&HKD~ zTo(tIXZG}wJ;NIbo&;BZZMWZvsm zvBPXZjbGc267}ibsxKM1Z?lDcPC2i=i2C1U-a>~aep^ucc8f=1Z>@(} zSI$T2jZe2@a~^2W9t^A9)pXhA)Un``@T7nzBsA5uJ^jKRJ1u{4t;0QUuJx=bVSHk2 zdgR}y?;h?S3**o3sOoXS=?-I_W%#>SK`~w#kint9E{mTE+~*5!3jWC{TNiWvqV-lm z#Z&Y9UjkN+ntFk9yZ6+FyQPPUMh~Nv4%xAAs)lblawRQi3)zLQutVpFII25gP%wzQ zUGIGi3DQ^8Mt%Z=z^5$G+l#~EB5}tZ>q6XhpYOYKYrazcQZq3V)X62sF7r@c*)sok z=jOl8jiOvea94$R`-vyN;#7-C-D7VTKZ&$&zq#kxixNOGluSMKona z`jOiHo;mvWb{sUplEeNygU=0d9d68VGp=htKAHq%4L0ar(Q9|D1+FEl)#zobC(b(l zGU+H4XRPd#jIn%*hlDwueye`Gkw;OCfs%yLvCuz)6X$6XgM;EIREmF-{s3QQfk4OUycVv74i zn_JiGgyndRcVioNL%?kaA79%y$`TH}bB~!!`svn?Fg6!(LIx(s-(s019RWe)I3FSz zyJ~kD7O7~#onb#H{_j8kYl8pX1^;^x{vY!NZzY(0{dkR(J90Oqerku4+t$*}fhqqV DpNolF diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 8836ffd4c8fa2b76f838f1461dd5af1d43a2e3b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 323 zcmV-J0lfZ+P)p_mOQBuY_Ofq!EXCOm({&%f1VW{!8~ zy~}hQM|&&tHTfUdw(T$sUDwrheH_Q8Y5Klb!nmSuHa=XpNQ^DPXr zsw&_2PhUj+D2mY9BuSQKp<&d#lDj<5E6b8GM!)!9WauBc`EDU8UZ6iNCNuth3vYnZCe6{kRc>NZi%d6 z7}7Ld*Oi8mK4b_oZ=SP_^dUn?0{jaL;>Unnxh4$@@lE8B8h)ss;13ih VYS*BZ!D|2j002ovPDHLkV1gR=g(Cm} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 826dc2b8c224a3fb999101b84185c304247467d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 626 zcmV-&0*(ENP)lKp^09x%hoJ9Co|i>2&&w zV4u&I&1Tc-bSxIL*=(QBuh;8xxg3o~{eFMD-HHUe-R^R^Tr3u?R_oWdY{1WlN~O|x zJg(R4o6SZ5I1-7p+ikz!|8k_sWXfbRiA17OsSE}KL*RHk-tBgsPUlPNryLGPv)R1e zZo}bFCpa37YNbkI>5WEXzu(X2bIoARwbg3rph~ja?VV01pUqR0YOgaXLy&6nMQ}s{-Td z_$xLigvxRki-jsM!qr8AXS3P)d{zs_O>uQh#yFT*BKuq(OoSjy;OYjc(swj~5ebGY zfvfAL-tYHnwR*W+w1Jr{35G18Z^NN7^~q%NY=BY&;iPHqWC>hdD-|d1^?C|pUUV*U z6A6Yap}u=dYgMMc1|xD4p2`Z;SQZDwxhm|i1~9@~NHAmxW`Muqbbkz>OK@MgIn?m8 zYSIIiG<^tH$6s+e$#X!`5$R2`T|x|466LmfNb4Vsf<@^K{{O+h0KVz?ga8p?BLDyZ M07*qoM6N<$f7>A>Oq*Me#A3{q(5YZA5I5|k+;2;zjB3KfkQ*8}`xM*%d1kDZxx(O|AE>2P6 zBofq+L{J({g`oNUFo>W!=RM~h@Ann=8S6dwKAg^d&+lz;dV0F=r!n}i1!OR!^}>+W z3qx8j3~9YkCOtntzq-1*u&^*YJ3Bc!IWjVWAHKf6K0G|!+}xB(r9z=_adFXZx3#}Z ztMu5|*xK6K#>U3n+}!8i_V@Sy>9V}M91I2EaiAG^D| zvQ~V2J|DVxE|;Selcdqz&?_{4d0b+#ShWkck|d3OEZ5zHFq_Rd+%A`^)9J7)`O>4K zqqsp7iE+TS>U28u`8>OfFTK9LPQUZC69@zpNF!G$@*#ngVzpZD?(P^h9BE{?FOyJD zvD@w0Y?e{Lkw)57>O%r;Taz^Mu~HurGcz;n0**8iy*e2x$WrVAjx=Tvbuv^YCMMVg z9O<{INoR(KhuH^pIpSnX|JqN+mUW6pKZCk#4tJgB6QvwHlAd ziNyke2@kc|Y`wT3A0Hogc6MG~UWoMq()D`Xu5kI~(Tz2YE|=5k3BrxpY24~`I{7YEtJQ9| z;{(O?k2?sH>D!!#`vQp``50*v*$qhuxq^F3_g4BH>|eHvlBaR`jf3s~i6N~QhO}N7 e(t7bDrT+p$##{=U>e{^k0000!^YCM09%aMXSA?r5%6vZW^?DrkalKNheBb2z{%khe?RGi1jYh+^?Pjx?aw1*V z9mg3ChwJrPh|5Vcp^<8}nq^so!CTQTDAF{oUayB?_@2w~-{&;1+U<5C7e^I?zScf*v1ws$toDhE z_pvFCD!`2y?}0jr#*Jxw~AG S^DImN0000%F(@XN&ha@A-J%bDr}&v|+Vcb^i_I&>{NlVz;3r+U0pRAjYJ|b91gk0a_eG_ z^Ye4wQD1Sp-Nj-t7z~cbWA;&ey4ZiQSd3Fl5r@N3DwV?FFuO5_F4h&UT$`1O%jK$8 ztI=o_DUT(dRTpa@Wehp$j5`2BvQJZdnLF7iMsl~OIH2#h@*4-zvql1UdiOE?cO z5|790^*S|C&~*6hPkCzfiJNbNmG#U|ND7vTzj*pL} zS}9^So4sCdrBWfpP;^nd5b6Qx_X()}={IUEgE@M$A7xJVe zUG&`et*g0#7d$^d6P}WE2ZI56ZZxs7l}Oy*-xHovj#{hLTBYvW+nf060+h@sl%y(A zrXvSXbi3Vdr_({TFHcF4$z+0to*YBZyXA6uHM+H0?e+DQ97ET|Td>AY}9%27{$i$>nmXaQhuxxu>V6kB^Ux@f;P|csve=!_{h4 zR-(YVa=Gew3rHA8qtQa4pxzi?AA5kyRVPsI;`90aevii!kH;+*3-55Cuq@ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 61789674e2f3ccadf5ba32111875d7f94d28e58c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1420 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 T_i9%0)08~XzNlumh}{1GcOGxh diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png deleted file mode 100644 index 37d3359909a36fc4045088bdeebba87ad9cd3bd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmV+s1Md8ZP)_zxtmL^h$)Dl{4z4Fx?K3MvtaM70~y?P`@0k!YyI zM?oPGUvZynHmh;Y%rSHB?k1j2&THm3$DH?l9{11B&v!ph_umb0SvM>e-LP16!(x$K zEVMnV)oL^vH5v^*?smJ`Y&IASdcEG^aQNR?4u`|*^?E!WyBtyZT}sbDZD{VR}Gt4*iVe!o8& zjgH4-g|SpBRk>VtyWLDoUvfH~jYb1-lgUIeEHLGAxvQB3>2$hEr4kB-q>zbY;fR$= zC7DcuOeWLo>uVqo7!HSWv69K8B20oFA0G>ag3ssMZnxKC;oPylFoQ|+PATC$F=N3O@WPRB3nCW03LluW34Wsnh9@mWWu$EyxJ` z<_~_sZnsNXrJY3N7JgW*R*MokXjsTnc=3@D6lVfZy_=uh-spa7O2oTK7N$O!P` z@V@Yw!v4XlfCe)d^A59x>CYp%SYH~QB{y}Dts=!V6jABy!CLKiWMof+Cz P00000NkvXXu0mjfpzc6hD@Q6Rk-(kkJR=sVo4IMzL%#yn5CGUVue5kl`?}3E*HvpDqg) zDv#aXFQ7?-Q&Lj)zK=4_YrJ*qWJ1E|@ut-V=`{ZQ_wp@7ciz*n(s{^5D!RzGrf)(s zQ2x=O(>9X9fPn9nt}rmbZrP%Uoh4pX9I1M01Rk22ni?5ly*`zkwp!#~*zsnYi;L>T zi%QdeOPDS=^L_}9b7`%jSpLt;mn{+r5JZPtM3gE&oVcUbXf(HP-?p%@$TGNg2n~(! zvq!k#@nP{9y&XU|>qj;b*%MZ%@Y&Y|7;D~itUz^Vy9RLd#m8eLLs}efoo$d0K;rQIZ8#i=p;Rj4WWJXmm6(z& zQDxZI`Q*{Vp{-PqB?;` zes7cYw1ZZz%6>q1%!3iH+duE=e9GMghPj#N%1FLD4LwEl^yPDSJEP(Du$zPhs(_|2 zTGs_gi+7r_AWdSiAz1q~qg@U(0Mhk|Vq|NMG5%E&K6h0Pdn67w_M*HXo$gqjYR{Il z%=wlvLs--0i?N*$cF;urnKMfU_ua2ojf)-vJ=quMMjwJ0(Am0-G;+W$$)R77_1)%T_em2*pXyLJO{x+K~i_0Mk~CkrqoUJ~`jF;rG9jn6XW zpBYoatbWc5n&I@oB$<{j7V#bP4T2sMiqe(CM)eR6Pjg`+I& zX30)o-ypZSxw)*od{^!c+ck8j%RO(oTr0F<6vTV~ zoDh}HUM>0O=1+4K869u1e`l+Gk};|tcV_n|!zlSA-BA||dYp0~D5#DZ&%l(l8m#p4 z9PH`#$cdyi2C|-M@9(5Lk~OM;=TU^8VVIStlBdX(P*?x@yBYWBb*gd8N1>PsZZ?TK zphMw5+ZX;ceE8Ej9C9EELF37W>H-Cb3ygeQTe^VIv0tc+M0%xMc^8f9$F;ScGE`)^ z={jlH0}}NOB!K5;o*twS$8HwqqC+=8gAm%k$O1_9+RO&2-ozW*>A=5W C^v(DH diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png deleted file mode 100644 index 687010b82e72780df3a4dedfe9d89c98e1d5a9c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 942 zcmV;f15x~mP)KoXi#T9iaIH$f2Etf5qBa8sNl36 znj;8DLl6t4hk|=A`1(EPyzhCv_jY{-QTQIu$Mc@^JO1`yDcRUb`R z_0g17AN{YaOG`^DD=T<47!3IM`uh6({QUIvG#n14e7{!K<>lp_ot^FNZHL2QwOU6D zy4`NG*?f3-C>D$LdR@z0>RH#;){c&jc6WDYXJ?5rlgaesQwIkJtyb&o?5tX?s+&*3+y@$oTDIjW6~jZ7wUb#;|UB(UD1lM1uK>%`-6r_(7q@Jsl49*<{#e?Jfil*?tI zv0|*NtE)FRH;aplLZe27^OsJigTY`no8=!Rz-qVKbGh8Y!h$%Pg0R4`Sj=cNVoPui z;bjHr_4TzZ(4Pv0LY+>hP$=*e^Ri+Mv_JY$p%X_Uky@?RZnv4mT&y_tst*%WX0th! zO1a(c_xE?YlFf=fiuNQ4Oj)=`(0!B1Bwfa4_4$0FeN=_KUhl=lMX%Q*Y8b4zLeUGQ zQYp(~vAA5Wd_GUqFj#TdPhe5Mw70jXi4~?qDvzeQ7_8X!@?aR6pP%2{+-x)&;|eHN z+=PlYPd{yKZK-61an^x{5cb$Lk2!hXBGy`^i|{WTm8XEGVRo#Ex><;%+pUBhOr zR;!4`9*;*7m4eW4qR}X`jO*S?BoasmI@tp}{nOLae!tJG8AZp-@Pc{{pDr?;i{Xob_Tp3x}-J z=|mzCv)L@p_Dk5Kc=T9Ne$W{ep0H3T)M~X-h&_InhVao_J3Es8o7w_>5#SiRb8YxsdA-mytq=V%+uEow%8p4WE#vT+r+F z@}I(c#AT$=(f?s!^WdInQ!)wG-_`h(tZ!4)cgb6So2IP#Xv(UOrmXtt1JhYf;lkyT Q!vFvP07*qoM6N<$f|~2$WdHyG diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png deleted file mode 100644 index 284f7ce43ec1003f128a2dbc70ef1a6cc8552a54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1771 zcmb7_`8OMg7RPBj)Y9o#+CwLVZiuC79a~!-$_$~Xm!d)vB%&|2s5FYf)S(kzqqY!1 z8dMg8WF&*6RB9|KN)U$7Dr)N%)Y_Lh?=P5hKKI_A@ACcLJb&=@6RKxa6%-Usczd}A z$ZO)?ar}rpD+n|}3JOXs-tMkJsfz1lKlfy)PA}E)qK8IQ?W@KbcdMt5?NAy*vjCG< zwZo13ev=RRWs zp9YzVTGDVNY4d@7_yj5CZEq|u~ zI#f622LN9nXj?1GcoxkZUfSN9o}R8CkyO>xzOmwlSzweFZiR;8akxBBYFEUEm6iN` zweID;8v5Jon2A!y_(WN406EpNN#Sf zxw(08LD}|up`wzqvbibuG)hQp;c}6kqeI7z{9II|)xn00b9-SEBnm~q<2l&a^tcRX zWPy)9L_ncHRgJr@5fhGAuQp|ko&o!K zNOU_a%<@DR%@)7R;c$F*E_6Bm-rnBMX6F!&UQf4R%7@+Wcn|@HpVKc)3Oag^389X4 zY-K1Xoh}{g>2W`=StIgk!lKdWh=@#Qb1g}1CaWaH$dhsE0QIedDC-3phto|eu{3H9 zmhH1um^E~|n)&+dto}_mD<+o|C#fLLCGso{iG2(2-kJEi5zQ1rO99wj#lhO5`}gk` z`*~1L1!9wvAD=HKR8PFia?m0oNQxbqw~P9$UPYC?cFyx_$xwFy!`H6^DVmc{aw$S z2kPKhJU+CpyFd0022(m%Z9t>ZCN27XASO%*gG3@Btc-s`qv>}-rl+QQs>=N-8yg!l zGq>mCO_-aTn^yCnbGX=mkkyqHME5D>m>5zWgzD z6mWwnLq>oKtyE|Ic}N12OeS|XJGf%8oOlLzyrsozezNk}dWu?aKKf2voOXdorGH@H z7r2m0!IZBapq$S9XpNai_z>=#e@v z$9MPl%>bq>Tg^NlFjzI0UN~r-6X0P$1`o&v^FPaE=K-b`7s`ERXJ_wqhR>_#YZdnX z0;esKP^53iL1`zQ`~pl@GNtcJ`>M^jr-AzVInQbA2hZm@9NTjB{;a?vmC{%F98D4V z9Ht{23LVH9V7(bZvIPRDRbJLy2ckQQqm=EsgdzxGL}1z@@jWbd^UD|G&;KE1<+vI4 zsUH*V_xJy3@Ll{Me{OxQj(3yYGH5<5G)$K=*D@Mj1mRz)fMV``WvHWN)5Lg{ZmcWY3Zgi+5Jiw9u@HU#6KE?*>;c9UQnUnprsF1qRAwlMwBxLzxq!;tC#* z??Y%t-$9`+UAmMoueCu%OLh=1UC8V7N&A*pZ-Z|3gjs!n7l z?%v*>yfX&8hM1T(G9!%`I+LZP4+LV6NVyz7?j6YQp1lKah8Snt7R&C&g_5LFDM4NC zjp0pga))Sd4_!$#J;~B!#p`YGb2K1!0{i^-+Hsb3~N}#6RH&0otl=hjo zZ{I>4t#hhZ)6&x)@ayZ1;v9WO*=X3I#vUiVYcOK_#-Fv7!7*}i{8K)ti2=!#|F#_1 Q`umA_dw|_pZV_4k0~{2JUjP6A diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 7863936769aad68485f34171246768d5362f01f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1786 zcmbVN`9B*77RRZ^$Dt?RdJWNvSp_v8tR(VwIy{eQsS(bEXK?*NFph*TcP8q z1d*xH*;03g-Tgskmd)ANCK}eV^}p@AE$Im-l_2cToI&uY*;gs!B>q zU{4GRtMH^RdPYTI+W@usN=kqio~Ua9B;~cLaMX6V{;;8rhzw(uQyaTAg=hlw5J!h~ zk+nuyMIqB@RJ!KRR5;WVwH%eM$<`z?d~h_=A*-l6tFR2sZ;qr6Cc^E*wdLh)=bDWg z!AF>1roee-BO$KluIq=xkk{bI+j2EADBY#?(PCrl-tFUiHQk` zkd~=cT)wx-O;ZTSc|;h26j?F(AGTj4D^h-be$mmsO#&~A+9bilIiJ863Kr& z=sTJwUC_r@98A_qEqPk;=--GPAM;9DBg$^UeAUczAvDTtL>-s1C_` zh(&?3;RX!C!!P74je7NZT+qO9#tI7yX++zi^M;0wSNmflGct7Ux(@lif_HH^z-{Lt zRd8KPi?&?}oepkRokB&Mb@6z~BM&NJB~=^i>uI=$k=pbQlg?fXB_!BmaCv!oclX=O zL;}l_p)9vNUkvHw|8UrdYpv@9aAOzK-t-R`)NPh zVy9dKv{mkPI`3MP3yAgXw)J6^N<-hqZg-f~+~Qq;sIB5plaVPYuOmczjcW|m381^n z6=M#yEj3+!<`}_c9UdN1>_b#8T9@}>*MsV*a`jZUs$d)=l2s>XpNf0nRo@#{c@dh* zmLKyoRBH3El^2m3XZ)$5YIFYvmEzmQKJX;VX|WhS=*bdKPn!<@nm@K&2f0jJbe1fqetd?;f-_;_GeB3DQH6=5UiRZnf!kezyrp}`(9JTOV$BZmO?-BMDd!9dIAA{K3gO zCh~PhN5^L7Ga3;(s8|H4^n7&w%Sn)ky=DaEUf5_hc*(M>@V=;ZHs7r*2dXZr_ypfH zJ3_wZ8mJc%+gC}MnGY%|B6*~`x|zh}WItcuTc33>`aRSe>A&>8FDfefM0$4%4gx%v zNO0(%pK!J46wNKBg1FHn5D3(bfCM(DjP#vLiHV6xO!UEN(-yY(6^$hBJgU-rpFqmV zxz`xC^z18*E3cW6`-_WcocX^lN7iHSBqgc;rR+}2-GLaQCc9vOaITrt&``!?zLLFE zi%r{WgG)+V3;b{WXrUGzZJ}c)d}9AZ>yO)uC+>*v`zx)he1!smR?QSUum9_glAd~> z00dGrJ8QI*O`aaXFR&fdmDqz)X*E@H{bTfVDvEeX*g_;?xwCce~C=gdZfI?7F_aPoC{Qz}nJCXCOnpo!kOAD)?`W{*rHiW2GzNnayIUR4S8Y zaK`ozk6&O`sDn}5zWI4$YVeFac3}2IS(_rq)T+dM4{C|Tie&CZI&S|v=E8G^3$Oj= T_i9%0)08~XzNlumh}{1GcOGxh diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 2ea76d6259c597d32c3fc6a3b0c93d42187721ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2305 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 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 16a1ae1616a355cceb9105d0cf6606ec003e5610..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1269 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 - - CADisableMinimumFrameDurationOnPhone - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Lightmeter - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - lightmeter - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UIApplicationSupportsIndirectInputEvents - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - NSCameraUsageDescription - Provide camera permissions in order to make measurements - - \ No newline at end of file + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + $(PRODUCT_NAME) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + lightmeter + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + NSCameraUsageDescription + Provide camera permissions in order to make measurements + + diff --git a/pubspec.yaml b/pubspec.yaml index 3cfdf6d..93635ef 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,8 +45,7 @@ dependencies: dev_dependencies: bloc_test: 9.1.3 build_runner: 2.4.6 - flutter_launcher_icons: 0.11.0 - flutter_native_splash: 2.2.16 + flutter_native_splash: 2.3.5 flutter_test: sdk: flutter google_fonts: 3.0.1 From 55b0e52d7f8cec83806e7fa6a03c8376bc65d9b3 Mon Sep 17 00:00:00 2001 From: ScaredCube <74418739+ScaredCube@users.noreply.github.com> Date: Fri, 1 Dec 2023 21:54:44 +0800 Subject: [PATCH 12/17] Fix Chinese Translation Errors (#140) --- lib/l10n/intl_zh.arb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 714c4b3..3844a76 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -98,11 +98,11 @@ }, "buyLightmeterPro": "购买 Lightmeter Pro", "lightmeterPro": "Lightmeter Pro", - "lightmeterProDescription": "解锁额外功能:\n \u2022 配置文件,其中包含光圈、快门速度等参数\n \u2022 胶片预设列表,用于在反转率发生故障时提供曝光补偿\n \u2022 点测光\n \u2022 直方图\n\n您可以在 GitHub 上获取 Lightmeter 的源代码,欢迎自行编译。不过,如果您想支持开发并获得新功能和更新,请考虑购买 Lightmeter Pro。", + "lightmeterProDescription": "解锁额外功能:\n \u2022 配置文件,其中包含光圈、快门速度等参数\n \u2022 胶卷列表,对胶片倒易率失效进行曝光补偿\n \u2022 点测光\n \u2022 直方图\n\n您可以在 GitHub 上获取 Lightmeter 的源代码,欢迎自行编译。不过,如果您想支持开发并获得新功能和更新,请考虑购买 Lightmeter Pro。", "buy": "购买", "proFeatures": "专业功能", "unlockProFeatures": "解锁专业功能", - "unlockProFeaturesDescription": "\n \u2022 配置文件,其中包含光圈、快门速度等参数\n \u2022 胶片预设列表,用于在反转率发生故障时提供曝光补偿\n \u2022 点测光\n \u2022 直方图\n\n通过解锁专业版功能,您可以支持开发工作,帮助为应用程序添加新功能。", + "unlockProFeaturesDescription": "\n \u2022 配置文件,其中包含光圈、快门速度等参数\n \u2022 胶卷列表,对胶片倒易率失效进行曝光补偿\n \u2022 点测光\n \u2022 直方图\n\n通过解锁专业版功能,您可以支持开发工作,帮助为应用程序添加新功能。", "unlock": "解锁", "tooltipAdd": "添加", "tooltipClose": "关闭", From 1b4be83dda0f08e1373b356cd378583674a0d6fb Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:52:56 +0100 Subject: [PATCH 13/17] Update PRIVACY_POLICY.md --- PRIVACY_POLICY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PRIVACY_POLICY.md b/PRIVACY_POLICY.md index 05710bd..d9b9cad 100644 --- a/PRIVACY_POLICY.md +++ b/PRIVACY_POLICY.md @@ -1,6 +1,6 @@ **Privacy Policy** -I, Vodemn, built the Material Lightmeter app as a Free app. This app is provided at no cost and is intended for use as is. +I, Vadim Turko, built the Material Lightmeter app as a Free app. This app is provided at no cost and is intended for use as is. **Information Collection and Use** @@ -20,7 +20,7 @@ This app contains links to other sites. If you click on a third-party link, you I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page. -This policy is effective as of 2023-02-24 +This policy is effective as of 2024-01-04 **Contact Us** From c80bac23b21569a8932d670b05072671baff4b72 Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Thu, 4 Jan 2024 18:39:44 +0100 Subject: [PATCH 14/17] Added Support section to README.md - Fixed Development section numeration - Added contact email link --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ef38b93..b5ef345 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - [Backstory](#backstory) - [Screenshots](#screenshots) - [Development](#development) -- [Contribution](#contribution) +- [Support](#support) - [iOS Limitations](#ios-limitations) # Backstory @@ -36,7 +36,7 @@ Without further delay behold my new Lightmeter app inspired by Material You (a.k To build this app you need to install Flutter 3.10.0 stable. [How to install](https://docs.flutter.dev/get-started/install). -### 3. Project setup +### 2. Project setup As part of the app's functionallity is in the private repo, you have to replace these lines in _pubspec.yaml_: @@ -69,11 +69,11 @@ flutter pub get flutter pub run intl_utils:generate ``` -### 4. (Optional) Install Firebase +### 3. (Optional) Install Firebase Out of the box Firebase Crashlytics won't work. If you want to add Crashlytics to your local build please follow [this guide](https://firebase.google.com/docs/flutter/setup). -### 5. Build +### 4. Build #### Android @@ -87,11 +87,11 @@ flutter build apk --release --flavor dev --dart-define cameraPreviewAspectRatio= TBD -# Contribution +# Support -To report a bug or suggest a new feature open a new [issue](https://github.com/vodemn/m3_lightmeter/issues). +To report a bug or suggest a new feature open a new [issue](https://github.com/vodemn/m3_lightmeter/issues). To contribute to the project feel free to open a Pull Request, but you need to follow this [style guide](doc/style_guide.md). -In case you want to help develop this project feel free to open a Pull Request, but you need to follow this [style guide](doc/style_guide.md). +In case you have any other questions please contact me via [email](mailto:contact.vodemn@gmail.com?subject="Lightmeter"). # iOS Limitations From a2b4c88256552311917bd7dded1c66db58e7123e Mon Sep 17 00:00:00 2001 From: nathan musoke Date: Sat, 13 Jan 2024 10:42:23 -0600 Subject: [PATCH 15/17] Fixed typo in reciprocity description (#142) grater -> greater Co-authored-by: Vadim <44135514+vodemn@users.noreply.github.com> --- lib/l10n/intl_en.arb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 02bb95a..8c5bf93 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -47,7 +47,7 @@ "film": "Film", "filmPush": "Film (push)", "filmPull": "Film (pull)", - "filmReciprocityHint": "Applies correction for shutter speeds grater than 1 second", + "filmReciprocityHint": "Applies correction for shutter speeds greater than 1 second", "equipmentProfileName": "Equipment profile name", "equipmentProfileNameHint": "Praktica MTL5B", "equipmentProfileAllValues": "All", @@ -116,4 +116,4 @@ "tooltipUseLightSensor": "Use lightsensor", "tooltipUseCamera": "Use camera", "tooltipOpenSettings": "Open settings" -} \ No newline at end of file +} From 73d0c323234a4c8268177655a80621cd7c9f4e65 Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Sat, 13 Jan 2024 18:20:58 +0100 Subject: [PATCH 16/17] Hide Pro features from the metering screen (#147) * implemented `MockCameraContainerBloc` to stub camera on simulator * hide pro features from metering screen * disable pro features in settings * use closed child background color in `AnimatedDialog` * adjust `AnimatedDialogPicker` to items count * close `AnimatedDialog` through context * cleanup * fixed `ReadingValueContainer` text color * removed legacy translations * fixed tests * fixed `AnimatedDialog` scaling * added `evFromImage` test * added no EXIF test to `evFromImage` --- .vscode/launch.json | 15 +++ lib/application.dart | 5 +- lib/l10n/intl_en.arb | 4 - lib/l10n/intl_fr.arb | 4 - lib/l10n/intl_ru.arb | 4 - lib/l10n/intl_zh.arb | 4 - lib/platform_config.dart | 2 + .../bloc_container_camera.dart | 39 ++---- .../mock_bloc_container_camera.dart | 80 ++++++++++++ .../provider_container_camera.dart | 17 ++- .../widget_container_camera.dart | 30 +++-- .../lightmeter_pro/widget_lightmeter_pro.dart | 27 ++++ .../widget_dialog_animated.dart | 43 ++++--- .../dialog_picker/widget_picker_dialog.dart | 117 +++++++----------- .../widget_picker_dialog_animated.dart | 36 +++--- .../widget_container_reading_value.dart | 27 ++-- .../widget_container_readings.dart | 24 ++-- .../buy_pro/widget_list_tile_buy_pro.dart | 16 +-- ...idget_settings_section_lightmeter_pro.dart | 6 +- ...dget_list_tile_metering_screen_layout.dart | 10 ++ .../dialog_switch/widget_dialog_switch.dart | 19 ++- .../shared/disable/widget_disable.dart | 24 ++++ .../iap_list_tile/widget_list_tile_iap.dart | 8 +- .../widget_list_tile_primary_color.dart | 13 +- .../settings/utils/show_buy_pro_dialog.dart | 59 --------- .../widget_dialog_pro_features.dart | 56 +++++++++ .../widget_dialog_transparent.dart | 104 ++++++++++++++++ lib/utils/context_utils.dart | 12 ++ lib/utils/ev_from_bytes.dart | 27 ++++ lib/utils/text_height.dart | 29 +++++ test/application_mock.dart | 8 +- ..._settings_section_lightmeter_pro_test.dart | 60 +++++++++ .../utils/show_buy_pro_dialog_test.dart | 61 --------- test/utils/ev_from_bytes_test.dart | 24 ++++ 34 files changed, 665 insertions(+), 349 deletions(-) create mode 100644 lib/screens/metering/components/camera_container/mock_bloc_container_camera.dart create mode 100644 lib/screens/metering/components/shared/readings_container/components/lightmeter_pro/widget_lightmeter_pro.dart create mode 100644 lib/screens/settings/components/shared/disable/widget_disable.dart delete mode 100644 lib/screens/settings/utils/show_buy_pro_dialog.dart create mode 100644 lib/screens/shared/pro_features_dialog/widget_dialog_pro_features.dart create mode 100644 lib/screens/shared/transparent_dialog/widget_dialog_transparent.dart create mode 100644 lib/utils/context_utils.dart create mode 100644 lib/utils/ev_from_bytes.dart create mode 100644 lib/utils/text_height.dart create mode 100644 test/screens/settings/components/widget_settings_section_lightmeter_pro_test.dart delete mode 100644 test/screens/settings/utils/show_buy_pro_dialog_test.dart create mode 100644 test/utils/ev_from_bytes_test.dart diff --git a/.vscode/launch.json b/.vscode/launch.json index 40dbfac..a222516 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -82,5 +82,20 @@ ], "program": "${workspaceFolder}/lib/main_dev.dart", }, + { + "name": "dev-simulator", + "request": "launch", + "type": "dart", + "flutterMode": "debug", + "args": [ + "--flavor", + "dev", + "--dart-define", + "cameraPreviewAspectRatio=240/320", + "--dart-define", + "cameraStubImage=assets/camera_stub_image.jpg" + ], + "program": "${workspaceFolder}/lib/main_dev.dart", + }, ], } \ No newline at end of file diff --git a/lib/application.dart b/lib/application.dart index 68dd44a..15eba3a 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:lightmeter/data/models/supported_locale.dart'; import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/platform_config.dart'; import 'package:lightmeter/providers/user_preferences_provider.dart'; import 'package:lightmeter/screens/metering/flow_metering.dart'; import 'package:lightmeter/screens/settings/flow_settings.dart'; @@ -17,13 +18,13 @@ class Application extends StatelessWidget { return AnnotatedRegion( value: SystemUiOverlayStyle( statusBarColor: Colors.transparent, - statusBarBrightness: - systemIconsBrightness == Brightness.light ? Brightness.dark : Brightness.light, + statusBarBrightness: systemIconsBrightness == Brightness.light ? Brightness.dark : Brightness.light, statusBarIconBrightness: systemIconsBrightness, systemNavigationBarColor: Colors.transparent, systemNavigationBarIconBrightness: systemIconsBrightness, ), child: MaterialApp( + debugShowCheckedModeBanner: !PlatformConfig.isTest, theme: theme, locale: Locale(UserPreferencesProvider.localeOf(context).intlName), localizationsDelegates: const [ diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 8c5bf93..13d5cbd 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -96,10 +96,6 @@ } } }, - "lightmeterPro": "Lightmeter Pro", - "buyLightmeterPro": "Buy Lightmeter Pro", - "lightmeterProDescription": "Unlocks extra features:\n \u2022 Equipment profiles containing filters for aperture, shutter speed, and more\n \u2022 List of films with compensation for what's known as reciprocity failure\n \u2022 Spot metering\n \u2022 Histogram\n\nThe source code of Lightmeter is available on GitHub. You are welcome to compile it yourself. However, if you want to support the development and receive new features and updates, consider purchasing Lightmeter Pro.", - "buy": "Buy", "proFeatures": "Pro features", "unlockProFeatures": "Unlock Pro features", "unlockProFeaturesDescription": "Unlock professional features:\n \u2022 Equipment profiles containing filters for aperture, shutter speed, and more\n \u2022 List of films with compensation for what's known as reciprocity failure\n \u2022 Spot metering\n \u2022 Histogram\n\nBy unlocking Pro features you support the development and make it possible to add new features to the app.", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index f8b52c3..66dc9fb 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -96,10 +96,6 @@ } } }, - "buyLightmeterPro": "Acheter Lightmeter Pro", - "lightmeterPro": "Lightmeter Pro", - "lightmeterProDescription": "Débloque des fonctionnalités supplémentaires:\n \u2022 Profils d'équipement contenant des filtres pour l'ouverture, la vitesse d'obturation et plus encore\n \u2022 Liste de films avec une compensation pour ce que l'on appelle l'échec de réciprocité\n \u2022 Mesure spot\n \u2022 Histogramme\n\nLe code source du Lightmeter est disponible sur GitHub. Vous pouvez le compiler vous-même. Cependant, si vous souhaitez soutenir le développement et recevoir de nouvelles fonctionnalités et mises à jour, envisagez d'acheter Lightmeter Pro.", - "buy": "Acheter", "proFeatures": "Fonctionnalités professionnelles", "unlockProFeatures": "Déverrouiller les fonctionnalités professionnelles", "unlockProFeaturesDescription": "Déverrouillez des fonctions professionnelles:\n \u2022 Profils d'équipement contenant des filtres pour l'ouverture, la vitesse d'obturation et plus encore, ainsi qu'une liste de films avec compensation pour ce que l'on appelle l'échec de réciprocité\n \u2022 Mesure spot\n \u2022 Histogramme\n\nEn débloquant les fonctionnalités Pro, vous soutenez le développement et permettez d'ajouter de nouvelles fonctionnalités à l'application.", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index f25dc8e..367b707 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -96,10 +96,6 @@ } } }, - "buyLightmeterPro": "Купить Lightmeter Pro", - "lightmeterPro": "Lightmeter Pro", - "lightmeterProDescription": "Даёт доступ к различным функциям:\n \u2022 Профили оборудования, содержащие фильтры для диафрагмы, выдержки и других значений\n \u2022 Список пленок с компенсацией эффекта Шварцшильда\n \u2022 Точечный замер\n \u2022 Гистограмма\n\nИсходный код Lightmeter доступен на GitHub. Вы можете собрать его самостоятельно. Однако если вы хотите поддержать разработку и получать новые функции и обновления, то приобретите Lightmeter Pro.", - "buy": "Купить", "proFeatures": "Профессиональные настройки", "unlockProFeatures": "Разблокировать профессиональные настройки", "unlockProFeaturesDescription": "Вы можете разблокировать профессиональные настройки:\n \u2022 Профили оборудования, содержащие фильтры для диафрагмы, выдержки и других значений\n \u2022 Список пленок с компенсацией эффекта Шварцшильда\n \u2022 Точечный замер\n \u2022 Гистограмма\n\nПолучая доступ к профессиональным настройкам, вы поддерживаете разработку и делаете возможным появление новых функций в приложении.", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 3844a76..0055685 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -96,10 +96,6 @@ } } }, - "buyLightmeterPro": "购买 Lightmeter Pro", - "lightmeterPro": "Lightmeter Pro", - "lightmeterProDescription": "解锁额外功能:\n \u2022 配置文件,其中包含光圈、快门速度等参数\n \u2022 胶卷列表,对胶片倒易率失效进行曝光补偿\n \u2022 点测光\n \u2022 直方图\n\n您可以在 GitHub 上获取 Lightmeter 的源代码,欢迎自行编译。不过,如果您想支持开发并获得新功能和更新,请考虑购买 Lightmeter Pro。", - "buy": "购买", "proFeatures": "专业功能", "unlockProFeatures": "解锁专业功能", "unlockProFeaturesDescription": "\n \u2022 配置文件,其中包含光圈、快门速度等参数\n \u2022 胶卷列表,对胶片倒易率失效进行曝光补偿\n \u2022 点测光\n \u2022 直方图\n\n通过解锁专业版功能,您可以支持开发工作,帮助为应用程序添加新功能。", diff --git a/lib/platform_config.dart b/lib/platform_config.dart index def5a80..d06223e 100644 --- a/lib/platform_config.dart +++ b/lib/platform_config.dart @@ -7,4 +7,6 @@ class PlatformConfig { } static String get cameraStubImage => const String.fromEnvironment('cameraStubImage'); + + static bool get isTest => cameraStubImage.isNotEmpty; } diff --git a/lib/screens/metering/components/camera_container/bloc_container_camera.dart b/lib/screens/metering/components/camera_container/bloc_container_camera.dart index 2e6b051..3b5596b 100644 --- a/lib/screens/metering/components/camera_container/bloc_container_camera.dart +++ b/lib/screens/metering/components/camera_container/bloc_container_camera.dart @@ -4,7 +4,6 @@ import 'dart:io'; import 'dart:math' as math; import 'package:camera/camera.dart'; -import 'package:exif/exif.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -17,7 +16,9 @@ import 'package:lightmeter/screens/metering/components/camera_container/event_co import 'package:lightmeter/screens/metering/components/camera_container/models/camera_error_type.dart'; import 'package:lightmeter/screens/metering/components/camera_container/state_container_camera.dart'; import 'package:lightmeter/screens/metering/components/shared/ev_source_base/bloc_base_ev_source.dart'; -import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; +import 'package:lightmeter/utils/ev_from_bytes.dart'; + +part 'mock_bloc_container_camera.dart'; class CameraContainerBloc extends EvSourceBlocBase { final MeteringInteractor _meteringInteractor; @@ -213,33 +214,15 @@ class CameraContainerBloc extends EvSourceBlocBase _takePhoto() async { try { // https://github.com/flutter/flutter/issues/84957#issuecomment-1661155095 + await _cameraController!.setFocusMode(FocusMode.locked); + await _cameraController!.setExposureMode(ExposureMode.locked); + final file = await _cameraController!.takePicture(); + await _cameraController!.setFocusMode(FocusMode.auto); + await _cameraController!.setExposureMode(ExposureMode.auto); + final bytes = await file.readAsBytes(); + Directory(file.path).deleteSync(recursive: true); - late final Uint8List bytes; - if (PlatformConfig.cameraStubImage.isNotEmpty) { - bytes = (await rootBundle.load(PlatformConfig.cameraStubImage)).buffer.asUint8List(); - } else { - await _cameraController!.setFocusMode(FocusMode.locked); - await _cameraController!.setExposureMode(ExposureMode.locked); - final file = await _cameraController!.takePicture(); - await _cameraController!.setFocusMode(FocusMode.auto); - await _cameraController!.setExposureMode(ExposureMode.auto); - bytes = await file.readAsBytes(); - Directory(file.path).deleteSync(recursive: true); - } - - final tags = await readExifFromBytes(bytes); - final iso = double.tryParse("${tags["EXIF ISOSpeedRatings"]}"); - final apertureValueRatio = (tags["EXIF FNumber"]?.values as IfdRatios?)?.ratios.first; - final speedValueRatio = (tags["EXIF ExposureTime"]?.values as IfdRatios?)?.ratios.first; - if (iso == null || apertureValueRatio == null || speedValueRatio == null) { - log('Error parsing EXIF: ${tags.keys}'); - return null; - } - - final aperture = apertureValueRatio.numerator / apertureValueRatio.denominator; - final speed = speedValueRatio.numerator / speedValueRatio.denominator; - - return log2(math.pow(aperture, 2)) - log2(speed) - log2(iso / 100); + return await evFromImage(bytes); } catch (e) { log(e.toString()); return null; diff --git a/lib/screens/metering/components/camera_container/mock_bloc_container_camera.dart b/lib/screens/metering/components/camera_container/mock_bloc_container_camera.dart new file mode 100644 index 0000000..f915a52 --- /dev/null +++ b/lib/screens/metering/components/camera_container/mock_bloc_container_camera.dart @@ -0,0 +1,80 @@ +part of 'bloc_container_camera.dart'; + +class MockCameraContainerBloc extends CameraContainerBloc { + MockCameraContainerBloc( + super._meteringInteractor, + super.communicationBloc, + ); + + @override + Future _onRequestPermission(_, Emitter emit) async { + add(const InitializeEvent()); + } + + @override + Future _onOpenAppSettings(_, Emitter emit) async { + _meteringInteractor.openAppSettings(); + } + + @override + Future _onInitialize(_, Emitter emit) async { + emit(const CameraLoadingState()); + try { + _cameraController = CameraController( + const CameraDescription(name: '0', lensDirection: CameraLensDirection.back, sensorOrientation: 0), + ResolutionPreset.low, + enableAudio: false, + ); + + _zoomRange = const RangeValues(1, 6); + _currentZoom = _zoomRange!.start; + + _exposureOffsetRange = const RangeValues(-4, 4); + _exposureStep = 0.1; + _currentExposureOffset = 0.0; + + emit(CameraInitializedState(_cameraController!)); + + _emitActiveState(emit); + } catch (e) { + emit(const CameraErrorState(CameraErrorType.other)); + } + } + + @override + Future _onZoomChanged(ZoomChangedEvent event, Emitter emit) async { + if (event.value >= _zoomRange!.start && event.value <= _zoomRange!.end) { + _currentZoom = event.value; + _emitActiveState(emit); + } + } + + @override + Future _onExposureOffsetChanged(ExposureOffsetChangedEvent event, Emitter emit) async { + _currentExposureOffset = event.value; + _emitActiveState(emit); + } + + @override + Future _onExposureOffsetResetEvent(ExposureOffsetResetEvent event, Emitter emit) async { + _meteringInteractor.quickVibration(); + add(const ExposureOffsetChangedEvent(0)); + } + + @override + Future _onExposureSpotChangedEvent(ExposureSpotChangedEvent event, Emitter emit) async {} + + @override + bool get _canTakePhoto => PlatformConfig.cameraStubImage.isNotEmpty; + + @override + Future _takePhoto() async { + try { + final bytes = (await rootBundle.load(PlatformConfig.cameraStubImage)).buffer.asUint8List(); + return await evFromImage(bytes); + } catch (e) { + log(e.toString()); + return null; + } + } +} diff --git a/lib/screens/metering/components/camera_container/provider_container_camera.dart b/lib/screens/metering/components/camera_container/provider_container_camera.dart index 1d6d8c0..80be814 100644 --- a/lib/screens/metering/components/camera_container/provider_container_camera.dart +++ b/lib/screens/metering/components/camera_container/provider_container_camera.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lightmeter/data/models/exposure_pair.dart'; +import 'package:lightmeter/platform_config.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; import 'package:lightmeter/screens/metering/components/camera_container/bloc_container_camera.dart'; import 'package:lightmeter/screens/metering/components/camera_container/event_container_camera.dart'; @@ -30,12 +31,18 @@ class CameraContainerProvider extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocProvider( + return BlocProvider( lazy: false, - create: (context) => CameraContainerBloc( - MeteringInteractorProvider.of(context), - context.read(), - )..add(const RequestPermissionEvent()), + create: (context) => (PlatformConfig.cameraStubImage.isNotEmpty + ? MockCameraContainerBloc( + MeteringInteractorProvider.of(context), + context.read(), + ) + : CameraContainerBloc( + MeteringInteractorProvider.of(context), + context.read(), + )) + ..add(const RequestPermissionEvent()), child: CameraContainer( fastest: fastest, slowest: slowest, diff --git a/lib/screens/metering/components/camera_container/widget_container_camera.dart b/lib/screens/metering/components/camera_container/widget_container_camera.dart index a23545e..a4cb3e8 100644 --- a/lib/screens/metering/components/camera_container/widget_container_camera.dart +++ b/lib/screens/metering/components/camera_container/widget_container_camera.dart @@ -5,7 +5,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lightmeter/data/models/exposure_pair.dart'; import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; import 'package:lightmeter/platform_config.dart'; -import 'package:lightmeter/providers/user_preferences_provider.dart'; import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/screens/metering/components/camera_container/bloc_container_camera.dart'; import 'package:lightmeter/screens/metering/components/camera_container/components/camera_controls/widget_camera_controls.dart'; @@ -17,6 +16,8 @@ import 'package:lightmeter/screens/metering/components/camera_container/state_co import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_list/widget_list_exposure_pairs.dart'; import 'package:lightmeter/screens/metering/components/shared/metering_top_bar/widget_top_bar_metering.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/widget_container_readings.dart'; +import 'package:lightmeter/utils/context_utils.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class CameraContainer extends StatelessWidget { @@ -101,28 +102,25 @@ class CameraContainer extends StatelessWidget { } double _meteringContainerHeight(BuildContext context) { + final isPro = IAPProducts.isPurchased(context, IAPProductType.paidFeatures); double enabledFeaturesHeight = 0; - if (UserPreferencesProvider.meteringScreenFeatureOf( - context, - MeteringScreenLayoutFeature.equipmentProfiles, - )) { + if (!isPro) { enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight; enabledFeaturesHeight += Dimens.paddingS; + } else { + if (context.meteringFeature(MeteringScreenLayoutFeature.equipmentProfiles)) { + enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight; + enabledFeaturesHeight += Dimens.paddingS; + } + if (context.meteringFeature(MeteringScreenLayoutFeature.filmPicker)) { + enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight; + enabledFeaturesHeight += Dimens.paddingS; + } } - if (UserPreferencesProvider.meteringScreenFeatureOf( - context, - MeteringScreenLayoutFeature.extremeExposurePairs, - )) { + if (context.meteringFeature(MeteringScreenLayoutFeature.extremeExposurePairs)) { enabledFeaturesHeight += Dimens.readingContainerDoubleValueHeight; enabledFeaturesHeight += Dimens.paddingS; } - if (UserPreferencesProvider.meteringScreenFeatureOf( - context, - MeteringScreenLayoutFeature.filmPicker, - )) { - enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight; - enabledFeaturesHeight += Dimens.paddingS; - } return enabledFeaturesHeight + Dimens.readingContainerSingleValueHeight; // ISO & ND } diff --git a/lib/screens/metering/components/shared/readings_container/components/lightmeter_pro/widget_lightmeter_pro.dart b/lib/screens/metering/components/shared/readings_container/components/lightmeter_pro/widget_lightmeter_pro.dart new file mode 100644 index 0000000..9d5218a --- /dev/null +++ b/lib/screens/metering/components/shared/readings_container/components/lightmeter_pro/widget_lightmeter_pro.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart'; +import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart'; +import 'package:lightmeter/screens/shared/pro_features_dialog/widget_dialog_pro_features.dart'; + +class LightmeterProAnimatedDialog extends StatelessWidget { + const LightmeterProAnimatedDialog({super.key}); + + @override + Widget build(BuildContext context) { + return AnimatedDialog( + closedChild: ReadingValueContainer( + color: Theme.of(context).colorScheme.errorContainer, + textColor: Theme.of(context).colorScheme.onErrorContainer, + values: [ + ReadingValue( + label: S.of(context).proFeatures, + value: S.of(context).unlock, + ), + ], + ), + openedChild: const ProFeaturesDialog(), + openedSize: Size.fromHeight(const ProFeaturesDialog().height(context)), + ); + } +} diff --git a/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart b/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart index 72e770b..63bd1e6 100644 --- a/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart +++ b/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart @@ -1,9 +1,15 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:lightmeter/res/dimens.dart'; +mixin AnimatedDialogClosedChild on Widget { + Color backgroundColor(BuildContext context); +} + class AnimatedDialog extends StatefulWidget { final Size? openedSize; - final Widget? closedChild; + final AnimatedDialogClosedChild? closedChild; final Widget? openedChild; final Widget? child; @@ -15,6 +21,9 @@ class AnimatedDialog extends StatefulWidget { super.key, }); + static Future? maybeClose(BuildContext context) => + context.findAncestorWidgetOfExactType<_AnimatedOverlay>()?.onDismiss(); + @override State createState() => AnimatedDialogState(); } @@ -95,7 +104,7 @@ class AnimatedDialogState extends State with SingleTickerProvide void didChangeDependencies() { super.didChangeDependencies(); _foregroundColorAnimation = ColorTween( - begin: Theme.of(context).colorScheme.primaryContainer, + begin: widget.closedChild?.backgroundColor(context) ?? Theme.of(context).colorScheme.primaryContainer, end: Theme.of(context).colorScheme.surface, ).animate(_defaultCurvedAnimation); @@ -135,14 +144,15 @@ class AnimatedDialogState extends State with SingleTickerProvide if (renderBox != null) { final size = MediaQuery.sizeOf(context); final padding = MediaQuery.paddingOf(context); + final maxWidth = size.width - padding.horizontal - Dimens.dialogMargin.horizontal; + final maxHeight = size.height - padding.vertical - Dimens.dialogMargin.vertical; _closedSize = _key.currentContext!.size!; _sizeTween = SizeTween( begin: _closedSize, - end: widget.openedSize ?? - Size( - size.width - padding.horizontal - Dimens.dialogMargin.horizontal, - size.height - padding.vertical - Dimens.dialogMargin.vertical, - ), + end: Size( + min(widget.openedSize?.width ?? double.maxFinite, maxWidth), + min(widget.openedSize?.height ?? double.maxFinite, maxHeight), + ), ); _sizeAnimation = _sizeTween.animate(_defaultCurvedAnimation); @@ -181,7 +191,6 @@ class AnimatedDialogState extends State with SingleTickerProvide onDismiss: close, builder: widget.closedChild != null && widget.openedChild != null ? (_) => _AnimatedSwitcher( - sizeAnimation: _sizeAnimation, closedOpacityAnimation: _closedOpacityAnimation, openedOpacityAnimation: _openedOpacityAnimation, closedSize: _sizeTween.begin!, @@ -223,7 +232,7 @@ class _AnimatedOverlay extends StatelessWidget { final Animation borderRadiusAnimation; final Animation foregroundColorAnimation; final Animation elevationAnimation; - final VoidCallback onDismiss; + final Future Function() onDismiss; final Widget? child; final Widget Function(BuildContext context)? builder; @@ -281,7 +290,6 @@ class _AnimatedOverlay extends StatelessWidget { } class _AnimatedSwitcher extends StatelessWidget { - final Animation sizeAnimation; final Animation closedOpacityAnimation; final Animation openedOpacityAnimation; final Size closedSize; @@ -290,7 +298,6 @@ class _AnimatedSwitcher extends StatelessWidget { final Widget openedChild; const _AnimatedSwitcher({ - required this.sizeAnimation, required this.closedOpacityAnimation, required this.openedOpacityAnimation, required this.closedSize, @@ -306,17 +313,21 @@ class _AnimatedSwitcher extends StatelessWidget { children: [ Opacity( opacity: closedOpacityAnimation.value, - child: Transform.scale( - scale: sizeAnimation.value!.width / closedSize.width, - child: SizedBox( - width: closedSize.width, + child: FittedBox( + child: SizedBox.fromSize( + size: closedSize, child: closedChild, ), ), ), Opacity( opacity: openedOpacityAnimation.value, - child: openedChild, + child: FittedBox( + child: SizedBox.fromSize( + size: openedSize, + child: openedChild, + ), + ), ), ], ); diff --git a/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/dialog_picker/widget_picker_dialog.dart b/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/dialog_picker/widget_picker_dialog.dart index 3c253b1..dfbf1ce 100644 --- a/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/dialog_picker/widget_picker_dialog.dart +++ b/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/dialog_picker/widget_picker_dialog.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/shared/transparent_dialog/widget_dialog_transparent.dart'; typedef DialogPickerItemTitleBuilder = Widget Function(BuildContext context, T value); typedef DialogPickerItemTrailingBuilder = Widget? Function(T selected, T value); @@ -29,6 +30,14 @@ class DialogPicker extends StatefulWidget { super.key, }); + double height(BuildContext context) => TransparentDialog.height( + context, + title: title, + subtitle: subtitle, + scrollableContent: true, + contextHeight: Dimens.grid56 * values.length, + ); + @override State> createState() => _DialogPickerState(); } @@ -46,83 +55,43 @@ class _DialogPickerState extends State> { @override Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Padding( - padding: Dimens.dialogTitlePadding, - child: Icon(widget.icon), - ), - Padding( - padding: Dimens.dialogIconTitlePadding, - child: Text( - widget.title, - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), - ), - if (widget.subtitle != null) - Padding( - padding: const EdgeInsets.fromLTRB( - Dimens.paddingL, - 0, - Dimens.paddingL, - Dimens.paddingM, - ), - child: Text( - widget.subtitle!, - style: Theme.of(context).textTheme.bodyMedium, - textAlign: TextAlign.center, - ), - ), - ], - ), - const Divider(), - Expanded( - child: ListView.builder( - controller: _scrollController, - padding: EdgeInsets.zero, - itemCount: widget.values.length, - itemExtent: Dimens.grid56, - itemBuilder: (context, index) => RadioListTile( - value: widget.values[index], - groupValue: _selectedValue, - title: DefaultTextStyle( - style: Theme.of(context).textTheme.bodyLarge!, - child: widget.itemTitleBuilder(context, widget.values[index]), - ), - secondary: widget.itemTrailingBuilder?.call(_selectedValue, widget.values[index]), - onChanged: (value) { - if (value != null) { - setState(() { - _selectedValue = value; - }); - } - }, + return TransparentDialog( + icon: widget.icon, + title: widget.title, + subtitle: widget.subtitle, + content: Expanded( + child: ListView.builder( + controller: _scrollController, + padding: EdgeInsets.zero, + itemCount: widget.values.length, + itemExtent: Dimens.grid56, + itemBuilder: (context, index) => RadioListTile( + value: widget.values[index], + groupValue: _selectedValue, + title: DefaultTextStyle( + style: Theme.of(context).textTheme.bodyLarge!, + child: widget.itemTitleBuilder(context, widget.values[index]), ), + secondary: widget.itemTrailingBuilder?.call(_selectedValue, widget.values[index]), + onChanged: (value) { + if (value != null) { + setState(() { + _selectedValue = value; + }); + } + }, ), ), - const Divider(), - Padding( - padding: Dimens.dialogActionsPadding, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - const Spacer(), - TextButton( - onPressed: widget.onCancel, - child: Text(S.of(context).cancel), - ), - const SizedBox(width: Dimens.grid16), - TextButton( - onPressed: () => widget.onSelect(_selectedValue), - child: Text(S.of(context).select), - ), - ], - ), + ), + scrollableContent: true, + actions: [ + TextButton( + onPressed: widget.onCancel, + child: Text(S.of(context).cancel), + ), + TextButton( + onPressed: () => widget.onSelect(_selectedValue), + child: Text(S.of(context).select), ), ], ); diff --git a/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart b/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart index eeeec52..efa07c7 100644 --- a/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart +++ b/lib/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/dialog_picker/widget_picker_dialog.dart'; -// Has to be stateful, so that [GlobalKey] is not recreated. +// Has to be stateful, so that [GlobalKey] is not recreated. // Otherwise use will no be able to close the dialog after EV value has changed. class AnimatedDialogPicker extends StatefulWidget { final IconData icon; @@ -13,7 +13,7 @@ class AnimatedDialogPicker extends StatefulWidget { final DialogPickerItemTitleBuilder itemTitleBuilder; final DialogPickerItemTrailingBuilder? itemTrailingBuilder; final ValueChanged onChanged; - final Widget closedChild; + final AnimatedDialogClosedChild closedChild; const AnimatedDialogPicker({ required this.icon, @@ -37,24 +37,26 @@ class _AnimatedDialogPickerState extends State> { @override Widget build(BuildContext context) { + final dialogPicker = DialogPicker( + icon: widget.icon, + title: widget.title, + subtitle: widget.subtitle, + initialValue: widget.selectedValue, + values: widget.values, + itemTitleBuilder: widget.itemTitleBuilder, + itemTrailingBuilder: widget.itemTrailingBuilder, + onCancel: () { + _key.currentState?.close(); + }, + onSelect: (value) { + _key.currentState?.close().then((_) => widget.onChanged(value)); + }, + ); return AnimatedDialog( key: _key, closedChild: widget.closedChild, - openedChild: DialogPicker( - icon: widget.icon, - title: widget.title, - subtitle: widget.subtitle, - initialValue: widget.selectedValue, - values: widget.values, - itemTitleBuilder: widget.itemTitleBuilder, - itemTrailingBuilder: widget.itemTrailingBuilder, - onCancel: () { - _key.currentState?.close(); - }, - onSelect: (value) { - _key.currentState?.close().then((_) => widget.onChanged(value)); - }, - ), + openedChild: dialogPicker, + openedSize: Size.fromHeight(dialogPicker.height(context)), ); } } diff --git a/lib/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart b/lib/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart index 3254456..6968db6 100644 --- a/lib/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart +++ b/lib/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart'; class ReadingValue { final String label; @@ -11,11 +12,15 @@ class ReadingValue { }); } -class ReadingValueContainer extends StatelessWidget { +class ReadingValueContainer extends StatelessWidget implements AnimatedDialogClosedChild { late final List _items; + final Color? color; + final Color? textColor; ReadingValueContainer({ required List values, + this.color, + this.textColor, super.key, }) { _items = []; @@ -23,21 +28,26 @@ class ReadingValueContainer extends StatelessWidget { if (i > 0) { _items.add(const SizedBox(height: Dimens.grid8)); } - _items.add(_ReadingValueBuilder(values[i])); + _items.add(_ReadingValueBuilder(values[i], textColor: textColor)); } } ReadingValueContainer.singleValue({ required ReadingValue value, + this.color, + this.textColor, super.key, - }) : _items = [_ReadingValueBuilder(value)]; + }) : _items = [_ReadingValueBuilder(value, textColor: textColor)]; + + @override + Color backgroundColor(BuildContext context) => color ?? Theme.of(context).colorScheme.primaryContainer; @override Widget build(BuildContext context) { return ClipRRect( borderRadius: BorderRadius.circular(Dimens.borderRadiusM), child: ColoredBox( - color: Theme.of(context).colorScheme.primaryContainer, + color: backgroundColor(context), child: Padding( padding: const EdgeInsets.all(Dimens.paddingM), child: Column( @@ -53,20 +63,21 @@ class ReadingValueContainer extends StatelessWidget { class _ReadingValueBuilder extends StatelessWidget { final ReadingValue reading; + final Color? textColor; - const _ReadingValueBuilder(this.reading); + const _ReadingValueBuilder(this.reading, {this.textColor}); @override Widget build(BuildContext context) { final textTheme = Theme.of(context).textTheme; - final textColor = Theme.of(context).colorScheme.onPrimaryContainer; + final color = textColor ?? Theme.of(context).colorScheme.onPrimaryContainer; return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( reading.label, - style: textTheme.labelMedium?.copyWith(color: textColor), + style: textTheme.labelMedium?.copyWith(color: color), maxLines: 1, overflow: TextOverflow.visible, softWrap: false, @@ -76,7 +87,7 @@ class _ReadingValueBuilder extends StatelessWidget { duration: Dimens.switchDuration, child: Text( reading.value, - style: textTheme.titleMedium?.copyWith(color: textColor), + style: textTheme.titleMedium?.copyWith(color: color), maxLines: 1, overflow: TextOverflow.ellipsis, softWrap: false, diff --git a/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart b/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart index cb8af05..30d1392 100644 --- a/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart +++ b/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart @@ -2,13 +2,15 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/data/models/exposure_pair.dart'; import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; import 'package:lightmeter/providers/equipment_profile_provider.dart'; -import 'package:lightmeter/providers/user_preferences_provider.dart'; import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/equipment_profile_picker/widget_picker_equipment_profiles.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/extreme_exposure_pairs_container/widget_container_extreme_exposure_pairs.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/film_picker/widget_picker_film.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/iso_picker/widget_picker_iso.dart'; +import 'package:lightmeter/screens/metering/components/shared/readings_container/components/lightmeter_pro/widget_lightmeter_pro.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/nd_picker/widget_picker_nd.dart'; +import 'package:lightmeter/utils/context_utils.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class ReadingsContainer extends StatelessWidget { @@ -31,30 +33,26 @@ class ReadingsContainer extends StatelessWidget { @override Widget build(BuildContext context) { + final isPro = IAPProducts.isPurchased(context, IAPProductType.paidFeatures); return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - if (UserPreferencesProvider.meteringScreenFeatureOf( - context, - MeteringScreenLayoutFeature.equipmentProfiles, - )) ...[ + if (!isPro) ...[ + const LightmeterProAnimatedDialog(), + const _InnerPadding(), + ], + if (isPro && context.meteringFeature(MeteringScreenLayoutFeature.equipmentProfiles)) ...[ const EquipmentProfilePicker(), const _InnerPadding(), ], - if (UserPreferencesProvider.meteringScreenFeatureOf( - context, - MeteringScreenLayoutFeature.extremeExposurePairs, - )) ...[ + if (context.meteringFeature(MeteringScreenLayoutFeature.extremeExposurePairs)) ...[ ExtremeExposurePairsContainer( fastest: fastest, slowest: slowest, ), const _InnerPadding(), ], - if (UserPreferencesProvider.meteringScreenFeatureOf( - context, - MeteringScreenLayoutFeature.filmPicker, - )) ...[ + if (isPro && context.meteringFeature(MeteringScreenLayoutFeature.filmPicker)) ...[ FilmPicker(selectedIso: iso), const _InnerPadding(), ], diff --git a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart index 9854a14..4bb401d 100644 --- a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart +++ b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart @@ -1,10 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:lightmeter/data/models/feature.dart'; import 'package:lightmeter/generated/l10n.dart'; -import 'package:lightmeter/providers/remote_config_provider.dart'; -import 'package:lightmeter/providers/services_provider.dart'; import 'package:lightmeter/res/dimens.dart'; -import 'package:lightmeter/screens/settings/utils/show_buy_pro_dialog.dart'; +import 'package:lightmeter/screens/shared/pro_features_dialog/widget_dialog_pro_features.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; class BuyProListTile extends StatelessWidget { @@ -12,18 +9,17 @@ class BuyProListTile extends StatelessWidget { @override Widget build(BuildContext context) { - final unlockFeaturesEnabled = RemoteConfig.isEnabled(context, Feature.unlockProFeaturesText); final status = IAPProducts.productOf(context, IAPProductType.paidFeatures)?.status; final isPending = status == IAPProductStatus.purchased || status == null; return ListTile( leading: const Icon(Icons.star), - title: Text(unlockFeaturesEnabled ? S.of(context).unlockProFeatures : S.of(context).buyLightmeterPro), + title: Text(S.of(context).unlockProFeatures), onTap: !isPending ? () { - showBuyProDialog(context); - ServicesProvider.of(context) - .analytics - .logUnlockProFeatures(unlockFeaturesEnabled ? 'Unlock Pro features' : 'Buy Lightmeter Pro'); + showDialog( + context: context, + builder: (_) => const Dialog(child: ProFeaturesDialog()), + ); } : null, trailing: isPending diff --git a/lib/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart b/lib/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart index 7050ae2..57d5d14 100644 --- a/lib/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart +++ b/lib/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:lightmeter/data/models/feature.dart'; import 'package:lightmeter/generated/l10n.dart'; -import 'package:lightmeter/providers/remote_config_provider.dart'; import 'package:lightmeter/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart'; import 'package:lightmeter/screens/settings/components/shared/settings_section/widget_settings_section.dart'; @@ -11,9 +9,7 @@ class LightmeterProSettingsSection extends StatelessWidget { @override Widget build(BuildContext context) { return SettingsSection( - title: RemoteConfig.isEnabled(context, Feature.unlockProFeaturesText) - ? S.of(context).proFeatures - : S.of(context).lightmeterPro, + title: S.of(context).proFeatures, children: const [BuyProListTile()], ); } diff --git a/lib/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart b/lib/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart index 1f89b4b..9dfb026 100644 --- a/lib/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart +++ b/lib/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart @@ -5,6 +5,7 @@ import 'package:lightmeter/providers/equipment_profile_provider.dart'; import 'package:lightmeter/providers/films_provider.dart'; import 'package:lightmeter/providers/user_preferences_provider.dart'; import 'package:lightmeter/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart'; +import 'package:lightmeter/utils/context_utils.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class MeteringScreenLayoutListTile extends StatelessWidget { @@ -24,6 +25,15 @@ class MeteringScreenLayoutListTile extends StatelessWidget { description: S.of(context).meteringScreenLayoutHint, values: UserPreferencesProvider.meteringScreenConfigOf(context), titleAdapter: _toStringLocalized, + enabledAdapter: (value) { + switch (value) { + case MeteringScreenLayoutFeature.equipmentProfiles: + case MeteringScreenLayoutFeature.filmPicker: + return context.isPro; + default: + return true; + } + }, onSave: (value) { if (!value[MeteringScreenLayoutFeature.equipmentProfiles]!) { EquipmentProfileProvider.of(context).setProfile(EquipmentProfiles.of(context).first); diff --git a/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart b/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart index aa3a370..fdf7cc5 100644 --- a/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart +++ b/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/settings/components/shared/disable/widget_disable.dart'; typedef StringAdapter = String Function(BuildContext context, T value); @@ -11,6 +12,7 @@ class DialogSwitch extends StatefulWidget { final Map values; final StringAdapter titleAdapter; final StringAdapter? subtitleAdapter; + final bool Function(T value)? enabledAdapter; final ValueChanged> onSave; const DialogSwitch({ @@ -20,6 +22,7 @@ class DialogSwitch extends StatefulWidget { required this.values, required this.titleAdapter, this.subtitleAdapter, + this.enabledAdapter, required this.onSave, super.key, }); @@ -52,9 +55,12 @@ class _DialogSwitchState extends State> { ], ListView( shrinkWrap: true, - children: _features.entries - .map( - (entry) => SwitchListTile( + children: _features.entries.map( + (entry) { + final isEnabled = widget.enabledAdapter?.call(entry.key) ?? true; + return Disable( + disable: !isEnabled, + child: SwitchListTile( contentPadding: EdgeInsets.symmetric(horizontal: Dimens.dialogTitlePadding.left), title: Text(widget.titleAdapter(context, entry.key)), subtitle: widget.subtitleAdapter != null @@ -63,15 +69,16 @@ class _DialogSwitchState extends State> { style: Theme.of(context).listTileTheme.subtitleTextStyle, ) : null, - value: _features[entry.key]!, + value: isEnabled && _features[entry.key]!, onChanged: (value) { setState(() { _features.update(entry.key, (_) => value); }); }, ), - ) - .toList(), + ); + }, + ).toList(), ), ], ), diff --git a/lib/screens/settings/components/shared/disable/widget_disable.dart b/lib/screens/settings/components/shared/disable/widget_disable.dart new file mode 100644 index 0000000..3b1d276 --- /dev/null +++ b/lib/screens/settings/components/shared/disable/widget_disable.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/res/dimens.dart'; + +class Disable extends StatelessWidget { + final bool disable; + final Widget? child; + + const Disable({ + this.disable = true, + this.child, + super.key, + }); + + @override + Widget build(BuildContext context) { + return Opacity( + opacity: disable ? Dimens.disabledOpacity : Dimens.enabledOpacity, + child: IgnorePointer( + ignoring: disable, + child: child, + ), + ); + } +} diff --git a/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart b/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart index a2b980f..5fd1d3d 100644 --- a/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart +++ b/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/settings/components/shared/disable/widget_disable.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; /// Depends on the product status and replaces [onTap] with purchase callback @@ -23,12 +23,12 @@ class IAPListTile extends StatelessWidget { @override Widget build(BuildContext context) { final isPurchased = IAPProducts.isPurchased(context, IAPProductType.paidFeatures); - return Opacity( - opacity: isPurchased ? Dimens.enabledOpacity : Dimens.disabledOpacity, + return Disable( + disable: !isPurchased, child: ListTile( leading: leading, title: title, - onTap: isPurchased ? onTap : null, + onTap: onTap, ), ); } diff --git a/lib/screens/settings/components/theme/components/primary_color/widget_list_tile_primary_color.dart b/lib/screens/settings/components/theme/components/primary_color/widget_list_tile_primary_color.dart index 44de22e..1cf8762 100644 --- a/lib/screens/settings/components/theme/components/primary_color/widget_list_tile_primary_color.dart +++ b/lib/screens/settings/components/theme/components/primary_color/widget_list_tile_primary_color.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/data/models/dynamic_colors_state.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/providers/user_preferences_provider.dart'; -import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/settings/components/shared/disable/widget_disable.dart'; import 'package:lightmeter/screens/settings/components/theme/components/primary_color/components/primary_color_picker_dialog/widget_dialog_picker_primary_color.dart'; class PrimaryColorListTile extends StatelessWidget { @@ -11,13 +11,10 @@ class PrimaryColorListTile extends StatelessWidget { @override Widget build(BuildContext context) { if (UserPreferencesProvider.dynamicColorStateOf(context) == DynamicColorState.enabled) { - return Opacity( - opacity: Dimens.disabledOpacity, - child: IgnorePointer( - child: ListTile( - leading: const Icon(Icons.palette), - title: Text(S.of(context).primaryColor), - ), + return Disable( + child: ListTile( + leading: const Icon(Icons.palette), + title: Text(S.of(context).primaryColor), ), ); } diff --git a/lib/screens/settings/utils/show_buy_pro_dialog.dart b/lib/screens/settings/utils/show_buy_pro_dialog.dart deleted file mode 100644 index 181259f..0000000 --- a/lib/screens/settings/utils/show_buy_pro_dialog.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lightmeter/data/models/feature.dart'; -import 'package:lightmeter/generated/l10n.dart'; -import 'package:lightmeter/providers/remote_config_provider.dart'; -import 'package:lightmeter/res/dimens.dart'; -import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; - -Future showBuyProDialog(BuildContext context) { - final unlockFeaturesEnabled = RemoteConfig.isEnabled(context, Feature.unlockProFeaturesText); - - Widget splitDescription() { - final description = - unlockFeaturesEnabled ? S.of(context).unlockProFeaturesDescription : S.of(context).lightmeterProDescription; - final paragraphs = description.split('\n\n'); - final features = paragraphs.first.split('\n \u2022 ').sublist(1); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text(paragraphs.first.split('\n \u2022 ').first), - ...features.map( - (f) => Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('\u2022 '), - Flexible(child: Text(f)), - ], - ), - ), - Text('\n${paragraphs.last}'), - ], - ); - } - - return showDialog( - context: context, - builder: (_) => AlertDialog( - icon: const Icon(Icons.star), - titlePadding: Dimens.dialogIconTitlePadding, - title: Text(unlockFeaturesEnabled ? S.of(context).proFeatures : S.of(context).lightmeterPro), - contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), - content: SingleChildScrollView(child: splitDescription()), - actionsPadding: Dimens.dialogActionsPadding, - actions: [ - TextButton( - onPressed: Navigator.of(context).pop, - child: Text(S.of(context).cancel), - ), - FilledButton( - onPressed: () { - Navigator.of(context).pop(); - IAPProductsProvider.maybeOf(context)?.buy(IAPProductType.paidFeatures); - }, - child: Text(unlockFeaturesEnabled ? S.of(context).unlock : S.of(context).buy), - ), - ], - ), - ); -} diff --git a/lib/screens/shared/pro_features_dialog/widget_dialog_pro_features.dart b/lib/screens/shared/pro_features_dialog/widget_dialog_pro_features.dart new file mode 100644 index 0000000..c58e94d --- /dev/null +++ b/lib/screens/shared/pro_features_dialog/widget_dialog_pro_features.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart'; +import 'package:lightmeter/screens/shared/transparent_dialog/widget_dialog_transparent.dart'; +import 'package:lightmeter/utils/text_height.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; + +class ProFeaturesDialog extends StatelessWidget { + const ProFeaturesDialog({super.key}); + + double height(BuildContext context) => TransparentDialog.height( + context, + title: S.of(context).proFeatures, + contextHeight: dialogTextHeight( + context, + S.of(context).unlockProFeaturesDescription, + Theme.of(context).textTheme.bodyMedium, + Dimens.paddingL * 2, + ), + ); + + @override + Widget build(BuildContext context) { + return TransparentDialog( + icon: Icons.star, + title: S.of(context).proFeatures, + scrollableContent: false, + content: Flexible( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), + child: Text( + S.of(context).unlockProFeaturesDescription, + style: Theme.of(context).textTheme.bodyMedium, + ), + ), + ), + ), + actions: [ + TextButton( + onPressed: () => _close(context), + child: Text(S.of(context).cancel), + ), + FilledButton( + onPressed: () { + _close(context).then((_) => IAPProductsProvider.maybeOf(context)?.buy(IAPProductType.paidFeatures)); + }, + child: Text(S.of(context).unlock), + ), + ], + ); + } + + Future _close(BuildContext context) async => AnimatedDialog.maybeClose(context) ?? Navigator.of(context).pop(); +} diff --git a/lib/screens/shared/transparent_dialog/widget_dialog_transparent.dart b/lib/screens/shared/transparent_dialog/widget_dialog_transparent.dart new file mode 100644 index 0000000..ee3870e --- /dev/null +++ b/lib/screens/shared/transparent_dialog/widget_dialog_transparent.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/utils/text_height.dart'; + +class TransparentDialog extends StatelessWidget { + final IconData icon; + final String title; + final String? subtitle; + final Widget content; + final bool scrollableContent; + final List actions; + + const TransparentDialog({ + required this.icon, + required this.title, + this.subtitle, + required this.content, + required this.scrollableContent, + this.actions = const [], + super.key, + }); + + static double height( + BuildContext context, { + required String title, + String? subtitle, + required double contextHeight, + bool scrollableContent = false, + }) { + double height = IconTheme.of(context).size! + Dimens.dialogTitlePadding.vertical; + height += dialogTextHeight( + context, + title, + Theme.of(context).textTheme.headlineSmall, + Dimens.dialogIconTitlePadding.horizontal, + ) + + Dimens.dialogIconTitlePadding.vertical; + if (subtitle != null) { + height += dialogTextHeight( + context, + subtitle, + Theme.of(context).textTheme.bodyMedium, + Dimens.dialogIconTitlePadding.horizontal, + ) + + Dimens.dialogIconTitlePadding.vertical; + } + height += contextHeight; + if (scrollableContent) height += 1; + return height += 48 + Dimens.dialogActionsPadding.vertical; + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: Dimens.dialogTitlePadding, + child: Icon(icon), + ), + Padding( + padding: Dimens.dialogIconTitlePadding, + child: Text( + title, + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, + ), + ), + if (subtitle != null) + Padding( + padding: Dimens.dialogIconTitlePadding, + child: Text( + subtitle!, + style: Theme.of(context).textTheme.bodyMedium, + textAlign: TextAlign.center, + ), + ), + ], + ), + if (scrollableContent) const Divider(), + content, + if (scrollableContent) const Divider(), + Padding( + padding: Dimens.dialogActionsPadding, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: _actions().toList(), + ), + ), + ], + ); + } + + Iterable _actions() sync* { + for (int i = 0; i < actions.length; i++) { + yield i == 0 ? const Spacer() : const SizedBox(width: Dimens.grid16); + yield actions[i]; + } + } +} diff --git a/lib/utils/context_utils.dart b/lib/utils/context_utils.dart new file mode 100644 index 0000000..f64ea76 --- /dev/null +++ b/lib/utils/context_utils.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; +import 'package:lightmeter/providers/user_preferences_provider.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; + +extension BuildContextUtils on BuildContext { + bool meteringFeature(MeteringScreenLayoutFeature feature) { + return UserPreferencesProvider.meteringScreenFeatureOf(this, feature); + } + + bool get isPro => IAPProducts.isPurchased(this, IAPProductType.paidFeatures); +} diff --git a/lib/utils/ev_from_bytes.dart b/lib/utils/ev_from_bytes.dart new file mode 100644 index 0000000..c7d12ea --- /dev/null +++ b/lib/utils/ev_from_bytes.dart @@ -0,0 +1,27 @@ +import 'dart:developer'; +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:exif/exif.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; + +Future evFromImage(Uint8List bytes) async { + try { + final tags = await readExifFromBytes(bytes); + final iso = double.tryParse("${tags["EXIF ISOSpeedRatings"]}"); + final apertureValueRatio = (tags["EXIF FNumber"]?.values as IfdRatios?)?.ratios.first; + final speedValueRatio = (tags["EXIF ExposureTime"]?.values as IfdRatios?)?.ratios.first; + if (iso == null || apertureValueRatio == null || speedValueRatio == null) { + log('Error parsing EXIF: ${tags.keys}'); + return null; + } + + final aperture = apertureValueRatio.numerator / apertureValueRatio.denominator; + final speed = speedValueRatio.numerator / speedValueRatio.denominator; + + return log2(math.pow(aperture, 2)) - log2(speed) - log2(iso / 100); + } catch (e) { + log(e.toString()); + return null; + } +} diff --git a/lib/utils/text_height.dart b/lib/utils/text_height.dart new file mode 100644 index 0000000..f5a0fe1 --- /dev/null +++ b/lib/utils/text_height.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/res/dimens.dart'; + +double dialogTextHeight( + BuildContext context, + String text, + TextStyle? style, + double textPadding, +) => + textHeight( + text, + style, + MediaQuery.sizeOf(context).width - Dimens.dialogMargin.horizontal - textPadding, + ); + +double textHeight( + String text, + TextStyle? style, + double maxWidth, +) { + final TextPainter titlePainter = TextPainter( + text: TextSpan( + text: text, + style: style, + ), + textDirection: TextDirection.ltr, + )..layout(maxWidth: maxWidth); + return titlePainter.height; +} diff --git a/test/application_mock.dart b/test/application_mock.dart index dbcf260..a5aecb3 100644 --- a/test/application_mock.dart +++ b/test/application_mock.dart @@ -2,12 +2,18 @@ import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/res/theme.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; /// Provides [MaterialApp] with default theme and "en" localization class WidgetTestApplicationMock extends StatelessWidget { + final IAPProductStatus productStatus; final Widget child; - const WidgetTestApplicationMock({required this.child, super.key}); + const WidgetTestApplicationMock({ + this.productStatus = IAPProductStatus.purchased, + required this.child, + super.key, + }); @override Widget build(BuildContext context) { diff --git a/test/screens/settings/components/widget_settings_section_lightmeter_pro_test.dart b/test/screens/settings/components/widget_settings_section_lightmeter_pro_test.dart new file mode 100644 index 0000000..1ae99f4 --- /dev/null +++ b/test/screens/settings/components/widget_settings_section_lightmeter_pro_test.dart @@ -0,0 +1,60 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart'; +import 'package:lightmeter/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart'; +import 'package:lightmeter/screens/shared/transparent_dialog/widget_dialog_transparent.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; + +import '../../../application_mock.dart'; + +void main() { + Future pumpApplication(WidgetTester tester) async { + await tester.pumpWidget( + IAPProducts( + products: [ + IAPProduct( + storeId: IAPProductType.paidFeatures.storeId, + ), + ], + child: const WidgetTestApplicationMock( + child: LightmeterProSettingsSection(), + ), + ), + ); + await tester.pumpAndSettle(); + } + + testWidgets( + '`showBuyProDialog` and buy', + (tester) async { + await pumpApplication(tester); + await tester.tap(find.byType(BuyProListTile)); + await tester.pumpAndSettle(); + expect(find.byType(TransparentDialog), findsOneWidget); + expect(find.text(S.current.proFeatures), findsNWidgets(2)); + expect(find.text(S.current.cancel), findsOneWidget); + expect(find.text(S.current.unlock), findsOneWidget); + + await tester.tap(find.text(S.current.unlock)); + await tester.pumpAndSettle(); + expect(find.byType(TransparentDialog), findsNothing); + }, + ); + + testWidgets( + '`showBuyProDialog` and cancel', + (tester) async { + await pumpApplication(tester); + await tester.tap(find.byType(BuyProListTile)); + await tester.pumpAndSettle(); + expect(find.byType(TransparentDialog), findsOneWidget); + expect(find.text(S.current.proFeatures), findsNWidgets(2)); + expect(find.text(S.current.cancel), findsOneWidget); + expect(find.text(S.current.unlock), findsOneWidget); + + await tester.tap(find.text(S.current.cancel)); + await tester.pumpAndSettle(); + expect(find.byType(TransparentDialog), findsNothing); + }, + ); +} diff --git a/test/screens/settings/utils/show_buy_pro_dialog_test.dart b/test/screens/settings/utils/show_buy_pro_dialog_test.dart deleted file mode 100644 index 16a8e19..0000000 --- a/test/screens/settings/utils/show_buy_pro_dialog_test.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:lightmeter/data/models/feature.dart'; -import 'package:lightmeter/generated/l10n.dart'; -import 'package:lightmeter/providers/remote_config_provider.dart'; -import 'package:lightmeter/screens/settings/utils/show_buy_pro_dialog.dart'; - -import '../../../application_mock.dart'; - -void main() { - Future pumpApplication(WidgetTester tester) async { - await tester.pumpWidget( - RemoteConfig( - config: const {Feature.unlockProFeaturesText: false}, - child: WidgetTestApplicationMock( - child: Builder( - builder: (context) => ElevatedButton( - onPressed: () => showBuyProDialog(context), - child: const SizedBox(), - ), - ), - ), - ), - ); - await tester.pumpAndSettle(); - } - - testWidgets( - '`showBuyProDialog` and buy', - (tester) async { - await pumpApplication(tester); - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text(S.current.lightmeterPro), findsOneWidget); - expect(find.text(S.current.cancel), findsOneWidget); - expect(find.text(S.current.buy), findsOneWidget); - - await tester.tap(find.text(S.current.buy)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsNothing); - }, - ); - - testWidgets( - '`showBuyProDialog` and cancel', - (tester) async { - await pumpApplication(tester); - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text(S.current.lightmeterPro), findsOneWidget); - expect(find.text(S.current.cancel), findsOneWidget); - expect(find.text(S.current.buy), findsOneWidget); - - await tester.tap(find.text(S.current.cancel)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsNothing); - }, - ); -} diff --git a/test/utils/ev_from_bytes_test.dart b/test/utils/ev_from_bytes_test.dart new file mode 100644 index 0000000..f73a257 --- /dev/null +++ b/test/utils/ev_from_bytes_test.dart @@ -0,0 +1,24 @@ +import 'dart:io'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/utils/ev_from_bytes.dart'; + +void main() { + group('evFromImage', () { + test( + 'camera_stub_image.jpg', + () { + final bytes = File('assets/camera_stub_image.jpg').readAsBytesSync(); + expectLater(evFromImage(bytes), completion(8.25230310752341)); + }, + ); + + test( + 'no EXIF', + () { + final bytes = File('assets/launcher_icon_dev_512.png').readAsBytesSync(); + expectLater(evFromImage(bytes), completion(null)); + }, + ); + }); +} From 8f5893c7d23beb1a487ff1c5600f94becf469a4c Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Mon, 15 Jan 2024 20:47:10 +0100 Subject: [PATCH 17/17] ML-143 EV100 indication (#148) * added `showEV100` to user preferences * integrated EV100 setting to UI * available for pro * replaced `IAPProducts.isPurchased` with context extension * fixed `UserPreferencesProvider` tests * EV100 -> Ev100 --- lib/data/shared_prefs_service.dart | 4 +++ lib/l10n/intl_en.arb | 1 + lib/l10n/intl_fr.arb | 1 + lib/l10n/intl_ru.arb | 1 + lib/l10n/intl_zh.arb | 1 + lib/providers/equipment_profile_provider.dart | 5 ++-- lib/providers/films_provider.dart | 7 ++--- lib/providers/user_preferences_provider.dart | 18 ++++++++++++ .../measure_button/widget_button_measure.dart | 28 +++++++++++++++++-- .../provider_bottom_controls.dart | 3 ++ .../widget_bottom_controls.dart | 3 ++ .../camera_preview/widget_camera_preview.dart | 4 +-- .../widget_container_camera.dart | 4 +-- .../widget_container_readings.dart | 8 ++---- lib/screens/metering/screen_metering.dart | 1 + .../widget_list_tile_show_ev_100.dart | 24 ++++++++++++++++ .../widget_settings_section_metering.dart | 2 ++ .../iap_list_tile/widget_list_tile_iap.dart | 4 +-- lib/screens/settings/screen_settings.dart | 5 ++-- test/data/shared_prefs_service_test.dart | 19 +++++++++++++ .../user_preferences_provider_test.dart | 22 +++++++++++++++ 21 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 lib/screens/settings/components/metering/components/show_ev_100/widget_list_tile_show_ev_100.dart diff --git a/lib/data/shared_prefs_service.dart b/lib/data/shared_prefs_service.dart index 443f2e5..3bb6dfb 100644 --- a/lib/data/shared_prefs_service.dart +++ b/lib/data/shared_prefs_service.dart @@ -16,6 +16,7 @@ class UserPreferencesService { static const evSourceTypeKey = "evSourceType"; static const stopTypeKey = "stopType"; + static const showEv100Key = "showEv100"; static const cameraEvCalibrationKey = "cameraEvCalibration"; static const lightSensorEvCalibrationKey = "lightSensorEvCalibration"; static const meteringScreenLayoutKey = "meteringScreenLayout"; @@ -84,6 +85,9 @@ class UserPreferencesService { StopType get stopType => StopType.values[_sharedPreferences.getInt(stopTypeKey) ?? 2]; set stopType(StopType value) => _sharedPreferences.setInt(stopTypeKey, value.index); + bool get showEv100 => _sharedPreferences.getBool(showEv100Key) ?? false; + set showEv100(bool value) => _sharedPreferences.setBool(showEv100Key, value); + MeteringScreenLayoutConfig get meteringScreenLayout { final configJson = _sharedPreferences.getString(meteringScreenLayoutKey); if (configJson != null) { diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 13d5cbd..02dbb3d 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -34,6 +34,7 @@ "calibrationMessageCameraOnly": "The accuracy of the readings measured by this application depends entirely on the rear camera of the device. Therefore, consider testing this application and setting up an EV calibration value that will give you the desired measurement results.", "camera": "Camera", "lightSensor": "Light sensor", + "showEv100": "Show EV\u2081\u2080\u2080", "meteringScreenLayout": "Metering screen layout", "meteringScreenLayoutHint": "Hide elements on the metering screen that you don't need so that they don't waste exposure pairs list space.", "meteringScreenLayoutHintEquipmentProfiles": "Equipment profile picker", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 66dc9fb..590976d 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -34,6 +34,7 @@ "calibrationMessageCameraOnly": "La précision des lectures mesurées par cette application dépend entièrement de la caméra arrière de l'appareil. Par conséquent, envisagez de tester cette application et de configurer une valeur d'étalonnage EV qui vous donnera les résultats de mesure souhaités.", "camera": "Caméra", "lightSensor": "Capteur de lumière", + "showEv100": "Montrer EV\u2081\u2080\u2080", "meteringScreenLayout": "Disposition de l'écran de mesure", "meteringScreenLayoutHint": "Masquer les éléments sur l'écran de mesure dont vous n'avez pas besoin pour qu'ils ne gaspillent pas de l'espace dans les paires d'exposition.", "meteringScreenLayoutHintEquipmentProfiles": "Sélecteur de profil de l'équipement", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index 367b707..e7f0743 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -34,6 +34,7 @@ "calibrationMessageCameraOnly": "Точность измерений данного приложения полностью зависит от точности камеры вашего устройства. Поэтому рекомендуется самостоятельно подобрать калибровочное значение, которое даст желаемый результат измерений.", "camera": "Камера", "lightSensor": "Датчик освещённости", + "showEv100": "Показывать EV\u2081\u2080\u2080", "meteringScreenLayout": "Элементы главного экрана", "meteringScreenLayoutHint": "Здесь вы можете скрыть некоторые ненужные или неиспользуемые элементы с главного экрана.", "meteringScreenLayoutHintEquipmentProfiles": "Выбор профиля оборудования", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 0055685..71fe757 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -34,6 +34,7 @@ "calibrationMessageCameraOnly": "此应用程序测量读数的准确s性完全取决于设备的后置摄像头。因此,请考虑测试此应用并手动设置 EV 校准,以获得准确的测量结果。", "camera": "摄像头", "lightSensor": "光传感器", + "showEv100": "显示 EV\u2081\u2080\u2080", "meteringScreenLayout": "布局", "meteringScreenLayoutHint": "隐藏不需要的元素,以免浪费曝光列表空间", "meteringScreenLayoutHintEquipmentProfiles": "设备配置选择", diff --git a/lib/providers/equipment_profile_provider.dart b/lib/providers/equipment_profile_provider.dart index 564c5ef..74397a5 100644 --- a/lib/providers/equipment_profile_provider.dart +++ b/lib/providers/equipment_profile_provider.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:lightmeter/utils/context_utils.dart'; import 'package:lightmeter/utils/selectable_provider.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; @@ -52,9 +53,9 @@ class EquipmentProfileProviderState extends State { return EquipmentProfiles( values: [ _defaultProfile, - if (IAPProducts.isPurchased(context, IAPProductType.paidFeatures)) ..._customProfiles, + if (context.isPro) ..._customProfiles, ], - selected: IAPProducts.isPurchased(context, IAPProductType.paidFeatures) ? _selectedProfile : _defaultProfile, + selected: context.isPro ? _selectedProfile : _defaultProfile, child: widget.child, ); } diff --git a/lib/providers/films_provider.dart b/lib/providers/films_provider.dart index aff6d01..3e9d02d 100644 --- a/lib/providers/films_provider.dart +++ b/lib/providers/films_provider.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:lightmeter/utils/context_utils.dart'; import 'package:lightmeter/utils/selectable_provider.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; @@ -44,11 +45,9 @@ class FilmsProviderState extends State { ], filmsInUse: [ const Film.other(), - if (IAPProducts.isPurchased(context, IAPProductType.paidFeatures)) ..._filmsInUse, + if (context.isPro) ..._filmsInUse, ], - selected: IAPProducts.isPurchased(context, IAPProductType.paidFeatures) - ? _selected - : const Film.other(), + selected: context.isPro ? _selected : const Film.other(), child: widget.child, ); } diff --git a/lib/providers/user_preferences_provider.dart b/lib/providers/user_preferences_provider.dart index 764f282..e2eecd7 100644 --- a/lib/providers/user_preferences_provider.dart +++ b/lib/providers/user_preferences_provider.dart @@ -53,6 +53,10 @@ class UserPreferencesProvider extends StatefulWidget { return _inheritFromEnumsModel(context, _Aspect.stopType).stopType; } + static bool showEv100Of(BuildContext context) { + return _inheritFromEnumsModel(context, _Aspect.showEv100).showEv100; + } + static CameraFeaturesConfig cameraConfigOf(BuildContext context) { return context.findAncestorWidgetOfExactType<_CameraFeaturesModel>()!.data; } @@ -83,6 +87,7 @@ class UserPreferencesProvider extends StatefulWidget { class _UserPreferencesProviderState extends State with WidgetsBindingObserver { late EvSourceType _evSourceType; late StopType _stopType = widget.userPreferencesService.stopType; + late bool _showEv100 = widget.userPreferencesService.showEv100; late MeteringScreenLayoutConfig _meteringScreenLayout = widget.userPreferencesService.meteringScreenLayout; late CameraFeaturesConfig _cameraFeatures = widget.userPreferencesService.cameraFeatures; late SupportedLocale _locale = widget.userPreferencesService.locale; @@ -135,6 +140,7 @@ class _UserPreferencesProviderState extends State with evSourceType: _evSourceType, locale: _locale, primaryColor: dynamicPrimaryColor ?? _primaryColor, + showEv100: _showEv100, stopType: _stopType, themeType: _themeType, child: _MeteringScreenLayoutModel( @@ -201,6 +207,13 @@ class _UserPreferencesProviderState extends State with widget.userPreferencesService.primaryColor = primaryColor; } + void toggleShowEv100() { + setState(() { + _showEv100 = !_showEv100; + }); + widget.userPreferencesService.showEv100 = _showEv100; + } + void setStopType(StopType stopType) { setState(() { _stopType = stopType; @@ -231,6 +244,7 @@ enum _Aspect { dynamicColorState, evSourceType, locale, + showEv100, stopType, theme, themeType, @@ -240,6 +254,7 @@ class _UserPreferencesModel extends InheritedModel<_Aspect> { final DynamicColorState dynamicColorState; final EvSourceType evSourceType; final SupportedLocale locale; + final bool showEv100; final StopType stopType; final ThemeType themeType; @@ -252,6 +267,7 @@ class _UserPreferencesModel extends InheritedModel<_Aspect> { required this.evSourceType, required this.locale, required Color primaryColor, + required this.showEv100, required this.stopType, required this.themeType, required super.child, @@ -267,6 +283,7 @@ class _UserPreferencesModel extends InheritedModel<_Aspect> { evSourceType != oldWidget.evSourceType || locale != oldWidget.locale || _primaryColor != oldWidget._primaryColor || + showEv100 != oldWidget.showEv100 || stopType != oldWidget.stopType || themeType != oldWidget.themeType; } @@ -279,6 +296,7 @@ class _UserPreferencesModel extends InheritedModel<_Aspect> { return (dependencies.contains(_Aspect.dynamicColorState) && dynamicColorState != oldWidget.dynamicColorState) || (dependencies.contains(_Aspect.evSourceType) && evSourceType != oldWidget.evSourceType) || (dependencies.contains(_Aspect.locale) && locale != oldWidget.locale) || + (dependencies.contains(_Aspect.showEv100) && showEv100 != oldWidget.showEv100) || (dependencies.contains(_Aspect.stopType) && stopType != oldWidget.stopType) || (dependencies.contains(_Aspect.theme) && (_brightness != oldWidget._brightness || _primaryColor != oldWidget._primaryColor)) || diff --git a/lib/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.dart b/lib/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.dart index 99bd2ae..e918557 100644 --- a/lib/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.dart +++ b/lib/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.dart @@ -1,15 +1,21 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/providers/user_preferences_provider.dart'; import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/screens/shared/filled_circle/widget_circle_filled.dart'; +import 'package:lightmeter/utils/context_utils.dart'; + +const String _subscript100 = '\u2081\u2080\u2080'; class MeteringMeasureButton extends StatefulWidget { final double? ev; + final double? ev100; final bool isMetering; final VoidCallback onTap; const MeteringMeasureButton({ required this.ev, + required this.ev100, required this.isMetering, required this.onTap, super.key, @@ -61,7 +67,7 @@ class _MeteringMeasureButtonState extends State { color: Theme.of(context).colorScheme.onSurface, size: Dimens.grid72 - Dimens.grid8, child: Center( - child: widget.ev != null ? _EvValueText(ev: widget.ev!) : null, + child: widget.ev != null ? _EvValueText(ev: widget.ev!, ev100: widget.ev100!) : null, ), ), ), @@ -83,16 +89,32 @@ class _MeteringMeasureButtonState extends State { class _EvValueText extends StatelessWidget { final double ev; + final double ev100; - const _EvValueText({required this.ev}); + const _EvValueText({ + required this.ev, + required this.ev100, + }); @override Widget build(BuildContext context) { final theme = Theme.of(context); return Text( - '${ev.toStringAsFixed(1)}\n${S.of(context).ev}', + _text(context), style: theme.textTheme.bodyMedium?.copyWith(color: theme.colorScheme.surface), textAlign: TextAlign.center, ); } + + String _text(BuildContext context) { + final bool showEv100 = context.isPro && UserPreferencesProvider.showEv100Of(context); + final StringBuffer buffer = StringBuffer() + ..writeAll([ + (showEv100 ? ev100 : ev).toStringAsFixed(1), + '\n', + S.of(context).ev, + if (showEv100) _subscript100, + ]); + return buffer.toString(); + } } diff --git a/lib/screens/metering/components/bottom_controls/provider_bottom_controls.dart b/lib/screens/metering/components/bottom_controls/provider_bottom_controls.dart index dd4a9be..f9d6d47 100644 --- a/lib/screens/metering/components/bottom_controls/provider_bottom_controls.dart +++ b/lib/screens/metering/components/bottom_controls/provider_bottom_controls.dart @@ -5,6 +5,7 @@ import 'package:lightmeter/screens/metering/components/bottom_controls/widget_bo class MeteringBottomControlsProvider extends StatelessWidget { final double? ev; + final double? ev100; final bool isMetering; final VoidCallback? onSwitchEvSourceType; final VoidCallback onMeasure; @@ -12,6 +13,7 @@ class MeteringBottomControlsProvider extends StatelessWidget { const MeteringBottomControlsProvider({ required this.ev, + required this.ev100, required this.isMetering, required this.onSwitchEvSourceType, required this.onMeasure, @@ -35,6 +37,7 @@ class MeteringBottomControlsProvider extends StatelessWidget { ), child: MeteringBottomControls( ev: ev, + ev100: ev100, isMetering: isMetering, onSwitchEvSourceType: onSwitchEvSourceType, onMeasure: onMeasure, diff --git a/lib/screens/metering/components/bottom_controls/widget_bottom_controls.dart b/lib/screens/metering/components/bottom_controls/widget_bottom_controls.dart index 31ecac4..0eef568 100644 --- a/lib/screens/metering/components/bottom_controls/widget_bottom_controls.dart +++ b/lib/screens/metering/components/bottom_controls/widget_bottom_controls.dart @@ -7,6 +7,7 @@ import 'package:lightmeter/screens/metering/components/bottom_controls/component class MeteringBottomControls extends StatelessWidget { final double? ev; + final double? ev100; final bool isMetering; final VoidCallback? onSwitchEvSourceType; final VoidCallback onMeasure; @@ -14,6 +15,7 @@ class MeteringBottomControls extends StatelessWidget { const MeteringBottomControls({ required this.ev, + required this.ev100, required this.isMetering, required this.onSwitchEvSourceType, required this.onMeasure, @@ -58,6 +60,7 @@ class MeteringBottomControls extends StatelessWidget { const Spacer(), MeteringMeasureButton( ev: ev, + ev100: ev100, isMetering: isMetering, onTap: onMeasure, ), diff --git a/lib/screens/metering/components/camera_container/components/camera_preview/widget_camera_preview.dart b/lib/screens/metering/components/camera_container/components/camera_preview/widget_camera_preview.dart index e6f1699..464228f 100644 --- a/lib/screens/metering/components/camera_container/components/camera_preview/widget_camera_preview.dart +++ b/lib/screens/metering/components/camera_container/components/camera_preview/widget_camera_preview.dart @@ -9,7 +9,7 @@ import 'package:lightmeter/screens/metering/components/camera_container/componen import 'package:lightmeter/screens/metering/components/camera_container/components/camera_preview/components/camera_view_placeholder/widget_placeholder_camera_view.dart'; import 'package:lightmeter/screens/metering/components/camera_container/components/camera_preview/components/histogram/widget_histogram.dart'; import 'package:lightmeter/screens/metering/components/camera_container/models/camera_error_type.dart'; -import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; +import 'package:lightmeter/utils/context_utils.dart'; class CameraPreview extends StatefulWidget { final CameraController? controller; @@ -93,7 +93,7 @@ class _CameraPreviewBuilderState extends State<_CameraPreviewBuilder> { alignment: Alignment.bottomCenter, children: [ CameraView(controller: widget.controller), - if (IAPProducts.isPurchased(context, IAPProductType.paidFeatures)) ...[ + if (context.isPro) ...[ if (UserPreferencesProvider.cameraFeatureOf( context, CameraFeature.histogram, diff --git a/lib/screens/metering/components/camera_container/widget_container_camera.dart b/lib/screens/metering/components/camera_container/widget_container_camera.dart index a4cb3e8..5ed2b43 100644 --- a/lib/screens/metering/components/camera_container/widget_container_camera.dart +++ b/lib/screens/metering/components/camera_container/widget_container_camera.dart @@ -17,7 +17,6 @@ import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_lis import 'package:lightmeter/screens/metering/components/shared/metering_top_bar/widget_top_bar_metering.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/widget_container_readings.dart'; import 'package:lightmeter/utils/context_utils.dart'; -import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class CameraContainer extends StatelessWidget { @@ -102,9 +101,8 @@ class CameraContainer extends StatelessWidget { } double _meteringContainerHeight(BuildContext context) { - final isPro = IAPProducts.isPurchased(context, IAPProductType.paidFeatures); double enabledFeaturesHeight = 0; - if (!isPro) { + if (!context.isPro) { enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight; enabledFeaturesHeight += Dimens.paddingS; } else { diff --git a/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart b/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart index 30d1392..ce373a8 100644 --- a/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart +++ b/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart @@ -10,7 +10,6 @@ import 'package:lightmeter/screens/metering/components/shared/readings_container import 'package:lightmeter/screens/metering/components/shared/readings_container/components/lightmeter_pro/widget_lightmeter_pro.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/nd_picker/widget_picker_nd.dart'; import 'package:lightmeter/utils/context_utils.dart'; -import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class ReadingsContainer extends StatelessWidget { @@ -33,15 +32,14 @@ class ReadingsContainer extends StatelessWidget { @override Widget build(BuildContext context) { - final isPro = IAPProducts.isPurchased(context, IAPProductType.paidFeatures); return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - if (!isPro) ...[ + if (!context.isPro) ...[ const LightmeterProAnimatedDialog(), const _InnerPadding(), ], - if (isPro && context.meteringFeature(MeteringScreenLayoutFeature.equipmentProfiles)) ...[ + if (context.isPro && context.meteringFeature(MeteringScreenLayoutFeature.equipmentProfiles)) ...[ const EquipmentProfilePicker(), const _InnerPadding(), ], @@ -52,7 +50,7 @@ class ReadingsContainer extends StatelessWidget { ), const _InnerPadding(), ], - if (isPro && context.meteringFeature(MeteringScreenLayoutFeature.filmPicker)) ...[ + if (context.isPro && context.meteringFeature(MeteringScreenLayoutFeature.filmPicker)) ...[ FilmPicker(selectedIso: iso), const _InnerPadding(), ], diff --git a/lib/screens/metering/screen_metering.dart b/lib/screens/metering/screen_metering.dart index 380411f..836e6d0 100644 --- a/lib/screens/metering/screen_metering.dart +++ b/lib/screens/metering/screen_metering.dart @@ -40,6 +40,7 @@ class MeteringScreen extends StatelessWidget { BlocBuilder( builder: (context, state) => MeteringBottomControlsProvider( ev: state is MeteringDataState ? state.ev : null, + ev100: state is MeteringDataState ? state.ev100 : null, isMetering: state.isMetering, onSwitchEvSourceType: ServicesProvider.of(context).environment.hasLightSensor ? UserPreferencesProvider.of(context).toggleEvSourceType diff --git a/lib/screens/settings/components/metering/components/show_ev_100/widget_list_tile_show_ev_100.dart b/lib/screens/settings/components/metering/components/show_ev_100/widget_list_tile_show_ev_100.dart new file mode 100644 index 0000000..a92623e --- /dev/null +++ b/lib/screens/settings/components/metering/components/show_ev_100/widget_list_tile_show_ev_100.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/providers/user_preferences_provider.dart'; +import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/settings/components/shared/disable/widget_disable.dart'; +import 'package:lightmeter/utils/context_utils.dart'; + +class ShowEv100ListTile extends StatelessWidget { + const ShowEv100ListTile({super.key}); + + @override + Widget build(BuildContext context) { + return Disable( + disable: !context.isPro, + child: SwitchListTile( + secondary: const Icon(Icons.adjust), + title: Text(S.of(context).showEv100), + value: context.isPro && UserPreferencesProvider.showEv100Of(context), + onChanged: (_) => UserPreferencesProvider.of(context).toggleShowEv100(), + contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM), + ), + ); + } +} diff --git a/lib/screens/settings/components/metering/widget_settings_section_metering.dart b/lib/screens/settings/components/metering/widget_settings_section_metering.dart index 0c6c07d..becf531 100644 --- a/lib/screens/settings/components/metering/widget_settings_section_metering.dart +++ b/lib/screens/settings/components/metering/widget_settings_section_metering.dart @@ -6,6 +6,7 @@ import 'package:lightmeter/screens/settings/components/metering/components/equip import 'package:lightmeter/screens/settings/components/metering/components/films/widget_list_tile_films.dart'; import 'package:lightmeter/screens/settings/components/metering/components/fractional_stops/widget_list_tile_fractional_stops.dart'; import 'package:lightmeter/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart'; +import 'package:lightmeter/screens/settings/components/metering/components/show_ev_100/widget_list_tile_show_ev_100.dart'; import 'package:lightmeter/screens/settings/components/shared/settings_section/widget_settings_section.dart'; class MeteringSettingsSection extends StatelessWidget { @@ -18,6 +19,7 @@ class MeteringSettingsSection extends StatelessWidget { children: const [ StopTypeListTile(), CalibrationListTile(), + ShowEv100ListTile(), MeteringScreenLayoutListTile(), EquipmentProfilesListTile(), FilmsListTile(), diff --git a/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart b/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart index 5fd1d3d..8cc522a 100644 --- a/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart +++ b/lib/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/screens/settings/components/shared/disable/widget_disable.dart'; +import 'package:lightmeter/utils/context_utils.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; /// Depends on the product status and replaces [onTap] with purchase callback @@ -22,9 +23,8 @@ class IAPListTile extends StatelessWidget { @override Widget build(BuildContext context) { - final isPurchased = IAPProducts.isPurchased(context, IAPProductType.paidFeatures); return Disable( - disable: !isPurchased, + disable: !context.isPro, child: ListTile( leading: leading, title: title, diff --git a/lib/screens/settings/screen_settings.dart b/lib/screens/settings/screen_settings.dart index ea8e1c5..295e01c 100644 --- a/lib/screens/settings/screen_settings.dart +++ b/lib/screens/settings/screen_settings.dart @@ -7,7 +7,7 @@ import 'package:lightmeter/screens/settings/components/metering/widget_settings_ import 'package:lightmeter/screens/settings/components/theme/widget_settings_section_theme.dart'; import 'package:lightmeter/screens/settings/flow_settings.dart'; import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart'; -import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; +import 'package:lightmeter/utils/context_utils.dart'; class SettingsScreen extends StatefulWidget { const SettingsScreen({super.key}); @@ -38,8 +38,7 @@ class _SettingsScreenState extends State { SliverList( delegate: SliverChildListDelegate( [ - if (!IAPProducts.isPurchased(context, IAPProductType.paidFeatures)) - const LightmeterProSettingsSection(), + if (!context.isPro) const LightmeterProSettingsSection(), const MeteringSettingsSection(), const GeneralSettingsSection(), const ThemeSettingsSection(), diff --git a/test/data/shared_prefs_service_test.dart b/test/data/shared_prefs_service_test.dart index 96f4e1e..269d002 100644 --- a/test/data/shared_prefs_service_test.dart +++ b/test/data/shared_prefs_service_test.dart @@ -181,6 +181,25 @@ void main() { }); }); + group('showEv100', () { + test('get default', () { + when(() => sharedPreferences.getBool(UserPreferencesService.showEv100Key)).thenReturn(null); + expect(service.showEv100, false); + }); + + test('get', () { + when(() => sharedPreferences.getBool(UserPreferencesService.showEv100Key)).thenReturn(true); + expect(service.showEv100, true); + }); + + test('set', () { + when(() => sharedPreferences.setBool(UserPreferencesService.showEv100Key, false)) + .thenAnswer((_) => Future.value(true)); + service.showEv100 = false; + verify(() => sharedPreferences.setBool(UserPreferencesService.showEv100Key, false)).called(1); + }); + }); + group('meteringScreenLayout', () { test('get default', () { when( diff --git a/test/providers/user_preferences_provider_test.dart b/test/providers/user_preferences_provider_test.dart index b6dc2ae..1a91419 100644 --- a/test/providers/user_preferences_provider_test.dart +++ b/test/providers/user_preferences_provider_test.dart @@ -27,6 +27,7 @@ void main() { setUp(() { when(() => mockUserPreferencesService.evSourceType).thenReturn(EvSourceType.camera); + when(() => mockUserPreferencesService.showEv100).thenReturn(false); when(() => mockUserPreferencesService.stopType).thenReturn(StopType.third); when(() => mockUserPreferencesService.meteringScreenLayout).thenReturn({ MeteringScreenLayoutFeature.extremeExposurePairs: true, @@ -164,6 +165,27 @@ void main() { }, ); + testWidgets( + 'Toggle Ev100', + (tester) async { + when(() => mockUserPreferencesService.showEv100).thenReturn(false); + await pumpTestWidget( + tester, + builder: (context) => ElevatedButton( + onPressed: () => UserPreferencesProvider.of(context).toggleShowEv100(), + child: Text('${UserPreferencesProvider.showEv100Of(context)}'), + ), + ); + await tester.pumpAndSettle(); + expect(find.text("${false}"), findsOneWidget); + + await tester.tap(find.text("${false}")); + await tester.pumpAndSettle(); + expect(find.text("${true}"), findsOneWidget); + verify(() => mockUserPreferencesService.showEv100 = true).called(1); + }, + ); + testWidgets( 'Set metering screen layout config', (tester) async {