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,
);
}
@loicgeek
Copy link

loicgeek commented Apr 9, 2020

hey Jonathan yes, for the second one, i have also use that technique. then main purpose was to add a from the constructor ,

listenStoreEditorBloc() {
    storeEditorBloc.listen((state) {
      print('editorstate in  myStore : $state');
      if (state.isStoredUpdated) {
        this.add(AddState(state: this.state.copyWith(store: state.store)));
      }
    });
  }

and then in the mapEventoState used

@override
 Stream<MystoreState> mapEventToState(
   MystoreEvent event,
 ) async* {
   if (event is AddState) {
     yield event.state;
   }

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

 if (event is CreateStore) {
      yield this.state.copyWith(creating: true);
      try {
        StoreModel store = await storeService.createStore(event.data);
        yield MystoreState.created(store: store);
      } on DioError catch (e) {
        print(e);
        yield this.state.copyWith(
              creating: false,
              message: extractMessage(e),
              creatingFailed: true,
            );
      } catch (e) {
        yield this.state.copyWith(
              creating: false,
              message: extractMessage(e),
              creatingFailed: true,
            );
      }
    } 

@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