Skip to content

Commit

Permalink
feat: add option to subscribe to overlay status: overlay showing or o…
Browse files Browse the repository at this point in the history
…verlay closed
  • Loading branch information
serhiisdev committed Feb 7, 2024
1 parent 2857f75 commit 4174ffe
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package flutter.overlay.window.flutter_overlay_window;

import androidx.annotation.Nullable;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.MethodChannel;

public abstract class CachedMessageChannels {
@Nullable
public static BasicMessageChannel<Object> mainAppMessageChannel;
public static MethodChannel mainAppMessageChannel;
@Nullable
public static BasicMessageChannel<Object> overlayMessageChannel;
public static MethodChannel overlayMessageChannel;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.JSONMessageCodec;
import io.flutter.plugin.common.JSONMethodCodec;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
Expand Down Expand Up @@ -165,37 +164,37 @@ private void registerMessageChannel(boolean isMainAppEngine) {
private void unregisterMessageChannel(boolean isMainAppEngine) {
if(isMainAppEngine) {
if (CachedMessageChannels.mainAppMessageChannel == null) return;
CachedMessageChannels.mainAppMessageChannel.setMessageHandler(null);
CachedMessageChannels.mainAppMessageChannel.setMethodCallHandler(null);
CachedMessageChannels.mainAppMessageChannel = null;
} else {
if(CachedMessageChannels.overlayMessageChannel == null) return;
CachedMessageChannels.overlayMessageChannel.setMessageHandler(null);
CachedMessageChannels.overlayMessageChannel.setMethodCallHandler(null);
CachedMessageChannels.overlayMessageChannel = null;
}
}

private void registerOverlayMessageChannel(io.flutter.plugin.common.BinaryMessenger overlyEngineBinaryMessenger) {
BasicMessageChannel<Object> overlayMessageChannel = new BasicMessageChannel<>(overlyEngineBinaryMessenger, OverlayConstants.MESSENGER_TAG, JSONMessageCodec.INSTANCE);
overlayMessageChannel.setMessageHandler((message, reply) -> {
MethodChannel overlayMessageChannel = new MethodChannel(overlyEngineBinaryMessenger, OverlayConstants.MESSENGER_TAG, JSONMethodCodec.INSTANCE);
overlayMessageChannel.setMethodCallHandler((call, result) -> {
if (CachedMessageChannels.mainAppMessageChannel == null) {
reply.reply(false);
result.success(false);
return;
}
CachedMessageChannels.mainAppMessageChannel.send(message);
reply.reply(true);
CachedMessageChannels.mainAppMessageChannel.invokeMethod("message", call.arguments);
result.success(true);
});
CachedMessageChannels.overlayMessageChannel = overlayMessageChannel;
}

private void registerMainAppMessageChannel(io.flutter.plugin.common.BinaryMessenger mainAppEngineBinaryMessenger) {
BasicMessageChannel<Object> mainAppMessageChannel = new BasicMessageChannel<>(mainAppEngineBinaryMessenger, OverlayConstants.MESSENGER_TAG, JSONMessageCodec.INSTANCE);
mainAppMessageChannel.setMessageHandler((message, reply) -> {
MethodChannel mainAppMessageChannel = new MethodChannel(mainAppEngineBinaryMessenger, OverlayConstants.MESSENGER_TAG, JSONMethodCodec.INSTANCE);
mainAppMessageChannel.setMethodCallHandler((call, result) -> {
if (CachedMessageChannels.overlayMessageChannel == null) {
reply.reply(false);
result.success(false);
return;
}
CachedMessageChannels.overlayMessageChannel.send(message);
reply.reply(true);
CachedMessageChannels.overlayMessageChannel.invokeMethod("message", call.arguments);
result.success(true);
});
CachedMessageChannels.mainAppMessageChannel = mainAppMessageChannel;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public void onDestroy() {
flutterView.detachFromFlutterEngine();
flutterView = null;
}
OverlayStatusEmitter.emitIsShowing(false);
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(OverlayConstants.NOTIFICATION_ID);
}
Expand Down Expand Up @@ -153,6 +154,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
params.gravity = WindowSetup.gravity;
flutterView.setOnTouchListener(this);
windowManager.addView(flutterView, params);
OverlayStatusEmitter.emitIsShowing(true);
return START_STICKY;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package flutter.overlay.window.flutter_overlay_window;

public abstract class OverlayStatusEmitter {
static private final String methodName = "isShowingOverlay";
static private boolean lastEmittedStatus;
static void emitIsShowing(boolean isShowing) {
if(isShowing == lastEmittedStatus) return;
lastEmittedStatus = isShowing;
if(CachedMessageChannels.mainAppMessageChannel != null) {
CachedMessageChannels.mainAppMessageChannel.invokeMethod(methodName, isShowing);
}
if(CachedMessageChannels.overlayMessageChannel != null) {
CachedMessageChannels.overlayMessageChannel.invokeMethod(methodName, isShowing);
}
}
}
48 changes: 35 additions & 13 deletions lib/src/overlay_window.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import 'dart:async';
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_overlay_window/src/overlay_config.dart';

class FlutterOverlayWindow {
FlutterOverlayWindow._();

static final StreamController _controller = StreamController.broadcast();
static const MethodChannel _channel =
MethodChannel("x-slayer/overlay_channel");
static const MethodChannel _overlayChannel =
MethodChannel("x-slayer/overlay");
static const BasicMessageChannel _overlayMessageChannel =
BasicMessageChannel("x-slayer/overlay_messenger", JSONMessageCodec());
static final _controller = StreamController<dynamic>.broadcast();
static final _controllerOverlayStatus = StreamController<bool>.broadcast();

static const _channel = MethodChannel("x-slayer/overlay_channel");
static const _overlayChannel = MethodChannel("x-slayer/overlay");
static const _overlayMessageChannel =
MethodChannel("x-slayer/overlay_messenger", JSONMethodCodec());

/// Open overLay content
///
Expand Down Expand Up @@ -93,19 +92,29 @@ class FlutterOverlayWindow {
///
/// Returns `true` if the [data] was sent successfully, otherwise `false`.
static Future<bool> shareData(dynamic data) async {
final isSent = await _overlayMessageChannel.send(data);
final isSent = await _overlayMessageChannel.invokeMethod('', data);
return isSent as bool;
}

/// Streams message shared between overlay and main app
static Stream<dynamic> get overlayListener {
_overlayMessageChannel.setMessageHandler((message) async {
_controller.add(message);
return message;
});
_registerOverlayMessageHandler();
return _controller.stream;
}

/// Overlay status stream.
///
/// Emit `true` when overlay is showing, and `false` when overlay is closed.
///
/// Emit value only once for every state change.
///
/// Doesn't emit a change when the overlay is already showing and [showOverlay] is called,
/// as in this case the overlay will almost immediately reopen.
static Stream<bool> get overlayStatusListener {
_registerOverlayMessageHandler();
return _controllerOverlayStatus.stream;
}

/// Update the overlay flag while the overlay in action
static Future<bool?> updateFlag(OverlayFlag flag) async {
final bool? _res = await _overlayChannel
Expand All @@ -131,6 +140,19 @@ class FlutterOverlayWindow {
return _res ?? false;
}

static void _registerOverlayMessageHandler() {
_overlayMessageChannel.setMethodCallHandler((call) async {
switch (call.method) {
case 'isShowingOverlay':
_controllerOverlayStatus.add(call.arguments as bool);
break;
case 'message':
_controller.add(call.arguments);
break;
}
});
}

/// Dispose overlay stream.
///
/// Once disposed, only a complete restart of the application will re-initialize the listener.
Expand Down

0 comments on commit 4174ffe

Please sign in to comment.