Skip to content

Commit

Permalink
Merge pull request #5 from emanuel-braz/issue/3
Browse files Browse the repository at this point in the history
feat: add distinct property to handlers
  • Loading branch information
emanuel-braz authored Feb 7, 2022
2 parents b1aebc9 + bb6ab36 commit 73a2f1a
Show file tree
Hide file tree
Showing 12 changed files with 696 additions and 528 deletions.
3 changes: 2 additions & 1 deletion lib/flutter_micro_app.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
library flutter_micro_app;

export 'src/controllers/micro_app_event_controller.dart';
export 'src/controllers/app_event/micro_app_event_controller.dart';
export 'src/controllers/navigator_controller.dart';
export 'src/core/micro_app.dart';
export 'src/core/micro_host.dart';
export 'src/core/micro_page.dart';
export 'src/core/micro_widget.dart';
export 'src/entities/events/micro_app_event.dart';
export 'src/entities/events/micro_app_event_handler.dart';
export 'src/entities/micro_app_preferences.dart';
export 'src/entities/router/base_route.dart';
export 'src/presentation/widgets/micro_widget_builder.dart';
Expand Down
97 changes: 97 additions & 0 deletions lib/src/controllers/app_event/micro_app_event_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// ignore_for_file: cancel_subscriptions
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_micro_app/flutter_micro_app.dart';
import 'package:flutter_micro_app/src/services/native_service.dart';

import 'micro_app_event_helper.dart';

/// [MicroAppEventController]
class MicroAppEventController {
final String _channel = Constants.channelAppEvents;
final StreamController<MicroAppEvent> _controller =
StreamController.broadcast();
late MicroAppNativeService _microAppNativeService;
late MicroAppEventHelper _handlerRegisterHelper;

/// Used to listen all micro app events
MicroAppEventSubscription get onEvent => _controller.stream.listen;

/// Can be used to filter events and listen to app events, anywhere
Stream<MicroAppEvent> get stream => _controller.stream;
bool get hasSubscribers => _controller.hasListener;
bool get hasHandlers => _handlers.isNotEmpty;

final Map<MicroAppEventHandler, StreamSubscription<MicroAppEvent>> _handlers =
{};

/// get all handlers and subscriptions availables
Map<MicroAppEventHandler, StreamSubscription<MicroAppEvent>> get handlers =>
_handlers;

/// Factory instance
factory MicroAppEventController() => instance;

/// MicroAppController instance
static MicroAppEventController instance = MicroAppEventController._();
MicroAppEventController._() {
_handlerRegisterHelper = MicroAppEventHelper();
_microAppNativeService = MicroAppNativeService(_channel,
methodCallHandler: (MethodCall call) async {
_controller
.add(MicroAppEvent(name: call.method, payload: call.arguments));
});
}

/// ⚠️ It is used only for unit tests purposes
factory MicroAppEventController.$testOnlyPurpose() =>
MicroAppEventController._();

/// [MicroAppEvent]
void emit(MicroAppEvent event) {
if (MicroAppPreferences.config.nativeEventsEnabled) {
_microAppNativeService.emit(
Constants.methodMicroAppEvent, event.toString());
}
_controller.add(event);
}

/// register handler
StreamSubscription<MicroAppEvent>? registerHandler<T>(
MicroAppEventHandler? handler) {
if (handler == null) return null;
final subscription =
_handlerRegisterHelper.registerHandler(stream, handler);
_handlers.putIfAbsent(handler, () => subscription);
return subscription;
}

/// pauseAllHandlers
void pauseAllHandlers() =>
_handlerRegisterHelper.pauseAllSubscriptions(_handlers);

/// resumeAllHandlers
void resumeAllHandlers() =>
_handlerRegisterHelper.resumeAllSubscriptions(_handlers);

/// unregisterAllHandlers
Future<void> unregisterAllHandlers() =>
_handlerRegisterHelper.unregisterAllSubscriptions(_handlers);

/// unregisterHandler
Future<void> unregisterHandler({String? id, List<String>? channels}) =>
_handlerRegisterHelper.unregisterSubscription(_handlers,
id: id, channels: channels);

/// hasHandler
bool hasHandler({String? id, List<String>? channels}) =>
_handlerRegisterHelper
.findHandlerEntries(handlers, id: id, channels: channels)
.isNotEmpty;

/// dispose controller (do not dispose this, if there is not a very specific situation case)
void dispose() {
_controller.close();
}
}
Original file line number Diff line number Diff line change
@@ -1,128 +1,15 @@
// ignore_for_file: cancel_subscriptions
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_micro_app/flutter_micro_app.dart';
import 'package:flutter_micro_app/src/services/native_service.dart';

/// [MicroAppEventHandler]
class MicroAppEventHandler<T> extends EventChannelsEquatable {
final String? id;
final MicroAppEventOnEvent onEvent;
final MicroAppEventOnDone? onDone;
final MicroAppEventOnError? onError;
final bool? cancelOnError;

const MicroAppEventHandler(
this.onEvent, {
this.onDone,
this.onError,
this.cancelOnError,
List<String> channels = const [],
this.id,
}) : super(channels);

@override
List<Object?> get props =>
[onEvent, onDone, onError, cancelOnError, channels, id];
}

/// [MicroAppEventController]
class MicroAppEventController {
final String _channel = Constants.channelAppEvents;
final StreamController<MicroAppEvent> _controller =
StreamController.broadcast();
late MicroAppNativeService _microAppNativeService;
late HandlerRegisterHelper _handlerRegisterHelper;

/// Used to listen all micro app events
MicroAppEventSubscription get onEvent => _controller.stream.listen;

/// Can be used to filter events and listen to app events, anywhere
Stream<MicroAppEvent> get stream => _controller.stream;
bool get hasSubscribers => _controller.hasListener;
bool get hasHandlers => _handlers.isNotEmpty;

final Map<MicroAppEventHandler, StreamSubscription<MicroAppEvent>> _handlers =
{};

/// get all handlers and subscriptions availables
Map<MicroAppEventHandler, StreamSubscription<MicroAppEvent>> get handlers =>
_handlers;

/// Factory instance
factory MicroAppEventController() => instance;

/// MicroAppController instance
static MicroAppEventController instance = MicroAppEventController._();
MicroAppEventController._() {
_handlerRegisterHelper = HandlerRegisterHelper();
_microAppNativeService = MicroAppNativeService(_channel,
methodCallHandler: (MethodCall call) async {
_controller
.add(MicroAppEvent(name: call.method, payload: call.arguments));
});
}

/// ⚠️ It is used only for unit tests purposes
factory MicroAppEventController.$testOnlyPurpose() =>
MicroAppEventController._();

/// [MicroAppEvent]
void emit(MicroAppEvent event) {
if (MicroAppPreferences.config.nativeEventsEnabled) {
_microAppNativeService.emit(
Constants.methodMicroAppEvent, event.toString());
}
_controller.add(event);
}

/// register handler
StreamSubscription<MicroAppEvent>? registerHandler<T>(
MicroAppEventHandler? handler) {
if (handler == null) return null;
final subscription =
_handlerRegisterHelper.registerHandler(stream, handler);
_handlers.putIfAbsent(handler, () => subscription);
return subscription;
}

/// pauseAllHandlers
void pauseAllHandlers() =>
_handlerRegisterHelper.pauseAllSubscriptions(_handlers);
import '../../entities/events/micro_app_event.dart';
import '../../entities/events/micro_app_event_handler.dart';

/// resumeAllHandlers
void resumeAllHandlers() =>
_handlerRegisterHelper.resumeAllSubscriptions(_handlers);

/// unregisterAllHandlers
Future<void> unregisterAllHandlers() =>
_handlerRegisterHelper.unregisterAllSubscriptions(_handlers);

/// unregisterHandler
Future<void> unregisterHandler({String? id, List<String>? channels}) =>
_handlerRegisterHelper.unregisterSubscription(_handlers,
id: id, channels: channels);

/// hasHandler
bool hasHandler({String? id, List<String>? channels}) =>
_handlerRegisterHelper
.findHandlerEntries(handlers, id: id, channels: channels)
.isNotEmpty;

/// dispose controller (do not dispose this, if there is not a very specific situation case)
void dispose() {
_controller.close();
}
}

class HandlerRegisterHelper {
class MicroAppEventHelper {
/// registerHandler
StreamSubscription<MicroAppEvent> registerHandler(
Stream<MicroAppEvent> stream, MicroAppEventHandler handler) {
return stream
// TODO: implementar distinct
// .distinct((previous, event) => event.distinct)
.distinct((previousEvent, currentEvent) =>
handleDistinct(handler, previousEvent, currentEvent))
.where((event) => handlerHasSameEventTypeOrDynamic(handler, event))
.where((event) => containsSomeChannelsOrHandlerHasNoChannels(
handler.channels, event.channels))
Expand Down Expand Up @@ -203,6 +90,12 @@ class HandlerRegisterHelper {
return entries;
}

bool handleDistinct(MicroAppEventHandler handler, MicroAppEvent previousEvent,
MicroAppEvent currentEvent) {
if (handler.distinct == false) return false;
return !(handler.distinct && previousEvent != currentEvent);
}

bool handlerHasSameEventTypeOrDynamic(
MicroAppEventHandler handler, MicroAppEvent event) {
final handlerGenericType = handler.runtimeType.toString();
Expand Down
2 changes: 1 addition & 1 deletion lib/src/core/micro_app.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import '../controllers/micro_app_event_controller.dart';
import '../entities/events/micro_app_event_handler.dart';
import '../entities/router/base_route.dart';
import '../utils/typedefs.dart';
import 'micro_page.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/core/micro_host.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:dart_log/dart_log.dart';
import 'package:flutter/material.dart';

import '../controllers/micro_app_event_controller.dart';
import '../controllers/app_event/micro_app_event_controller.dart';
import '../controllers/navigator_controller.dart';
import '../utils/typedefs.dart';
import 'micro_app.dart';
Expand Down
24 changes: 24 additions & 0 deletions lib/src/entities/events/micro_app_event_handler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import '../../../flutter_micro_app.dart';

/// [MicroAppEventHandler]
class MicroAppEventHandler<T> extends EventChannelsEquatable {
final String? id;
final MicroAppEventOnEvent onEvent;
final MicroAppEventOnDone? onDone;
final MicroAppEventOnError? onError;
final bool? cancelOnError;
final bool distinct;

const MicroAppEventHandler(this.onEvent,
{this.onDone,
this.onError,
this.cancelOnError,
List<String> channels = const [],
this.id,
this.distinct = true})
: super(channels);

@override
List<Object?> get props =>
[onEvent, onDone, onError, cancelOnError, channels, id, distinct];
}
3 changes: 2 additions & 1 deletion lib/src/presentation/widgets/micro_widget_builder.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/widgets.dart';

import '../../../flutter_micro_app.dart';
import '../../controllers/app_event/micro_app_event_helper.dart';
import '../../utils/extensions/list_extension.dart';

class MicroAppWidgetBuilder<T> extends StatefulWidget {
Expand All @@ -22,7 +23,7 @@ class MicroAppWidgetBuilder<T> extends StatefulWidget {

class _MicroAppWidgetBuilderState<T> extends State<MicroAppWidgetBuilder> {
Stream<MicroAppEvent>? stream;
final helper = HandlerRegisterHelper();
final helper = MicroAppEventHelper();

@override
void initState() {
Expand Down
Loading

0 comments on commit 73a2f1a

Please sign in to comment.