Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ThinkDigitalSoftware/737e6007f496f581285367d2d6afd42e to your computer and use it in GitHub Desktop.
Save ThinkDigitalSoftware/737e6007f496f581285367d2d6afd42e to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:fritter_for_reddit/exports.dart';
import 'package:hive/hive.dart';
/// Every time notifyListeners is called, the state is persisted to allow easy app persistence.
/// Persistence is based on Hive with a box opened with the class name.
/// If this is not desired, supply an alternative [boxName] in the constructor.
///
/// Listeners are automatically notified whenever [state] changes.
abstract class StatePersistingChangeNotifier<T extends SerializableClass>
extends ChangeNotifier {
final Completer<bool> isInitializedCompleter = Completer();
Future<bool> get initializationFuture => isInitializedCompleter.future;
Box _storage;
T _state;
T get state => _state;
set state(T state) {
_state = state;
writeState(state);
notifyListeners();
}
StatePersistingChangeNotifier({String boxName}) {
_state = initialState;
Hive.openBox(boxName ?? runtimeType.toString()).then((box) {
_storage = box;
isInitializedCompleter.complete(true);
state = fromJson(_storage.get('state')) ?? initialState;
notifyListeners();
});
}
T fromJson(Map json);
@mustCallSuper
void writeState(T state) async {
await initializationFuture;
debugPrint('Writing state: $state');
_storage.put('state', state.toJson());
}
T get initialState;
}
abstract class SerializableClass<T> {
Map<String, dynamic> toJson();
}
class SettingsNotifier extends StatePersistingChangeNotifier<SettingsState> {
@override
SettingsState get initialState => SettingsState.initial();
static SettingsNotifier of(BuildContext context, {bool listen = false}) =>
Provider.of<SettingsNotifier>(context, listen: listen);
void changeViewMode(ViewMode viewMode) =>
state = state.copyWith(viewMode: viewMode);
@override
SettingsState fromJson(Map<dynamic, dynamic> json) {
return SettingsState.fromJson(json);
}
}
@immutable
class SettingsState extends SerializableClass {
final ViewMode viewMode;
SettingsState({@required this.viewMode});
@override
String toString() {
return 'SettingsState{viewMode: $viewMode}';
}
SettingsState.initial() : viewMode = ViewMode.card;
@override
factory SettingsState.fromJson(Map json) {
if (json == null) {
return SettingsState.initial();
}
return SettingsState(
viewMode: viewModeFromString(json['viewMode']),
);
}
@override
Map<String, dynamic> toJson() => {'viewMode': viewMode.toString()};
static ViewMode viewModeFromString(String viewModeString) {
switch (viewModeString) {
case 'ViewMode.card':
return ViewMode.card;
case 'ViewMode.gallery':
return ViewMode.gallery;
default:
{
debugPrint(
'$viewModeString is not a supported ViewMode setting. Returning ViewMode.card');
return ViewMode.card;
}
}
}
SettingsState copyWith({
ViewMode viewMode,
}) =>
SettingsState(
viewMode: viewMode ?? this.viewMode,
);
}
@ThinkDigitalSoftware
Copy link
Author

@loicgeek, yeah, I use copyWith as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment