Last active
April 9, 2020 22:02
-
-
Save ThinkDigitalSoftware/737e6007f496f581285367d2d6afd42e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | |
); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hey Jonathan yes, for the second one, i have also use that technique. then main purpose was to add a from the constructor ,
and then in the mapEventoState used
In fact there are lot of boilerplate code that we could avoid when using flutter_bloc, like creating a class for each state we would like 🤨 , I use abusively this bloc of code with the copyWith method