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.
HMG_Patient_App_New/lib/services/remote_config_service.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}';
}