Skip to content

Commit

Permalink
Merge pull request #22 from alvarobcprado/feature/update-re-listener-…
Browse files Browse the repository at this point in the history
…modifier

Feature/update re listener modifier
  • Loading branch information
alvarobcprado authored Nov 12, 2023
2 parents 6cafc67 + 58c8966 commit b1372e0
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 78 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.1.0
* Updated `ReListenerModifier` approach

## 1.0.1
* Added `guardState` method to `ReState` to allow safe emitting of state changes without try-catch blocks

Expand Down
5 changes: 2 additions & 3 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,11 @@ class ReCounterStateActionEvent
ReCounterStateActionEvent() : super(0) {
on<IncrementCounter>(
(event) => _increment(),
modifier: ReListenerModifiers.throttleTime(const Duration(seconds: 1)),
);
on<ResetCounter>(
(event) => _reset(),
modifier: (eventFlow) => eventFlow.debounceTime(
const Duration(seconds: 1),
),
modifier: ReListenerModifiers.debounceTime(const Duration(seconds: 1)),
);

listenState(
Expand Down
46 changes: 23 additions & 23 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev"
source: hosted
version: "1.17.1"
version: "1.17.2"
cupertino_icons:
dependency: "direct main"
description:
Expand All @@ -66,47 +66,39 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "2.0.2"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
js:
dependency: transitive
description:
name: js
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.6.7"
lints:
dependency: transitive
description:
name: lints
sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "2.1.1"
matcher:
dependency: transitive
description:
name: matcher
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
version: "0.12.15"
version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.5.0"
meta:
dependency: transitive
description:
Expand Down Expand Up @@ -147,10 +139,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
stack_trace:
dependency: transitive
description:
Expand Down Expand Up @@ -187,10 +179,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
version: "0.6.0"
vector_math:
dependency: transitive
description:
Expand All @@ -199,6 +191,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
web:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
sdks:
dart: ">=3.0.0-0 <4.0.0"
dart: ">=3.1.0-185.0.dev <4.0.0"
flutter: ">=1.17.0"
39 changes: 39 additions & 0 deletions lib/re_listener_modifiers.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,42 @@
library re_listener_modifiers;

import 'package:re_state_action/src/typedefs/re_types.dart';
import 'package:rxdart/transformers.dart';

export 'package:rxdart/transformers.dart';

/// A collection of static methods that return [ReListenerModifier] functions.
/// These functions can be used to modify the behavior of a
/// [ReListenerModifier].
abstract class ReListenerModifiers {
/// Returns a [ReListenerModifier] that applies a mapper function to the
/// listener and returns the flattened result.
static ReListenerModifier<T> flatMap<T>() =>
(listener, mapper) => listener.flatMap(mapper);

/// Returns a [ReListenerModifier] that applies a mapper function to the
/// listener and returns the result of the latest mapped stream.
static ReListenerModifier<T> switchMap<T>() =>
(listener, mapper) => listener.switchMap(mapper);

/// Returns a [ReListenerModifier] that applies a mapper function to the
/// listener and ignores all events until the mapper completes.
static ReListenerModifier<T> exhaustMap<T>() =>
(listener, mapper) => listener.exhaustMap(mapper);

/// Returns a [ReListenerModifier] that applies a mapper function to the
/// listener and returns the result of the mapped stream as soon as it is
/// available.
static ReListenerModifier<T> asyncExpand<T>() =>
(listener, mapper) => listener.asyncExpand(mapper);

/// Returns a [ReListenerModifier] that applies a [Duration] [duration] to
/// the listener and debounces the events.
static ReListenerModifier<T> debounceTime<T>(Duration duration) =>
(listener, mapper) => listener.debounceTime(duration).flatMap(mapper);

/// Returns a [ReListenerModifier] that applies a [Duration] [duration] to
/// the listener and throttles the events.
static ReListenerModifier<T> throttleTime<T>(Duration duration) =>
(listener, mapper) => listener.throttleTime(duration).flatMap(mapper);
}
21 changes: 5 additions & 16 deletions lib/src/mixins/re_action_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:re_state_action/src/typedefs/re_types.dart';
import 'package:re_state_action/src/utils/re_listener_utils.dart';
import 'package:re_state_action/src/utils/re_subscription_holder.dart';
import 'package:rxdart/rxdart.dart';

Expand Down Expand Up @@ -51,18 +52,10 @@ mixin ReActionMixin<Action> on ReSubscriptionHolder {
/// [listener] is called whenever an [Action] is emitted.
///
/// [modifier] is used to modify the stream of actions before it is listened to.
///
/// [onError] is called whenever an error occurs.
///
/// [onDone] is called when the stream is closed.
///
/// [cancelOnError] is used to cancel the subscription when an error occurs.
void listenAction(
ReActionCallback<Action> listener, {
ReListenerModifier<Action>? modifier,
Function? onError,
void Function()? onDone,
bool cancelOnError = false,
}) {
if (!_isInitialized) {
throw StateError(
Expand All @@ -78,15 +71,11 @@ mixin ReActionMixin<Action> on ReSubscriptionHolder {
);
}

final listenerModifier = modifier ?? (listener) => listener;
final listenerModifier = modifier ?? reListenerModifier();
final listenerMapper = reListenerMapper(listener);

final subscription = subscriptions.add(
listenerModifier(actionStream).listen(
listener,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
),
listenerModifier(actionStream, listenerMapper).listen(null),
);
_actionSubscriptions[listener] = subscription;
}
Expand Down
20 changes: 4 additions & 16 deletions lib/src/mixins/re_event_mixin.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:re_state_action/re_state_action.dart';
import 'package:re_state_action/src/utils/re_listener_utils.dart';
import 'package:re_state_action/src/utils/re_subscription_holder.dart';
import 'package:rxdart/rxdart.dart';

Expand All @@ -24,19 +25,10 @@ mixin ReEventMixin<Event> on ReSubscriptionHolder {
/// [callback] is called whenever an event of type [T] is dispatched.
///
/// [modifier] is used to modify the stream of events before it is listened.
///
/// [onError] is called whenever an error occurs.
///
/// [onDone] is called when the stream is closed.
///
/// [cancelOnError] is used to cancel the subscription when an error occurs.
@protected
void on<T extends Event>(
ReEventCallback<T> callback, {
ReListenerModifier<T>? modifier,
Function? onError,
void Function()? onDone,
bool cancelOnError = false,
}) {
if (!_isInitialized) {
throw StateError(
Expand All @@ -62,15 +54,11 @@ mixin ReEventMixin<Event> on ReSubscriptionHolder {
_eventsMap[type] = callback;

final stream = _eventsNotifier.stream.whereType<T>();
final listenerModifier = modifier ?? (stream) => stream;
final listenerModifier = modifier ?? reListenerModifier();
final listenerMapper = reListenerMapper(callback);

final subscription = subscriptions.add(
listenerModifier(stream).listen(
callback,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
),
listenerModifier(stream, listenerMapper).listen(null),
);

subscriptions.add(subscription);
Expand Down
20 changes: 4 additions & 16 deletions lib/src/mixins/re_state_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:re_state_action/src/typedefs/re_types.dart';
import 'package:re_state_action/src/utils/re_listener_utils.dart';
import 'package:re_state_action/src/utils/re_subscription_holder.dart';
import 'package:rxdart/rxdart.dart';

Expand Down Expand Up @@ -90,18 +91,9 @@ mixin ReStateMixin<State> on ReSubscriptionHolder {
/// [listener] is called whenever a [State] is emitted.
///
/// [modifier] is used to modify the stream of state before it is listened to.
///
/// [onError] is called whenever an error occurs.
///
/// [onDone] is called when the stream is closed.
///
/// [cancelOnError] is used to cancel the subscription when an error occurs.
void listenState(
ReStateCallback<State> listener, {
ReListenerModifier<State>? modifier,
Function? onError,
void Function()? onDone,
bool cancelOnError = false,
}) {
if (!_isInitialized) {
throw StateError(
Expand All @@ -117,15 +109,11 @@ mixin ReStateMixin<State> on ReSubscriptionHolder {
);
}

final listenerModifier = modifier ?? (listener) => listener;
final listenerModifier = modifier ?? reListenerModifier();
final listenerMapper = reListenerMapper(listener);

final subscription = subscriptions.add(
listenerModifier(stateStream).listen(
listener,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
),
listenerModifier(stateStream, listenerMapper).listen(null),
);

_stateSubscriptions[listener] = subscription;
Expand Down
12 changes: 9 additions & 3 deletions lib/src/typedefs/re_types.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:flutter/widgets.dart';

/// A function that builds a widget given the current [State] and the [child].
Expand All @@ -8,12 +10,12 @@ typedef ReStateBuilder<State> = Widget Function(
);

/// A function that is called when the [State] changes.
typedef ReStateCallback<State> = void Function(
typedef ReStateCallback<State> = FutureOr<void> Function(
State state,
);

/// A function that is called when an [Action] is dispatched.
typedef ReActionCallback<Action> = void Function(
typedef ReActionCallback<Action> = FutureOr<void> Function(
Action action,
);

Expand All @@ -31,12 +33,16 @@ typedef ReActionListenerCondition<Action> = bool Function(
Action currentAction,
);

/// A function that maps the [T] to a [Stream] of [T].
typedef ReListenerMapper<T> = Stream<T> Function(T callback);

/// A function that modifies the listener to be called when the [T] changes.
typedef ReListenerModifier<T> = Stream<T> Function(
Stream<T> listener,
ReListenerMapper<T> mapper,
);

/// A function that is called when an [Event] is dispatched.
typedef ReEventCallback<Event> = void Function(
typedef ReEventCallback<Event> = FutureOr<void> Function(
Event event,
);
26 changes: 26 additions & 0 deletions lib/src/utils/re_listener_utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'dart:async';

import 'package:re_state_action/re_listener_modifiers.dart';
import 'package:re_state_action/src/typedefs/re_types.dart';

/// @nodoc
ReListenerMapper<T> reListenerMapper<T>(FutureOr<void> Function(T) callback) =>
(data) {
final controller = StreamController<T>.broadcast(sync: true);

Future<void> handleData() async {
try {
await callback(data);
} catch (_) {
rethrow;
} finally {
await controller.done;
}
}

handleData();
return controller.stream;
};

/// @nodoc
ReListenerModifier<T> reListenerModifier<T>() => ReListenerModifiers.flatMap();
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: re_state_action
description: A simple state management library for Flutter based on States and Actions managed by Streams with RxDart.
repository: https://github.com/alvarobcprado/re_state_action
issue_tracker: https://github.com/alvarobcprado/re_state_action/issues
version: 1.0.1
version: 1.1.0

environment:
sdk: ">=2.12.0 <4.0.0"
Expand Down

0 comments on commit b1372e0

Please sign in to comment.