You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
3.1 KiB
Dart
84 lines
3.1 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:firebase_remote_config/firebase_remote_config.dart';
|
|
import 'package:flutter/foundation.dart' show kDebugMode;
|
|
import 'package:flutter/services.dart' show rootBundle;
|
|
import 'package:hmg_patient_app_new/services/logger_service.dart';
|
|
|
|
/// Firebase Remote Config wrapper. Fully generic — the app never hardcodes
|
|
/// occasion-specific values here; it only knows about the `occasion_config`
|
|
/// remote key and reads whatever JSON is published on the Firebase console.
|
|
abstract class RemoteConfigService {
|
|
/// Must be called once at startup, before the first frame if possible.
|
|
Future<void> initialize();
|
|
|
|
/// Fetches the latest values from Firebase (respecting the configured
|
|
/// minimum fetch interval) and activates them.
|
|
Future<bool> fetchAndActivate();
|
|
|
|
/// Raw JSON string currently held for the `occasion_config` key
|
|
/// (bundled default until the first successful fetch/activate).
|
|
String get occasionConfigRawJson;
|
|
}
|
|
|
|
class RemoteConfigServiceImp implements RemoteConfigService {
|
|
static const String occasionConfigKey = 'occasion_config';
|
|
static const String _defaultConfigAssetPath = 'assets/json/default_occasion_config.json';
|
|
|
|
final LoggerService loggerService;
|
|
final FirebaseRemoteConfig _remoteConfig;
|
|
|
|
RemoteConfigServiceImp({
|
|
required this.loggerService,
|
|
FirebaseRemoteConfig? remoteConfig,
|
|
}) : _remoteConfig = remoteConfig ?? FirebaseRemoteConfig.instance;
|
|
|
|
@override
|
|
Future<void> initialize() async {
|
|
try {
|
|
await _remoteConfig.setConfigSettings(
|
|
RemoteConfigSettings(
|
|
fetchTimeout: const Duration(seconds: 10),
|
|
// In debug builds, always fetch fresh values so you can test
|
|
// Remote Config changes instantly without waiting/throttling.
|
|
// Release builds keep a sane 1-hour minimum interval.
|
|
minimumFetchInterval: kDebugMode ? Duration.zero : const Duration(hours: 1),
|
|
),
|
|
);
|
|
|
|
// Bundled fallback so behaviour is deterministic (and identical to the
|
|
// current app look) before the very first successful remote fetch.
|
|
final defaultJson = await rootBundle.loadString(_defaultConfigAssetPath);
|
|
await _remoteConfig.setDefaults(<String, dynamic>{occasionConfigKey: defaultJson});
|
|
} catch (ex) {
|
|
loggerService.logError('RemoteConfigService.initialize error: $ex');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<bool> fetchAndActivate() async {
|
|
try {
|
|
return await _remoteConfig.fetchAndActivate();
|
|
} catch (ex) {
|
|
loggerService.logError('RemoteConfigService.fetchAndActivate error: $ex');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@override
|
|
String get occasionConfigRawJson {
|
|
try {
|
|
final value = _remoteConfig.getString(occasionConfigKey);
|
|
if (value.isEmpty) return _fallbackDisabledJson;
|
|
// Validate JSON shape early; if malformed, fall back safely.
|
|
json.decode(value);
|
|
return value;
|
|
} catch (ex) {
|
|
loggerService.logError('RemoteConfigService.occasionConfigRawJson parse error: $ex');
|
|
return _fallbackDisabledJson;
|
|
}
|
|
}
|
|
|
|
static const String _fallbackDisabledJson = '{"key":"none","enabled":false}';
|
|
}
|