Skip to content

Commit 9c8b369

Browse files
wupididurobot-piglet
authored andcommitted
Public sealed scope state
It is currently impossible to check the status of the creation or deletion of a scope. Therefore, we export the ScopeState, which reflects the current state of the scope. --- I hereby agree to the terms of the CLA available at: https://yandex.ru/legal/cla/?lang=ru --- Pull Request resolved: #22 commit_hash:3a3cba954ba16d49da888a17a19cbff83a596326
1 parent af1796b commit 9c8b369

File tree

8 files changed

+529
-247
lines changed

8 files changed

+529
-247
lines changed

.mapping.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"packages/yx_scope/test/observers_test.dart":"flutter/pro/opensource/yx_scope/packages/yx_scope/test/observers_test.dart",
5858
"packages/yx_scope/test/parent_scope_test.dart":"flutter/pro/opensource/yx_scope/packages/yx_scope/test/parent_scope_test.dart",
5959
"packages/yx_scope/test/scope_state_streamable_test.dart":"flutter/pro/opensource/yx_scope/packages/yx_scope/test/scope_state_streamable_test.dart",
60+
"packages/yx_scope/test/scope_state_test.dart":"flutter/pro/opensource/yx_scope/packages/yx_scope/test/scope_state_test.dart",
6061
"packages/yx_scope/test/scope_test.dart":"flutter/pro/opensource/yx_scope/packages/yx_scope/test/scope_test.dart",
6162
"packages/yx_scope/test/utils/test_logger.dart":"flutter/pro/opensource/yx_scope/packages/yx_scope/test/utils/test_logger.dart",
6263
"packages/yx_scope/test/utils/utils.dart":"flutter/pro/opensource/yx_scope/packages/yx_scope/test/utils/utils.dart",
Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,46 @@
1-
enum ScopeState {
2-
none,
3-
initializing,
4-
available,
5-
disposing,
1+
abstract class ScopeState<Scope> {
2+
ScopeState._();
3+
4+
factory ScopeState.none() = ScopeStateNone;
5+
factory ScopeState.initializing() = ScopeStateInitializing;
6+
factory ScopeState.available({required Scope scope}) = ScopeStateAvailable;
7+
factory ScopeState.disposing() = ScopeStateDisposing;
8+
9+
bool get none => this is ScopeStateNone;
10+
11+
bool get initializing => this is ScopeStateInitializing;
12+
13+
bool get available => this is ScopeStateAvailable;
14+
15+
bool get disposing => this is ScopeStateDisposing;
16+
}
17+
18+
class ScopeStateNone<Scope> extends ScopeState<Scope> {
19+
ScopeStateNone() : super._();
20+
21+
@override
22+
String toString() => 'ScopeState<$Scope>.none';
23+
}
24+
25+
class ScopeStateInitializing<Scope> extends ScopeState<Scope> {
26+
ScopeStateInitializing() : super._();
27+
28+
@override
29+
String toString() => 'ScopeState<$Scope>.initializing';
30+
}
31+
32+
class ScopeStateAvailable<Scope> extends ScopeState<Scope> {
33+
final Scope scope;
34+
35+
ScopeStateAvailable({required this.scope}) : super._();
36+
37+
@override
38+
String toString() => 'ScopeState<$Scope>.available';
639
}
740

8-
extension ScopeStateExt on ScopeState {
9-
bool get none => this == ScopeState.none;
41+
class ScopeStateDisposing<Scope> extends ScopeState<Scope> {
42+
ScopeStateDisposing() : super._();
1043

11-
bool get available => this == ScopeState.available;
44+
@override
45+
String toString() => 'ScopeState<$Scope>.disposing';
1246
}

packages/yx_scope/lib/src/core/scope_state_holder.dart

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
part of '../base_scope_container.dart';
22

3-
typedef StateListener<S> = void Function(S scope);
3+
typedef StateListener<S> = void Function(S? scope);
4+
5+
typedef ScopeStateListener<S> = void Function(ScopeState<S> state);
46

57
typedef RemoveStateListener = void Function();
68

79
class ScopeStateHolder<Scope> {
810
final _listeners = LinkedList<Entry<Scope>>();
9-
Scope _scope;
11+
ScopeState<Scope> _state;
1012

1113
bool _debugCanAddListeners = true;
1214

13-
ScopeStateHolder(Scope state) : _scope = state;
15+
ScopeStateHolder(this._state);
16+
17+
Scope? get scope {
18+
final state = this.state;
19+
if (state is ScopeStateAvailable<Scope>) {
20+
return state.scope;
21+
}
22+
return null;
23+
}
1424

15-
Scope get scope => _scope;
25+
ScopeState<Scope> get state => _state;
1626

17-
void _setScope(Scope state) {
18-
_scope = state;
27+
void _updateState(ScopeState<Scope> state) {
28+
_state = state;
1929

2030
final errors = <Object>[];
2131
final stackTraces = <StackTrace>[];
@@ -40,6 +50,10 @@ class ScopeStateHolder<Scope> {
4050
/// The [listener] callback will be called immediately on addition and
4151
/// synchronously whenever [state] changes.
4252
///
53+
/// Note: This method only calls the callback when the state is [ScopeStateAvailable]
54+
/// (passing the scope object) or when the scope is [ScopeStateNone] (passing null).
55+
/// It doesn't trigger for [ScopeStateInitializing] or [ScopeStateDisposing] states.
56+
///
4357
/// Set [emitImmediately] to true if you want to an immediate execution
4458
/// of the [listener] with the current state.
4559
///
@@ -50,6 +64,44 @@ class ScopeStateHolder<Scope> {
5064
RemoveStateListener listen(
5165
StateListener<Scope> listener, {
5266
bool emitImmediately = false,
67+
}) =>
68+
_listen(
69+
(state) {
70+
if (state is ScopeStateAvailable<Scope>) {
71+
listener(state.scope);
72+
} else if (state is ScopeStateNone) {
73+
listener(null);
74+
}
75+
},
76+
emitImmediately: emitImmediately,
77+
);
78+
79+
/// Subscribes to the state.
80+
///
81+
/// The [listener] callback will be called immediately on addition and
82+
/// synchronously whenever [state] changes.
83+
///
84+
/// Note: This method emits on every [ScopeState] change.
85+
///
86+
/// Set [emitImmediately] to true if you want to an immediate execution
87+
/// of the [listener] with the current state.
88+
///
89+
/// To remove this [listener], call the function returned by [listen].
90+
///
91+
/// Listeners cannot add other listeners.
92+
/// Adding and removing listeners has a constant time-complexity.
93+
RemoveStateListener listenState(
94+
ScopeStateListener<Scope> listener, {
95+
bool emitImmediately = false,
96+
}) =>
97+
_listen(
98+
(state) => listener(state),
99+
emitImmediately: emitImmediately,
100+
);
101+
102+
RemoveStateListener _listen(
103+
void Function(ScopeState<Scope> state) listener, {
104+
bool emitImmediately = false,
53105
}) {
54106
assert(() {
55107
if (!_debugCanAddListeners) {
@@ -64,7 +116,7 @@ class ScopeStateHolder<Scope> {
64116
// Intentionally unsafe call of the listener before adding to the [_listeners]
65117
// so that if there is an exception — we throw it back to consumer
66118
// with an original stacktrace without adding to the [_listeners].
67-
listener(scope);
119+
listener(state);
68120
} on Object catch (_) {
69121
rethrow;
70122
} finally {
@@ -93,7 +145,7 @@ class ScopeStateHolder<Scope> {
93145
class Entry<T> extends LinkedListEntry<Entry<T>> {
94146
Entry(this.listener);
95147

96-
final StateListener<T> listener;
148+
final ScopeStateListener<T> listener;
97149
}
98150

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

0 commit comments

Comments
 (0)