Skip to content

Commit 8ddfda9

Browse files
committed
Added to/from Json and Map, added SettingFactory
1 parent b331b91 commit 8ddfda9

File tree

6 files changed

+263
-11
lines changed

6 files changed

+263
-11
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 1.1.1
2+
3+
Added `fromJson` and `fromMap` factory constructors to `Setting`, `SettingsGroup` and `GroupConfig` classes for easier deserialization from JSON strings.
4+
Added `toJson` and `toMap` in `Setting`, `SettingsGroup` and `GroupConfig`.
5+
Added `SettingFactory` class to easily create `Setting` instances from maps / json.
6+
17
## 1.1.0
28

39
* **Breaking**: Renamed `Settings` to `EasySettings` to avoid potential conflicts with a commonly used name.

example/pubspec.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,10 @@ packages:
250250
dependency: transitive
251251
description:
252252
name: shared_preferences_android
253-
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
253+
sha256: a2608114b1ffdcbc9c120eb71a0e207c71da56202852d4aab8a5e30a82269e74
254254
url: "https://pub.dev"
255255
source: hosted
256-
version: "2.4.10"
256+
version: "2.4.12"
257257
shared_preferences_foundation:
258258
dependency: transitive
259259
description:
@@ -397,4 +397,4 @@ packages:
397397
version: "1.1.0"
398398
sdks:
399399
dart: ">=3.8.0 <4.0.0"
400-
flutter: ">=3.27.0"
400+
flutter: ">=3.29.0"

lib/src/global_settings.dart

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,19 @@
2828
library;
2929

3030
import 'dart:async';
31-
import 'settings_manager.dart';
32-
import 'settings_group.dart';
33-
import 'settings_store.dart';
34-
import 'setting.dart';
35-
import 'logger.dart';
31+
import 'dart:convert';
32+
import 'package:easy_shared_preferences/easy_shared_preferences.dart';
3633

3734
/// Configuration for a settings group used in GlobalSettings initialization.
3835
///
3936
/// This class holds the key and items for a settings group without requiring
4037
/// a store instance, which will be provided by GlobalSettings.
41-
class GroupConfig {
38+
class GroupConfig implements Serializable {
4239
/// The unique key for the settings group.
4340
final String key;
4441

4542
/// The list of settings to include in the group.
46-
final List<Setting> items;
43+
final Iterable<Setting> items;
4744

4845
/// Creates a new group configuration.
4946
///
@@ -54,6 +51,41 @@ class GroupConfig {
5451
required this.key,
5552
required this.items,
5653
});
54+
55+
@override
56+
Map<String, dynamic> toMap() {
57+
return {
58+
'key': key,
59+
'items': items.map((item) => item.toMap()).toList(),
60+
};
61+
}
62+
63+
@override
64+
String toJson() {
65+
final map = toMap();
66+
return jsonEncode(map);
67+
}
68+
69+
/// Creates a group configuration from a map representation.
70+
factory GroupConfig.fromMap(Map<String, dynamic> map) {
71+
return GroupConfig(
72+
key: map['key'] as String,
73+
items: (map['items'] as List<dynamic>)
74+
.map((item) => SettingFactory.fromMap(item as Map<String, dynamic>))
75+
.toList(),
76+
);
77+
}
78+
79+
/// Creates a group configuration from a JSON string representation.
80+
factory GroupConfig.fromJson(String json) {
81+
final map = jsonDecode(json) as Map<String, dynamic>;
82+
return GroupConfig.fromMap(map);
83+
}
84+
85+
@override
86+
String toString() {
87+
return 'GroupConfig(key: $key, items: ${items.length})';
88+
}
5789
}
5890

5991
/// Helper class that eliminates duplication by providing a single method

lib/src/setting.dart

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,22 @@ class BoolSetting extends Setting<bool> {
415415
return defaultValue.toString();
416416
}
417417

418+
/// Creates a boolean setting from a map representation.
419+
factory BoolSetting.fromMap(Map<String, dynamic> map) {
420+
return BoolSetting(
421+
key: map['key'] as String,
422+
defaultValue: map['defaultValue'] as bool,
423+
userConfigurable: map['userConfigurable'] as bool? ?? true,
424+
validator: null, // Todo: implement validator deserialization
425+
onValidationError: null, // Handlers cannot be serialized
426+
);
427+
}
428+
418429
/// Creates a boolean setting from a JSON string representation.
430+
factory BoolSetting.fromJson(String json) {
431+
final map = jsonDecode(json) as Map<String, dynamic>;
432+
return BoolSetting.fromMap(map);
433+
}
419434
}
420435

421436
/// A setting that stores integer numeric values.
@@ -452,6 +467,23 @@ class IntSetting extends Setting<int> {
452467
super.validator,
453468
super.onValidationError,
454469
}) : super(type: SettingType.int);
470+
471+
/// Creates an integer setting from a map representation.
472+
factory IntSetting.fromMap(Map<String, dynamic> map) {
473+
return IntSetting(
474+
key: map['key'] as String,
475+
defaultValue: map['defaultValue'] as int,
476+
userConfigurable: map['userConfigurable'] as bool? ?? true,
477+
validator: null, // Todo: implement validator deserialization
478+
onValidationError: null, // Handlers cannot be serialized
479+
);
480+
}
481+
482+
/// Creates an integer setting from a JSON string representation.
483+
factory IntSetting.fromJson(String json) {
484+
final map = jsonDecode(json) as Map<String, dynamic>;
485+
return IntSetting.fromMap(map);
486+
}
455487
}
456488

457489
/// A setting that stores double-precision floating-point values.
@@ -488,6 +520,23 @@ class DoubleSetting extends Setting<double> {
488520
super.validator,
489521
super.onValidationError,
490522
}) : super(type: SettingType.double);
523+
524+
/// Creates a double setting from a map representation.
525+
factory DoubleSetting.fromMap(Map<String, dynamic> map) {
526+
return DoubleSetting(
527+
key: map['key'] as String,
528+
defaultValue: map['defaultValue'] as double,
529+
userConfigurable: map['userConfigurable'] as bool? ?? true,
530+
validator: null, // Todo: implement validator deserialization
531+
onValidationError: null, // Handlers cannot be serialized
532+
);
533+
}
534+
535+
/// Creates a double setting from a JSON string representation.
536+
factory DoubleSetting.fromJson(String json) {
537+
final map = jsonDecode(json) as Map<String, dynamic>;
538+
return DoubleSetting.fromMap(map);
539+
}
491540
}
492541

493542
/// A setting that stores string text values.
@@ -524,6 +573,23 @@ class StringSetting extends Setting<String> {
524573
super.validator,
525574
super.onValidationError,
526575
}) : super(type: SettingType.string);
576+
577+
/// Creates a string setting from a map representation.
578+
factory StringSetting.fromMap(Map<String, dynamic> map) {
579+
return StringSetting(
580+
key: map['key'] as String,
581+
defaultValue: map['defaultValue'] as String,
582+
userConfigurable: map['userConfigurable'] as bool? ?? true,
583+
validator: null, // Todo: implement validator deserialization
584+
onValidationError: null, // Handlers cannot be serialized
585+
);
586+
}
587+
588+
/// Creates a string setting from a JSON string representation.
589+
factory StringSetting.fromJson(String json) {
590+
final map = jsonDecode(json) as Map<String, dynamic>;
591+
return StringSetting.fromMap(map);
592+
}
527593
}
528594

529595
/// A setting that stores lists of string values.
@@ -560,6 +626,23 @@ class StringListSetting extends Setting<List<String>> {
560626
super.validator,
561627
super.onValidationError,
562628
}) : super(type: SettingType.stringList);
629+
630+
/// Creates a string list setting from a map representation.
631+
factory StringListSetting.fromMap(Map<String, dynamic> map) {
632+
return StringListSetting(
633+
key: map['key'] as String,
634+
defaultValue: List<String>.from(map['defaultValue'] as List),
635+
userConfigurable: map['userConfigurable'] as bool? ?? true,
636+
validator: null, // Todo: implement validator deserialization
637+
onValidationError: null, // Handlers cannot be serialized
638+
);
639+
}
640+
641+
/// Creates a string list setting from a JSON string representation.
642+
factory StringListSetting.fromJson(String json) {
643+
final map = jsonDecode(json) as Map<String, dynamic>;
644+
return StringListSetting.fromMap(map);
645+
}
563646
}
564647

565648
/// Represents the result of a validation operation.
@@ -591,3 +674,27 @@ class ValidationResult<T> {
591674
: 'ValidationResult(invalid: $value, error: $errorDescription)';
592675
}
593676
}
677+
678+
class SettingFactory {
679+
/// Creates a Setting instance from a map or JSON representation.
680+
static Setting fromMap(Map<String, dynamic> map) {
681+
final typeString = map['type'] as String;
682+
final type = SettingType.values.firstWhere(
683+
(e) => e.name == typeString,
684+
orElse: () => throw ArgumentError('Invalid setting type: $typeString'),
685+
);
686+
687+
switch (type) {
688+
case SettingType.bool:
689+
return BoolSetting.fromMap(map);
690+
case SettingType.int:
691+
return IntSetting.fromMap(map);
692+
case SettingType.double:
693+
return DoubleSetting.fromMap(map);
694+
case SettingType.string:
695+
return StringSetting.fromMap(map);
696+
case SettingType.stringList:
697+
return StringListSetting.fromMap(map);
698+
}
699+
}
700+
}

lib/src/settings_group.dart

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import 'dart:convert';
12
import 'dart:async';
23
import 'dart:collection';
4+
import 'package:easy_shared_preferences/src/global_settings.dart';
35
import 'package:logging/logging.dart';
46

57
import 'exceptions.dart';
@@ -640,4 +642,109 @@ class SettingsGroup extends UnmodifiableMapBase<String, Setting> {
640642
_ready = false;
641643
_logger.fine('SettingsGroup disposed: $key');
642644
}
645+
646+
Map<String, dynamic> toMap() {
647+
final map = <String, dynamic>{};
648+
for (final setting in items) {
649+
map[setting.key] = _get(setting);
650+
}
651+
return map;
652+
}
653+
654+
/// Creates a JSON string representation of this settings group.
655+
String toJson() {
656+
final map = toMap();
657+
return jsonEncode(map);
658+
}
659+
660+
/// Creates a settings group from a Map representation.
661+
/// Note: This does not initialize the settings in storage.
662+
/// You must call _init() manually after creating the group.
663+
static SettingsGroup fromMap({
664+
required String key,
665+
required Map<String, dynamic> map,
666+
required SettingsStore store,
667+
Duration operationTimeout = const Duration(seconds: 30),
668+
}) {
669+
final items = <Setting>[];
670+
map.forEach((settingKey, value) {
671+
if (value is bool) {
672+
items.add(BoolSetting(key: settingKey, defaultValue: value));
673+
} else if (value is int) {
674+
items.add(IntSetting(key: settingKey, defaultValue: value));
675+
} else if (value is double) {
676+
items.add(DoubleSetting(key: settingKey, defaultValue: value));
677+
} else if (value is String) {
678+
items.add(StringSetting(key: settingKey, defaultValue: value));
679+
} else if (value is List<String>) {
680+
items.add(StringListSetting(key: settingKey, defaultValue: value));
681+
} else {
682+
throw ArgumentError(
683+
'Unsupported setting type for key: $settingKey, value: $value');
684+
}
685+
});
686+
return SettingsGroup(
687+
key: key,
688+
items: items,
689+
store: store,
690+
operationTimeout: operationTimeout,
691+
);
692+
}
693+
694+
/// Creates a settings group from a JSON string representation.
695+
/// Note: This does not initialize the settings in storage.
696+
/// You must call _init() manually after creating the group.
697+
static SettingsGroup fromJson({
698+
required String key,
699+
required String json,
700+
required SettingsStore store,
701+
Duration operationTimeout = const Duration(seconds: 30),
702+
}) {
703+
final map = jsonDecode(json) as Map<String, dynamic>;
704+
return fromMap(
705+
key: key,
706+
map: map,
707+
store: store,
708+
operationTimeout: operationTimeout,
709+
);
710+
}
711+
712+
/// updates the settings in this group from a Map representation.
713+
/// Only updates settings that already exist in this group.
714+
/// Does not add new settings or remove existing ones.
715+
Future<void> updateFromMap(Map<String, dynamic> map) async {
716+
await _waitUntilReady();
717+
for (final entry in map.entries) {
718+
final setting = this[entry.key];
719+
if (setting != null) {
720+
await setValue(entry.key, entry.value);
721+
} else {
722+
_logger.warning(
723+
'Attempted to update non-existent setting: ${entry.key} in group: $key');
724+
}
725+
}
726+
}
727+
728+
/// Returns a string representation of this settings group.
729+
@override
730+
String toString() {
731+
return 'SettingsGroup($key, items: ${items.length}, ready: $_ready)';
732+
}
733+
734+
/// Converts this SettingsGroup to a GroupConfig for serialization or re-initialization.
735+
GroupConfig toConfig() {
736+
return GroupConfig(key: key, items: items);
737+
}
738+
739+
/// Converts this SettingsGroup to a JSON string representation of its configuration.
740+
String toConfigJson() {
741+
final config = toConfig();
742+
return config.toJson();
743+
}
744+
745+
/// Converts this SettingsGroup to a Map representation of its configuration.
746+
Map<String, dynamic> toConfigMap() {
747+
final config = toConfig();
748+
return config.toMap();
749+
}
643750
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: easy_shared_preferences
22
description: A flexible, hierarchical wrapper for flutter's shared_preferences package.
3-
version: 1.1.0
3+
version: 1.1.1
44
homepage: https://github.com/NexusDynamic/easy_shared_preferences
55
repository: https://github.com/NexusDynamic/easy_shared_preferences
66
issue_tracker: https://github.com/NexusDynamic/easy_shared_preferences/issues

0 commit comments

Comments
 (0)