From e3f09d41e08583b594806d2d6b61de15765391eb Mon Sep 17 00:00:00 2001 From: Plague Fox Date: Wed, 16 Oct 2024 15:22:04 +0400 Subject: [PATCH] Add context --- lib/control.dart | 7 ++- lib/src/concurrency/concurrency.dart | 3 ++ .../concurrent_controller_handler.dart | 16 ++++++- .../droppable_controller_handler.dart | 14 ++++++ .../sequential_controller_handler.dart | 14 ++++++ lib/src/controller.dart | 23 ++++++++-- lib/src/handler_context.dart | 43 +++++++++++++++++++ lib/src/state_controller.dart | 5 +++ pubspec.yaml | 6 +-- 9 files changed, 120 insertions(+), 11 deletions(-) create mode 100644 lib/src/concurrency/concurrency.dart rename lib/src/{ => concurrency}/concurrent_controller_handler.dart (86%) rename lib/src/{ => concurrency}/droppable_controller_handler.dart (82%) rename lib/src/{ => concurrency}/sequential_controller_handler.dart (89%) create mode 100644 lib/src/handler_context.dart diff --git a/lib/control.dart b/lib/control.dart index 1541dc1..c07da81 100644 --- a/lib/control.dart +++ b/lib/control.dart @@ -1,9 +1,8 @@ -library control; +library; -export 'package:control/src/concurrent_controller_handler.dart'; +export 'package:control/src/concurrency/concurrency.dart'; export 'package:control/src/controller.dart' hide IController; export 'package:control/src/controller_scope.dart' hide ControllerScope$Element; -export 'package:control/src/droppable_controller_handler.dart'; -export 'package:control/src/sequential_controller_handler.dart'; +export 'package:control/src/handler_context.dart' show HandlerContext; export 'package:control/src/state_consumer.dart'; export 'package:control/src/state_controller.dart' hide IStateController; diff --git a/lib/src/concurrency/concurrency.dart b/lib/src/concurrency/concurrency.dart new file mode 100644 index 0000000..251dc8f --- /dev/null +++ b/lib/src/concurrency/concurrency.dart @@ -0,0 +1,3 @@ +export 'package:control/src/concurrency/concurrent_controller_handler.dart'; +export 'package:control/src/concurrency/droppable_controller_handler.dart'; +export 'package:control/src/concurrency/sequential_controller_handler.dart'; diff --git a/lib/src/concurrent_controller_handler.dart b/lib/src/concurrency/concurrent_controller_handler.dart similarity index 86% rename from lib/src/concurrent_controller_handler.dart rename to lib/src/concurrency/concurrent_controller_handler.dart index c5864ba..21c3026 100644 --- a/lib/src/concurrent_controller_handler.dart +++ b/lib/src/concurrency/concurrent_controller_handler.dart @@ -1,10 +1,11 @@ import 'dart:async'; import 'package:control/src/controller.dart'; +import 'package:control/src/handler_context.dart'; import 'package:flutter/foundation.dart' show SynchronousFuture; import 'package:meta/meta.dart'; -/// Sequential controller concurrency +/// Concurrent controller concurrency base mixin ConcurrentControllerHandler on Controller { @override @nonVirtual @@ -22,6 +23,8 @@ base mixin ConcurrentControllerHandler on Controller { Future Function() handler, { Future Function(Object error, StackTrace stackTrace)? error, Future Function()? done, + String? name, + Map? context, }) { if (isDisposed) return Future.value(null); _$processingCalls++; @@ -46,6 +49,14 @@ base mixin ConcurrentControllerHandler on Controller { _done = null; } + final handlerContext = HandlerContextImpl( + controller: this, + name: name ?? '$runtimeType.handler#${handler.runtimeType}', + context: { + ...?context, + }, + ); + runZonedGuarded( () async { try { @@ -63,6 +74,9 @@ base mixin ConcurrentControllerHandler on Controller { } }, onError, + zoneValues: { + HandlerContext.key: handlerContext, + }, ); return completer.future; diff --git a/lib/src/droppable_controller_handler.dart b/lib/src/concurrency/droppable_controller_handler.dart similarity index 82% rename from lib/src/droppable_controller_handler.dart rename to lib/src/concurrency/droppable_controller_handler.dart index 42bee35..e4318b1 100644 --- a/lib/src/droppable_controller_handler.dart +++ b/lib/src/concurrency/droppable_controller_handler.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:control/src/controller.dart'; +import 'package:control/src/handler_context.dart'; import 'package:flutter/foundation.dart' show SynchronousFuture; import 'package:meta/meta.dart'; @@ -22,6 +23,8 @@ base mixin DroppableControllerHandler on Controller { Future Function() handler, { Future Function(Object error, StackTrace stackTrace)? error, Future Function()? done, + String? name, + Map? context, }) { if (isDisposed || isProcessing) return Future.value(null); _$processingCalls++; @@ -46,6 +49,14 @@ base mixin DroppableControllerHandler on Controller { _done = null; } + final handlerContext = HandlerContextImpl( + controller: this, + name: name ?? '$runtimeType.handler#${handler.runtimeType}', + context: { + ...?context, + }, + ); + runZonedGuarded( () async { try { @@ -63,6 +74,9 @@ base mixin DroppableControllerHandler on Controller { } }, onError, + zoneValues: { + HandlerContext.key: handlerContext, + }, ); return completer.future; diff --git a/lib/src/sequential_controller_handler.dart b/lib/src/concurrency/sequential_controller_handler.dart similarity index 89% rename from lib/src/sequential_controller_handler.dart rename to lib/src/concurrency/sequential_controller_handler.dart index 271cfd4..eb9896c 100644 --- a/lib/src/sequential_controller_handler.dart +++ b/lib/src/concurrency/sequential_controller_handler.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:collection'; import 'package:control/src/controller.dart'; +import 'package:control/src/handler_context.dart'; import 'package:flutter/foundation.dart' show SynchronousFuture; import 'package:meta/meta.dart'; @@ -24,6 +25,8 @@ base mixin SequentialControllerHandler on Controller { Future Function() handler, { Future Function(Object error, StackTrace stackTrace)? error, Future Function()? done, + String? name, + Map? context, }) => _eventQueue.push( () { @@ -40,6 +43,14 @@ base mixin SequentialControllerHandler on Controller { } } + final handlerContext = HandlerContextImpl( + controller: this, + name: name ?? '$runtimeType.handler#${handler.runtimeType}', + context: { + ...?context, + }, + ); + runZonedGuarded( () async { if (isDisposed) return; @@ -58,6 +69,9 @@ base mixin SequentialControllerHandler on Controller { } }, onError, + zoneValues: { + HandlerContext.key: handlerContext, + }, ); return completer.future; diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 1b077e7..e403c30 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -1,7 +1,8 @@ import 'dart:async'; -import 'package:control/control.dart'; +import 'package:control/src/handler_context.dart'; import 'package:control/src/registry.dart'; +import 'package:control/src/state_controller.dart'; import 'package:flutter/foundation.dart' show ChangeNotifier, Listenable, VoidCallback; import 'package:meta/meta.dart'; @@ -37,11 +38,19 @@ abstract interface class IController implements Listenable { /// Depending on the implementation, the handler may be executed /// sequentially, concurrently, dropped and etc. /// + /// The [name] parameter is used to identify the handler. + /// The [context] parameter is used to pass additional + /// information to the handler's zone. + /// /// See: /// - [ConcurrentControllerHandler] - handler that executes concurrently /// - [SequentialControllerHandler] - handler that executes sequentially /// - [DroppableControllerHandler] - handler that drops the request when busy - void handle(Future Function() handler); + void handle( + Future Function() handler, { + String? name, + Map? context, + }); } /// Controller observer @@ -74,6 +83,10 @@ abstract base class Controller with ChangeNotifier implements IController { ); } + /// Get the handler's context from the current zone. + static HandlerContext? getContext(Controller controller) => + HandlerContext.zoned(); + /// Controller observer static IControllerObserver? observer; @@ -101,7 +114,11 @@ abstract base class Controller with ChangeNotifier implements IController { @protected @override - Future handle(Future Function() handler); + Future handle( + Future Function() handler, { + String? name, + Map? context, + }); @protected @nonVirtual diff --git a/lib/src/handler_context.dart b/lib/src/handler_context.dart new file mode 100644 index 0000000..4bd1ac6 --- /dev/null +++ b/lib/src/handler_context.dart @@ -0,0 +1,43 @@ +import 'dart:async'; + +import 'package:control/src/controller.dart'; +import 'package:meta/meta.dart'; + +/// Handler's context. +abstract interface class HandlerContext { + /// Key to access the handler's context. + static const Object key = #handler; + + /// Get the handler's context from the current zone. + static HandlerContext? zoned() => switch (Zone.current[HandlerContext.key]) { + HandlerContext context => context, + _ => null, + }; + + /// Controller that the handler is attached to. + abstract final Controller controller; + + /// Name of the handler. + abstract final String name; + + /// Extra meta information about the handler. + abstract final Map context; +} + +@internal +final class HandlerContextImpl implements HandlerContext { + HandlerContextImpl({ + required this.controller, + required this.name, + required this.context, + }); + + @override + final Controller controller; + + @override + final String name; + + @override + final Map context; +} diff --git a/lib/src/state_controller.dart b/lib/src/state_controller.dart index 3b3b08d..147bbae 100644 --- a/lib/src/state_controller.dart +++ b/lib/src/state_controller.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:control/src/controller.dart'; +import 'package:control/src/handler_context.dart'; import 'package:flutter/foundation.dart'; import 'package:meta/meta.dart'; @@ -28,6 +29,10 @@ abstract base class StateController extends Controller /// State controller StateController({required S initialState}) : _$state = initialState; + /// Get the handler's context from the current zone. + static HandlerContext? getContext(Controller controller) => + HandlerContext.zoned(); + @override @nonVirtual S get state => _$state; diff --git a/pubspec.yaml b/pubspec.yaml index 9af1540..0c88b47 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: control description: "Simple state management for Flutter with concurrency support." -version: 0.1.0 +version: 0.2.0 homepage: https://github.com/PlugFox/control @@ -34,7 +34,7 @@ platforms: # path: example.png environment: - sdk: '>=3.0.0 <4.0.0' + sdk: '>=3.4.0 <4.0.0' flutter: ">=3.0.0" dependencies: @@ -45,4 +45,4 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.0 + flutter_lints: ^5.0.0