From e690e81e8053080b237fab336d349ab33a2c0935 Mon Sep 17 00:00:00 2001 From: Codefarmer Date: Thu, 3 Oct 2024 23:26:07 +0100 Subject: [PATCH] feat: chat events listener --- .../mastersam/livechat/LivechatPlugin.java | 60 ++++++++++++++----- example/lib/main.dart | 32 ++++------ lib/livechatt.dart | 31 ++++++++++ 3 files changed, 86 insertions(+), 37 deletions(-) diff --git a/android/src/main/java/tech/mastersam/livechat/LivechatPlugin.java b/android/src/main/java/tech/mastersam/livechat/LivechatPlugin.java index 3984251..d67b506 100644 --- a/android/src/main/java/tech/mastersam/livechat/LivechatPlugin.java +++ b/android/src/main/java/tech/mastersam/livechat/LivechatPlugin.java @@ -17,17 +17,23 @@ import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.EventChannel; +import io.flutter.plugin.common.EventChannel.StreamHandler; import com.livechatinc.inappchat.ChatWindowConfiguration; +import com.livechatinc.inappchat.ChatWindowErrorType; import com.livechatinc.inappchat.ChatWindowView; +import com.livechatinc.inappchat.models.NewMessageModel; import java.util.HashMap; public class LivechatPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware { - private MethodChannel channel; + private MethodChannel methodChannel; + private EventChannel eventChannel; private Context context; private Activity activity; private ChatWindowView windowView; + private EventChannel.EventSink events; @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { @@ -36,8 +42,21 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBindin } private void setupChannel(BinaryMessenger messenger) { - channel = new MethodChannel(messenger, "livechatt"); - channel.setMethodCallHandler(this); + methodChannel = new MethodChannel(messenger, "livechatt"); + methodChannel.setMethodCallHandler(this); + + eventChannel = new EventChannel(messenger, "livechatt/events"); + eventChannel.setStreamHandler(new StreamHandler() { + @Override + public void onListen(Object arguments, EventChannel.EventSink eventSink) { + events = eventSink; // Capture the event sink for pushing events later + } + + @Override + public void onCancel(Object arguments) { + events = null; // Clear the event sink when not in use + } + }); } @Override @@ -94,12 +113,14 @@ public void onNewMessage(NewMessageModel message) { // Notify Flutter about the new message HashMap messageData = new HashMap<>(); messageData.put("text", message.getText()); - channel.invokeMethod("onNewMessage", messageData); + events.success(messageData); } @Override public void onChatWindowVisibilityChanged(boolean visible) { - channel.invokeMethod("onChatVisibilityChanged", visible); + if (events != null) { + events.success("onChatWindowVisibilityChanged: " + visible); + } } @Override @@ -114,17 +135,21 @@ public void onRequestAudioPermissions(String[] permissions, int requestCode) { @Override public boolean onError(ChatWindowErrorType errorType, int errorCode, String errorDescription) { - HashMap errorData = new HashMap<>(); - errorData.put("errorType", errorType.toString()); - errorData.put("errorCode", errorCode); - errorData.put("errorDescription", errorDescription); - channel.invokeMethod("onError", errorData); + if (events != null) { + HashMap errorData = new HashMap<>(); + errorData.put("errorType", errorType.toString()); + errorData.put("errorCode", errorCode); + errorData.put("errorDescription", errorDescription); + events.success(errorData); // Push error event to Flutter + } return true; } @Override public boolean handleUri(Uri uri) { - channel.invokeMethod("handleUri", uri.toString()); + if (events != null) { + events.success("handleUri: " + uri.toString()); + } return true; } }); @@ -162,13 +187,16 @@ public void onAttachedToActivity(ActivityPluginBinding binding) { @Override public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { - teardownChannel(); + teardownChannels(); } - private void teardownChannel() { - if (channel != null) { - channel.setMethodCallHandler(null); - channel = null; + private void teardownChannels() { + if (methodChannel != null) { + methodChannel.setMethodCallHandler(null); + methodChannel = null; + } + if (eventChannel != null) { + eventChannel.setStreamHandler(null); } } diff --git a/example/lib/main.dart b/example/lib/main.dart index bfd2b46..b65ed4c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'dart:async'; import 'package:flutter/services.dart'; import 'package:livechatt/livechatt.dart'; @@ -37,26 +36,17 @@ class _SupportState extends State { @override void initState() { super.initState(); - initPlatformState(); - } - - // Platform messages are asynchronous, so we initialize in an async method. - Future initPlatformState() async { - String? platformVersion; - // Platform messages may fail, so we use a try/catch PlatformException. - try { - platformVersion = await Livechat.platformVersion; - } on PlatformException { - platformVersion = 'Failed to get platform version.'; - } - - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. - if (!mounted) return; - - setState(() { - _platformVersion = platformVersion; + Livechat.newMessages.listen((message) { + print('New message: $message'); + }); + Livechat.visibilityChanges.listen((isVisible) { + print('Chat window is visible: $isVisible'); + }); + Livechat.errors.listen((error) { + print('Error: ${error['errorDescription']}'); + }); + Livechat.uriHandlers.listen((uri) { + print('Custom URI clicked: $uri'); }); } diff --git a/lib/livechatt.dart b/lib/livechatt.dart index 53ad202..e1293d1 100644 --- a/lib/livechatt.dart +++ b/lib/livechatt.dart @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; class Livechat { static const MethodChannel _channel = const MethodChannel('livechatt'); + static const EventChannel _eventChannel = EventChannel('livechatt/events'); /// Get platform version static Future get platformVersion async { @@ -23,4 +24,34 @@ class Livechat { 'customParams': customParams, }); } + + /// Clear chat session + static Future clearSession() async { + await _channel.invokeMethod('clearSession'); + } + + /// Listen to chat events: new messages, errors, visibility changes, etc. + static Stream get chatEvents => + _eventChannel.receiveBroadcastStream(); + + /// Start listening for new messages + static Stream get newMessages => chatEvents + .where((event) => event is Map && event.containsKey('text')) + .map((event) => event['text'] as String); + + /// Start listening for visibility changes + static Stream get visibilityChanges => chatEvents + .where((event) => + event is String && event.contains('onChatWindowVisibilityChanged')) + .map((event) => event.endsWith('true')); + + /// Start listening for errors + static Stream> get errors => chatEvents + .where((event) => event is Map && event.containsKey('errorDescription')) + .map((event) => event as Map); + + /// Handle URIs + static Stream get uriHandlers => chatEvents + .where((event) => event is String && event.contains('handleUri')) + .map((event) => event.replaceFirst('handleUri: ', '')); }