diff --git a/lib/application_wrapper.dart b/lib/application_wrapper.dart index d2975d6..447d892 100644 --- a/lib/application_wrapper.dart +++ b/lib/application_wrapper.dart @@ -3,11 +3,13 @@ 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 +25,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) { @@ -38,16 +41,19 @@ class ApplicationWrapper extends StatelessWidget { hapticsService: const HapticsService(), lightSensorService: const LightSensorService(LocalPlatform()), permissionsService: const PermissionsService(), + remoteConfigService: const RemoteConfigService(), userPreferencesService: userPreferencesService, volumeEventsService: const VolumeEventsService(LocalPlatform()), - child: EquipmentProfileProvider( - storageService: iapService, - child: FilmsProvider( + child: RemoteConfig( + 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/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..3a247b6 --- /dev/null +++ b/lib/data/remote_config_service.dart @@ -0,0 +1,42 @@ +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'); + } + } + + bool isEnabled(Feature feature) => FirebaseRemoteConfig.instance.getBool(feature.name); + + void _logError(dynamic throwable, {StackTrace? stackTrace}) { + FirebaseCrashlytics.instance.recordError(throwable, stackTrace); + } +} diff --git a/lib/providers/remote_config_provider.dart b/lib/providers/remote_config_provider.dart new file mode 100644 index 0000000..2b05073 --- /dev/null +++ b/lib/providers/remote_config_provider.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/feature.dart'; +import 'package:lightmeter/providers/services_provider.dart'; + +class RemoteConfig extends InheritedWidget { + const RemoteConfig({ + super.key, + required super.child, + }); + + static bool isEnabled(BuildContext context, Feature feature) { + return ServicesProvider.of(context).remoteConfigService.isEnabled(feature); + } + + @override + bool updateShouldNotify(RemoteConfig oldWidget) => true; +} diff --git a/lib/providers/services_provider.dart b/lib/providers/services_provider.dart index e65aa96..080b42d 100644 --- a/lib/providers/services_provider.dart +++ b/lib/providers/services_provider.dart @@ -3,6 +3,7 @@ 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'; @@ -14,6 +15,7 @@ class ServicesProvider extends InheritedWidget { final HapticsService hapticsService; final LightSensorService lightSensorService; final PermissionsService permissionsService; + final RemoteConfigService remoteConfigService; final UserPreferencesService userPreferencesService; final VolumeEventsService volumeEventsService; @@ -23,6 +25,7 @@ class ServicesProvider extends InheritedWidget { required this.hapticsService, required this.lightSensorService, required this.permissionsService, + required this.remoteConfigService, required this.userPreferencesService, required this.volumeEventsService, required super.child, diff --git a/pubspec.yaml b/pubspec.yaml index 215f802..67cb101 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,8 +13,9 @@ 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_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 +27,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 +57,7 @@ dev_dependencies: flutter: uses-material-design: true - assets: + assets: - assets/camera_stub_image.jpg flutter_intl: