Skip to content

Commit

Permalink
refactor: Refactor RemoteParameterFetcher to use
Browse files Browse the repository at this point in the history
RemoteParameter class
  • Loading branch information
naipaka committed Nov 12, 2023
1 parent ada9fab commit cdee8dc
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 193 deletions.
35 changes: 12 additions & 23 deletions packages/flutterfire_remote_parameter_fetcher/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,26 @@ class MainApp extends StatefulWidget {
class _MainAppState extends State<MainApp> {
late final rpf = widget.rpf;

late final _intRemoteParameter = rpf.getIntParameter('int_parameter');
late RemoteParameter<int> _intRemoteParameter;

late int _intParameterValue;

void listen(int value) {
debugPrint('remoteParameter value changed: $value');
_intParameterValue = value;
}

@override
void initState() {
super.initState();
_intRemoteParameter = rpf.getIntParameter(
'int_parameter',
onConfigUpdated: (value) {
debugPrint('remoteParameter value changed: $value');
_intParameterValue = value;
},
);
_intParameterValue = _intRemoteParameter.value;
_intRemoteParameter.addListener(listen);
}

@override
void dispose() {
// TODO(riscait): adding
// remoteParameter.removeListener(listen);
Future<void> dispose() async {
await _intRemoteParameter.dispose();
super.dispose();
}

Expand All @@ -57,19 +57,8 @@ class _MainAppState extends State<MainApp> {
appBar: AppBar(title: const Text('FlutterFireRemoteParameterFetcher')),
body: Padding(
padding: const EdgeInsets.all(32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('RemoteParameter value: $_intParameterValue'),
const SizedBox(height: 16),
FilledButton(
onPressed: () async {
await _intRemoteParameter.activateAndRefetch();
},
child: const Text('Activate and refetch'),
),
],
child: Center(
child: Text('RemoteParameter value: $_intParameterValue'),
),
),
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/// Remote Parameter Fetcher
library remote_parameter_fetcher;

export '../src/remote_parameter.dart';
export '../src/remote_parameter_fetcher.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,19 @@ import 'dart:async';
class RemoteParameter<T> {
RemoteParameter({
required T value,
required this.onConfigUpdated,
required this.activateAndRefetch,
}) : _value = value;
required StreamSubscription<void> subscription,
}) : _value = value,
_subscription = subscription;

/// A Stream of updated parameter information.
Stream<void> onConfigUpdated;

/// A function that will activate the fetched config and refetch the value.
/// This is useful for when you want to force a refetch of the value.
final Future<T> Function() activateAndRefetch;
/// The subscription to the stream of updated parameter information.
final StreamSubscription<void> _subscription;

/// The current value of the parameter.
T get value => _value;
T _value;

final List<void Function(T value)> _listeners = [];

late StreamSubscription<void> _subscription;

/// Add a listener to be notified when the value changes.
/// Executed when the remote value is updated.
void addListener(void Function(T value) listener) {
_listeners.add(listener);

if (_listeners.length == 1) {
// When the listener is added for the first time,
// monitor the onConfigUpdated stream.
_subscription = onConfigUpdated.listen((_) async {
_value = await activateAndRefetch();
_notifyListeners();
});
}
}

/// Remove a listener.
Future<void> removeListener(void Function(T value) listener) async {
_listeners.remove(listener);

if (_listeners.isEmpty) {
// When the last listener is removed,
// cancel the subscription to the onConfigUpdated stream.
await _subscription.cancel();
}
}
final T _value;

void _notifyListeners() {
for (final listener in _listeners) {
listener(_value);
}
/// Closes the [RemoteParameter].
Future<void> dispose() async {
await _subscription.cancel();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import 'package:meta/meta.dart';

import 'remote_parameter.dart';

typedef ValueChanged<T> = void Function(T value);

/// A class that wraps Remote Config.
/// Its role is to "fetch the configured parameters from remote and provide
/// them".
Expand Down Expand Up @@ -57,6 +59,11 @@ class RemoteParameterFetcher {
@visibleForTesting
late final Stream<RemoteConfigUpdate> onConfigUpdated = _rc.onConfigUpdated;

/// Filter the Stream of updated parameter information by key.
Stream<RemoteConfigUpdate> filteredOnConfigUpdated(String key) {
return onConfigUpdated.where((config) => config.updatedKeys.contains(key));
}

@visibleForTesting
String getString(String key) {
final value = _rc.getString(key);
Expand Down Expand Up @@ -107,103 +114,101 @@ class RemoteParameterFetcher {
}

/// Returns a [RemoteParameter] of type [String].
RemoteParameter<String> getStringParameter(String key) {
RemoteParameter<String> getStringParameter(
String key, {
required ValueChanged<String> onConfigUpdated,
}) {
return RemoteParameter<String>(
value: getString(key),
onConfigUpdated: onConfigUpdated.where(
(config) => config.updatedKeys.contains(key),
),
activateAndRefetch: () async {
subscription: filteredOnConfigUpdated(key).listen((event) async {
await activate();
return getString(key);
},
onConfigUpdated(getString(key));
}),
);
}

/// Returns a [RemoteParameter] of type [int].
RemoteParameter<int> getIntParameter(String key) {
RemoteParameter<int> getIntParameter(
String key, {
required ValueChanged<int> onConfigUpdated,
}) {
return RemoteParameter<int>(
value: getInt(key),
onConfigUpdated: onConfigUpdated.where(
(config) => config.updatedKeys.contains(key),
),
activateAndRefetch: () async {
subscription: filteredOnConfigUpdated(key).listen((event) async {
await activate();
return getInt(key);
},
onConfigUpdated(getInt(key));
}),
);
}

/// Returns a [RemoteParameter] of type [double].
RemoteParameter<double> getDoubleParameter(String key) {
RemoteParameter<double> getDoubleParameter(
String key, {
required ValueChanged<double> onConfigUpdated,
}) {
return RemoteParameter<double>(
value: getDouble(key),
onConfigUpdated: onConfigUpdated.where(
(config) => config.updatedKeys.contains(key),
),
activateAndRefetch: () async {
subscription: filteredOnConfigUpdated(key).listen((event) async {
await activate();
return getDouble(key);
},
onConfigUpdated(getDouble(key));
}),
);
}

/// Returns a [RemoteParameter] of type [bool].
RemoteParameter<bool> getBoolParameter(String key) {
RemoteParameter<bool> getBoolParameter(
String key, {
required ValueChanged<bool> onConfigUpdated,
}) {
return RemoteParameter<bool>(
value: getBool(key),
onConfigUpdated: onConfigUpdated.where(
(config) => config.updatedKeys.contains(key),
),
activateAndRefetch: () async {
subscription: filteredOnConfigUpdated(key).listen((event) async {
await activate();
return getBool(key);
},
onConfigUpdated(getBool(key));
}),
);
}

/// Returns a [RemoteParameter] of type [Map].
RemoteParameter<Map<String, Object?>> getJsonParameter(String key) {
RemoteParameter<Map<String, Object?>> getJsonParameter(
String key, {
required void Function(Map<String, Object?> value) onConfigUpdated,
}) {
return RemoteParameter<Map<String, Object?>>(
value: getJson(key),
onConfigUpdated: onConfigUpdated.where(
(config) => config.updatedKeys.contains(key),
),
activateAndRefetch: () async {
subscription: filteredOnConfigUpdated(key).listen((event) async {
await activate();
return getJson(key);
},
onConfigUpdated(getJson(key));
}),
);
}

/// Returns a [RemoteParameter] of type [List] of [Map].
RemoteParameter<List<Map<String, Object?>>> getListJsonParameter(String key) {
RemoteParameter<List<Map<String, Object?>>> getListJsonParameter(
String key, {
required ValueChanged<List<Map<String, Object?>>> onConfigUpdated,
}) {
return RemoteParameter<List<Map<String, Object?>>>(
value: getListJson(key),
onConfigUpdated: onConfigUpdated.where(
(config) => config.updatedKeys.contains(key),
),
activateAndRefetch: () async {
subscription: filteredOnConfigUpdated(key).listen((event) async {
await activate();
return getListJson(key);
},
onConfigUpdated(getListJson(key));
}),
);
}

/// Returns a [RemoteParameter] of type [T].
RemoteParameter<T> getDataParameter<T extends Object>({
required String key,
RemoteParameter<T> getDataParameter<T extends Object>(
String key, {
required T Function(Map<String, Object?>) fromJson,
required ValueChanged<T> onConfigUpdated,
}) {
return RemoteParameter<T>(
value: getData<T>(key: key, fromJson: fromJson),
onConfigUpdated: onConfigUpdated.where(
(config) => config.updatedKeys.contains(key),
),
activateAndRefetch: () async {
subscription: filteredOnConfigUpdated(key).listen((event) async {
await activate();
return getData<T>(key: key, fromJson: fromJson);
},
onConfigUpdated(getData(key: key, fromJson: fromJson));
}),
);
}
}
Loading

0 comments on commit cdee8dc

Please sign in to comment.