Persisted Signals
When you need to store the state of your signals between app launches you can create a PersistedSignal from this example code.
You need to have a store that can be SharedPreferences, SQLite, in memory, or any other storage solution. The store just needs to be able to save and restore the data.
abstract class KeyValueStore {  Future<void> setItem(String key, String value);  Future<String?> getItem(String key);  Future<void> removeItem(String key);}You can create an in-memory store for testing:
class InMemoryStore implements KeyValueStore {  final Map<String, String> _store = {};
  @override  Future<String?> getItem(String key) async {    return _store[key];  }
  @override  Future<void> removeItem(String key) async {    _store.remove(key);  }
  @override  Future<void> setItem(String key, String value) async {    _store[key] = value;  }}For this example we are going to be using SharedPreferences:
class SharedPreferencesStore implements KeyValueStore {  SharedPreferencesStore();
  SharedPreferences? prefs;
  Future<SharedPreferences> init() async {    prefs ??= await SharedPreferences.getInstance();    return prefs!;  }
  @override  Future<String?> getItem(String key) async {    final prefs = await init();    return prefs.getString(key);  }
  @override  Future<void> removeItem(String key) async {    final prefs = await init();    prefs.remove(key);  }
  @override  Future<void> setItem(String key, String value) async {    final prefs = await init();    prefs.setString(key, value);  }}By default we can encode and decode the value to and from JSON:
abstract class PersistedSignal<T> extends FlutterSignal<T>    with PersistedSignalMixin<T> {  PersistedSignal(    super.internalValue, {    super.autoDispose,    super.debugLabel,    required this.key,    required this.store,  });
  @override  final String key;
  @override  final KeyValueStore store;}
mixin PersistedSignalMixin<T> on Signal<T> {  String get key;  KeyValueStore get store;
  bool loaded = false;
  Future<void> init() async {    try {      final val = await load();      super.value = val;    } catch (e) {      debugPrint('Error loading persisted signal: $e');    } finally {      loaded = true;    }  }
  @override  T get value {    if (!loaded) init().ignore();    return super.value;  }
  @override  set value(T value) {    super.value = value;    save(value).ignore();  }
  Future<T> load() async {    final val = await store.getItem(key);    if (val == null) return value;    return decode(val);  }
  Future<void> save(T value) async {    final str = encode(value);    await store.setItem(key, str);  }
  T decode(String value) => jsonDecode(value);
  String encode(T value) => jsonEncode(value);}This can work in a lot of cases, but we might want to handle specific cases like enums:
class EnumSignal<T extends Enum> extends PersistedSignal<T> {  EnumSignal(super.val, String key, this.values)      : super(          key: key,          store: SharedPreferencesStore(),        );
  final List<T> values;
  @override  T decode(String value) => values.firstWhere((e) => e.name == value);
  @override  String encode(T value) => value.name;}Or if you are in Flutter we can persist color values:
class ColorSignal extends PersistedSignal<Color> {  ColorSignal(super.val, String key)      : super(          key: key,          store: SharedPreferencesStore(),        );
  @override  String encode(Color value) => value.value.toString();
  @override  Color decode(String value) => Color(int.parse(value));}Example
class AppTheme {  final sourceColor = ColorSignal(    Colors.blue,    'sourceColor', );  final themeMode = EnumSignal(    ThemeMode.system,    'themeMode',    ThemeMode.values, );
  static AppTheme instance = AppTheme();
  Future<void> init() async {    await Future.wait([      sourceColor.init(),      themeMode.init(),    ]);  }}
void main() async{    final theme = AppTheme.instance;    // We need to init before running the app to prevent the theme from flickering    await theme.init();    runApp(MyApp());}
class MyApp extends StatelessWidget {  @override  Widget build(BuildContext context) {    final theme = AppTheme.instance;    return MaterialApp(      theme: ThemeData.light().copyWith(        colorScheme: ColorScheme.fromSeed(          seedColor: theme.sourceColor.watch(context),          brightness: Brightness.light,        ),      ),      darkTheme: ThemeData.dark().copyWith(        colorScheme: ColorScheme.fromSeed(          seedColor: theme.sourceColor.watch(context),          brightness: Brightness.dark,        ),      ),      themeMode: theme.themeMode.watch(context),      home: Scaffold(        appBar: AppBar(          title: Text('Persisted Signals'),        ),        body: Center(          child: Column(            mainAxisAlignment: MainAxisAlignment.center,            children: <Widget>[              ElevatedButton(                onPressed: () {                  theme.sourceColor.value = Colors.red;                },                child: Text('Change Color'),              ),              ElevatedButton(                onPressed: () {                  theme.themeMode.value = ThemeMode.dark;                },                child: Text('Change Theme'),              ),            ],          ),        ),      ),    );  }}Now when we run the app and make changes, if we close the app and reopen it, the changes will persist offline.