Skip to content

Instantly share code, notes, and snippets.

@dtodt
Last active September 15, 2022 15:07
Show Gist options
  • Save dtodt/f0662d77127f4fd1345d49a3723059c1 to your computer and use it in GitHub Desktop.
Save dtodt/f0662d77127f4fd1345d49a3723059c1 to your computer and use it in GitHub Desktop.
SSP - Listenable approach [IoC Propagation]
// Package imports:
import 'package:flutter/material.dart';
import 'package:flutter_triple/flutter_triple.dart';
//
abstract class ListenableStore<Error extends Object, State extends Object>
extends ValueNotifier<Triple<Error, State>> {
ListenableStore(State state) : super(Triple(state: state));
State get state => value.state;
Error? get error => value.error;
bool get isLoading => value.isLoading;
/// Change the State value.
@protected
void update(State newState, {bool force = false}) {
var candidate = value.copyWith(
state: newState,
event: TripleEvent.state,
);
candidate = candidate.clearError();
if (force || (candidate.state != value.state)) {
value = candidate;
}
}
/// Change the loading value.
@protected
void setLoading(bool newloading, {bool force = false}) {
var candidate = value.copyWith(
isLoading: newloading,
event: TripleEvent.loading,
);
if (force || (candidate.isLoading != value.isLoading)) {
value = candidate;
}
}
/// Change the error value.
@protected
void setError(Error newError, {bool force = false}) {
var candidate = value.copyWith(
error: newError,
event: TripleEvent.error,
);
if (force || (candidate.error != value.error)) {
value = candidate;
}
}
}
// Package imports:
import 'package:core/core.dart';
// Project imports:
import 'package:auth/src/domain/domain.dart';
import 'package:auth/src/external/external.dart';
import 'package:auth/src/presentation/models/models.dart';
//
class SessionStore extends ListenableStore<Failure, SessionModel> {
final IFetchSessionUsecase _fetchSession;
final IGetCurrentUserUsecase _getCurrentUser;
final ISignInUsecase _signIn;
final ISignOutUsecase _signOut;
SessionStore(
this._fetchSession,
this._getCurrentUser,
this._signIn,
this._signOut,
) : super(SessionModel.initial());
bool get isExpired => state.isExpired;
bool get isSignedIn => state.isSignedIn;
CurrentUserEntity? get currentUser => state.currentUser;
Future<void> fetchSession() async {
final failureOrSession = await _fetchSession(NoParams());
failureOrSession.fold(
(failure) => setError(failure),
(session) => update(state.copyWith(
accessToken: session.accessToken,
)),
);
if (isSignedIn && currentUser == null) {
await getCurrentUser();
}
}
Future<void> getCurrentUser() async {
final failureOrUser = await _getCurrentUser(NoParams());
failureOrUser.fold(
(failure) => setError(failure),
(user) => update(state.copyWith(
currentUser: user,
)),
);
}
Future<void> signIn(SignInParams params) async {
final failureOrBoolean = await _signIn(params);
failureOrBoolean.fold(
(failure) => setError(failure),
(boolean) => update(SessionModel.initial().copyWith(
signedIn: boolean,
)),
);
if (isSignedIn && state.accessToken == null) {
await fetchSession();
}
}
Future<void> signOut(SignOutParams params) async {
await _signOut(params);
update(SessionModel.initial());
}
}
// Flutter imports:
import 'package:flutter/material.dart';
// Project imports:
import 'package:auth/src/presentation/stores/stores.dart';
//
class SessionWrapper extends InheritedNotifier<SessionStore> {
const SessionWrapper({
Key? key,
required SessionStore store,
required Widget child,
}) : super(key: key, notifier: store, child: child);
static SessionStore of(BuildContext context) {
final wrapper =
context.dependOnInheritedWidgetOfExactType<SessionWrapper>()!;
return wrapper.notifier!;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment