Browse Source

Merge pull request #527 from Leptopoda/fix/option_persistence

fix(neon): option serialization and reset
pull/530/head
Nikolas Rimikis 1 year ago committed by GitHub
parent
commit
ce3140c262
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      packages/neon/neon/lib/src/settings/models/option.dart
  2. 30
      packages/neon/neon/lib/src/settings/models/select_option.dart
  3. 3
      packages/neon/neon/lib/src/settings/models/storage.dart
  4. 10
      packages/neon/neon/lib/src/settings/models/toggle_option.dart
  5. 18
      packages/neon/neon/test/option_test.dart

4
packages/neon/neon/lib/src/settings/models/option.dart

@ -84,10 +84,10 @@ abstract class Option<T> extends ChangeNotifier implements ValueListenable<T> {
}
/// Deserializes the data.
T deserialize(final Object data);
T? deserialize(final Object? data);
/// Serializes the [value].
Object serialize();
Object? serialize();
BehaviorSubject<T>? _stream;

30
packages/neon/neon/lib/src/settings/models/select_option.dart

@ -46,15 +46,14 @@ class SelectOption<T> extends Option<T> {
return stored as T;
}
return _fromString(vs, stored);
return _deserialize(vs, stored);
}
static T? _fromString<T>(final Map<T, LabelBuilder> vs, final String? valueStr) {
if (valueStr == null) {
return null;
}
@override
void reset() {
unawaited(storage.remove(key));
return vs.keys.firstWhereOrNull((final e) => e.toString() == valueStr);
super.reset();
}
Map<T, LabelBuilder> _values;
@ -62,7 +61,10 @@ class SelectOption<T> extends Option<T> {
@override
set value(final T value) {
super.value = value;
unawaited(storage.setString(key, serialize()));
if (value != null) {
unawaited(storage.setString(key, serialize()!));
}
}
/// A collection of different values this can have.
@ -80,8 +82,18 @@ class SelectOption<T> extends Option<T> {
}
@override
String serialize() => value.toString();
String? serialize() => _serialize(value);
static String? _serialize<T>(final T value) => value?.toString();
@override
T deserialize(final Object data) => _fromString(_values, data as String)!;
T? deserialize(final Object? data) => _deserialize(_values, data as String?);
static T? _deserialize<T>(final Map<T, LabelBuilder> vs, final String? valueStr) {
if (valueStr == null) {
return null;
}
return vs.keys.firstWhereOrNull((final e) => _serialize(e) == valueStr);
}
}

3
packages/neon/neon/lib/src/settings/models/storage.dart

@ -9,6 +9,8 @@ abstract interface class SettingsStorage {
// ignore: avoid_positional_boolean_parameters
Future setBool(final String key, final bool value);
Future<bool> remove(final String key);
}
class AppStorage implements SettingsStorage {
@ -24,6 +26,7 @@ class AppStorage implements SettingsStorage {
bool containsKey(final String key) => _sharedPreferences.containsKey(_formatKey(key));
@override
Future<bool> remove(final String key) => _sharedPreferences.remove(_formatKey(key));
@override

10
packages/neon/neon/lib/src/settings/models/toggle_option.dart

@ -25,9 +25,17 @@ class ToggleOption extends Option<bool> {
defaultValue: storage.getBool(key) ?? defaultValue,
);
@override
void reset() {
unawaited(storage.remove(key));
super.reset();
}
@override
set value(final bool value) {
super.value = value;
unawaited(storage.setBool(key, serialize()));
}
@ -35,5 +43,5 @@ class ToggleOption extends Option<bool> {
bool serialize() => value;
@override
bool deserialize(final Object data) => data as bool;
bool? deserialize(final Object? data) => data as bool?;
}

18
packages/neon/neon/test/option_test.dart

@ -37,6 +37,8 @@ void main() {
setUp(() {
when(() => storage.setString(key, any())).thenAnswer((final _) async {});
when(() => storage.remove(key)).thenAnswer((final _) async => true);
option = SelectOption<SelectValues>(
storage: storage,
key: key,
@ -148,8 +150,21 @@ void main() {
option.reset();
verify(callback.call).called(1);
verify(() => storage.remove(key)).called(1);
expect(option.value, option.defaultValue, reason: 'Should reset the value.');
});
test('Serialize null', () {
final option = SelectOption<SelectValues?>(
storage: storage,
key: key,
label: labelBuilder,
defaultValue: null,
values: valuesLabel,
);
expect(option.serialize(), null, reason: 'Should serialize to null. A string containing "null" is an error');
});
});
group('ToggleOption', () {
@ -157,6 +172,8 @@ void main() {
setUp(() {
when(() => storage.setBool(key, any())).thenAnswer((final _) async {});
when(() => storage.remove(key)).thenAnswer((final _) async => true);
option = ToggleOption(
storage: storage,
key: key,
@ -245,6 +262,7 @@ void main() {
option.reset();
verify(callback.call).called(1);
verify(() => storage.remove(key)).called(1);
expect(option.value, option.defaultValue, reason: 'Should reset the value.');
});
});

Loading…
Cancel
Save