Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 42 additions & 8 deletions packages/yx_scope/lib/src/core/scope_state.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,46 @@
enum ScopeState {
none,
initializing,
available,
disposing,
abstract class ScopeState<Scope> {
ScopeState._();

factory ScopeState.none() = ScopeStateNone;
factory ScopeState.initializing() = ScopeStateInitializing;
factory ScopeState.available({required Scope scope}) = ScopeStateAvailable;
factory ScopeState.disposing() = ScopeStateDisposing;

bool get none => this is ScopeStateNone;

bool get initializing => this is ScopeStateInitializing;

bool get available => this is ScopeStateAvailable;

bool get disposing => this is ScopeStateDisposing;
}

class ScopeStateNone<Scope> extends ScopeState<Scope> {
ScopeStateNone() : super._();

@override
String toString() => 'ScopeState<$Scope>.none';
}

class ScopeStateInitializing<Scope> extends ScopeState<Scope> {
ScopeStateInitializing() : super._();

@override
String toString() => 'ScopeState<$Scope>.initializing';
}

class ScopeStateAvailable<Scope> extends ScopeState<Scope> {
final Scope scope;

ScopeStateAvailable({required this.scope}) : super._();

@override
String toString() => 'ScopeState<$Scope>.available';
}

extension ScopeStateExt on ScopeState {
bool get none => this == ScopeState.none;
class ScopeStateDisposing<Scope> extends ScopeState<Scope> {
ScopeStateDisposing() : super._();

bool get available => this == ScopeState.available;
@override
String toString() => 'ScopeState<$Scope>.disposing';
}
68 changes: 60 additions & 8 deletions packages/yx_scope/lib/src/core/scope_state_holder.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
part of '../base_scope_container.dart';

typedef StateListener<S> = void Function(S scope);
typedef StateListener<S> = void Function(S? scope);

typedef ScopeStateListener<S> = void Function(ScopeState<S> state);

typedef RemoveStateListener = void Function();

class ScopeStateHolder<Scope> {
final _listeners = LinkedList<Entry<Scope>>();
Scope _scope;
ScopeState<Scope> _state;

bool _debugCanAddListeners = true;

ScopeStateHolder(Scope state) : _scope = state;
ScopeStateHolder(this._state);

Scope? get scope {
final state = this.state;
if (state is ScopeStateAvailable<Scope>) {
return state.scope;
}
return null;
}

Scope get scope => _scope;
ScopeState<Scope> get state => _state;

void _setScope(Scope state) {
_scope = state;
void _updateState(ScopeState<Scope> state) {
_state = state;

final errors = <Object>[];
final stackTraces = <StackTrace>[];
Expand All @@ -40,6 +50,10 @@ class ScopeStateHolder<Scope> {
/// The [listener] callback will be called immediately on addition and
/// synchronously whenever [state] changes.
///
/// Note: This method only calls the callback when the state is [ScopeStateAvailable]
/// (passing the scope object) or when the scope is [ScopeStateNone] (passing null).
/// It doesn't trigger for [ScopeStateInitializing] or [ScopeStateDisposing] states.
///
/// Set [emitImmediately] to true if you want to an immediate execution
/// of the [listener] with the current state.
///
Expand All @@ -50,6 +64,44 @@ class ScopeStateHolder<Scope> {
RemoveStateListener listen(
StateListener<Scope> listener, {
bool emitImmediately = false,
}) =>
_listen(
(state) {
if (state is ScopeStateAvailable<Scope>) {
listener(state.scope);
} else if (state is ScopeStateNone) {
listener(null);
}
},
emitImmediately: emitImmediately,
);

/// Subscribes to the state.
///
/// The [listener] callback will be called immediately on addition and
/// synchronously whenever [state] changes.
///
/// Note: This method emits on every [ScopeState] change.
///
/// Set [emitImmediately] to true if you want to an immediate execution
/// of the [listener] with the current state.
///
/// To remove this [listener], call the function returned by [listen].
///
/// Listeners cannot add other listeners.
/// Adding and removing listeners has a constant time-complexity.
RemoveStateListener listenState(
ScopeStateListener<Scope> listener, {
bool emitImmediately = false,
}) =>
_listen(
(state) => listener(state),
emitImmediately: emitImmediately,
);

RemoveStateListener _listen(
void Function(ScopeState<Scope> state) listener, {
bool emitImmediately = false,
}) {
assert(() {
if (!_debugCanAddListeners) {
Expand All @@ -64,7 +116,7 @@ class ScopeStateHolder<Scope> {
// Intentionally unsafe call of the listener before adding to the [_listeners]
// so that if there is an exception — we throw it back to consumer
// with an original stacktrace without adding to the [_listeners].
listener(scope);
listener(state);
} on Object catch (_) {
rethrow;
} finally {
Expand Down Expand Up @@ -93,7 +145,7 @@ class ScopeStateHolder<Scope> {
class Entry<T> extends LinkedListEntry<Entry<T>> {
Entry(this.listener);

final StateListener<T> listener;
final ScopeStateListener<T> listener;
}

/// An error thrown when tried to update the state of a [ScopeStateHolder],
Expand Down
Loading