From ae8dd814d544bf3dd605497e4ae91fdc626d51b7 Mon Sep 17 00:00:00 2001 From: abedelaziz-deriv <135210555+abedelaziz-deriv@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:45:50 +0800 Subject: [PATCH] Minor code refactoring (#8) --- CHANGELOG.md | 5 ++ README.md | 2 +- assets/live_chat.js | 84 +++++++++++++++++++ example/pubspec.lock | 6 +- .../live_chat_plus/assets/live_chat.js | 84 +++++++++++++++++++ example/web/index.html | 2 +- ios/Classes/LiveChatPlugin.swift | 8 +- lib/_internal/live_chat_web.dart | 6 +- lib/src/js/js_helper_web.dart | 5 ++ lib/src/js/js_library.dart | 7 ++ lib/src/live_chat.dart | 45 +++++----- lib/src/live_chat_method_channel.dart | 38 ++++----- lib/src/live_chat_platform_interface.dart | 9 +- pubspec.yaml | 10 ++- 14 files changed, 256 insertions(+), 55 deletions(-) create mode 100644 assets/live_chat.js create mode 100644 example/web/assets/packages/live_chat_plus/assets/live_chat.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 26c0b10..79f9927 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.0.5 + +* Minor code refactoring. +* Fixed a bug in iOS when passing null customParams. + ## 1.0.4 * Updated README diff --git a/README.md b/README.md index 45bf5eb..d3e0688 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Step 2: To avoid issues with proguard enabled, include the following to proguard ### Web Inside index.html file, add this line inside `` tag: ```html - + ``` ## Usage diff --git a/assets/live_chat.js b/assets/live_chat.js new file mode 100644 index 0000000..238be5a --- /dev/null +++ b/assets/live_chat.js @@ -0,0 +1,84 @@ +function startLiveChat(license, userName, email) { + window.__lc = window.__lc || {}; + window.__lc.license = license;; + window.__lc.asyncInit = true; + (function(n, t, c) { + function i(n) { + return e._h ? e._h.apply(null, n) : e._q.push(n) + } + var e = { + _q: [], + _h: null, + _v: "2.0", + on: function() { + i(["on", c.call(arguments)]) + }, + once: function() { + i(["once", c.call(arguments)]) + }, + off: function() { + i(["off", c.call(arguments)]) + }, + get: function() { + if (!e._h) throw new Error("[LiveChatWidget] You can't use getters before load."); + return i(["get", c.call(arguments)]) + }, + call: function() { + i(["call", c.call(arguments)]) + }, + init: function() { + var n = t.createElement("script"); + n.async = !0, n.type = "text/javascript", n.src = "https://cdn.livechatinc.com/tracking.js", t.head.appendChild(n) + } + }; + !n.__lc.asyncInit && e.init(), n.LiveChatWidget = n.LiveChatWidget || e + }(window, document, [].slice)); + window.LiveChatWidget.init(); + window.LiveChatWidget.on('ready', function() { + window.eventProducer.emit('event', 'chatOpen'); + if (window.LiveChatWidget && typeof window.LiveChatWidget.call === 'function') { + window.LiveChatWidget.call('set_customer_email', email); + window.LiveChatWidget.call('set_customer_name', userName); + } + }); + + if (window.LiveChatWidget && typeof window.LiveChatWidget.call === 'function') { + window.LiveChatWidget.call('maximize'); + } + + window.LiveChatWidget.on('new_event', onNewEvent); +} + +function onNewEvent(event) { + window.eventProducer.emit('event', event.type); +} + +function hideWindow() { + LiveChatWidget.call("hide"); +} + +function destroyWindow() { + LiveChatWidget.call("destroy"); +} + + +class EventProducer { + constructor() { + this.listeners = {}; + } + + on(event, listener) { + if (!this.listeners[event]) { + this.listeners[event] = []; + } + this.listeners[event].push(listener); + } + + emit(event, data) { + if (this.listeners[event]) { + this.listeners[event].forEach(listener => listener(data)); + } + } +} + + window.eventProducer = new EventProducer(); diff --git a/example/pubspec.lock b/example/pubspec.lock index d11fcd5..c7d2123 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -47,10 +47,10 @@ packages: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.7.1" lints: dependency: transitive description: @@ -65,7 +65,7 @@ packages: path: ".." relative: true source: path - version: "1.0.3" + version: "1.0.5" material_color_utilities: dependency: transitive description: diff --git a/example/web/assets/packages/live_chat_plus/assets/live_chat.js b/example/web/assets/packages/live_chat_plus/assets/live_chat.js new file mode 100644 index 0000000..238be5a --- /dev/null +++ b/example/web/assets/packages/live_chat_plus/assets/live_chat.js @@ -0,0 +1,84 @@ +function startLiveChat(license, userName, email) { + window.__lc = window.__lc || {}; + window.__lc.license = license;; + window.__lc.asyncInit = true; + (function(n, t, c) { + function i(n) { + return e._h ? e._h.apply(null, n) : e._q.push(n) + } + var e = { + _q: [], + _h: null, + _v: "2.0", + on: function() { + i(["on", c.call(arguments)]) + }, + once: function() { + i(["once", c.call(arguments)]) + }, + off: function() { + i(["off", c.call(arguments)]) + }, + get: function() { + if (!e._h) throw new Error("[LiveChatWidget] You can't use getters before load."); + return i(["get", c.call(arguments)]) + }, + call: function() { + i(["call", c.call(arguments)]) + }, + init: function() { + var n = t.createElement("script"); + n.async = !0, n.type = "text/javascript", n.src = "https://cdn.livechatinc.com/tracking.js", t.head.appendChild(n) + } + }; + !n.__lc.asyncInit && e.init(), n.LiveChatWidget = n.LiveChatWidget || e + }(window, document, [].slice)); + window.LiveChatWidget.init(); + window.LiveChatWidget.on('ready', function() { + window.eventProducer.emit('event', 'chatOpen'); + if (window.LiveChatWidget && typeof window.LiveChatWidget.call === 'function') { + window.LiveChatWidget.call('set_customer_email', email); + window.LiveChatWidget.call('set_customer_name', userName); + } + }); + + if (window.LiveChatWidget && typeof window.LiveChatWidget.call === 'function') { + window.LiveChatWidget.call('maximize'); + } + + window.LiveChatWidget.on('new_event', onNewEvent); +} + +function onNewEvent(event) { + window.eventProducer.emit('event', event.type); +} + +function hideWindow() { + LiveChatWidget.call("hide"); +} + +function destroyWindow() { + LiveChatWidget.call("destroy"); +} + + +class EventProducer { + constructor() { + this.listeners = {}; + } + + on(event, listener) { + if (!this.listeners[event]) { + this.listeners[event] = []; + } + this.listeners[event].push(listener); + } + + emit(event, data) { + if (this.listeners[event]) { + this.listeners[event].forEach(listener => listener(data)); + } + } +} + + window.eventProducer = new EventProducer(); diff --git a/example/web/index.html b/example/web/index.html index 9bf2075..9353de8 100644 --- a/example/web/index.html +++ b/example/web/index.html @@ -32,7 +32,7 @@ live_chat_example - + diff --git a/ios/Classes/LiveChatPlugin.swift b/ios/Classes/LiveChatPlugin.swift index e4c60ee..6b78f49 100644 --- a/ios/Classes/LiveChatPlugin.swift +++ b/ios/Classes/LiveChatPlugin.swift @@ -30,7 +30,7 @@ public class LiveChatPlugin: NSObject, FlutterPlugin, LiveChatDelegate, FlutterS let visitorName = (arguments["visitorName"] as? String) let visitorEmail = (arguments["visitorEmail"] as? String) let groupId = (arguments["groupId"] as? String) - let customParams = (arguments["customParams"] as! [String: String]) + let customParams = (arguments["customParams"] as? [String: String]) if licenseId == "" { result(FlutterError(code: "", message: "LICENSE NUMBER EMPTY", details: nil)) @@ -40,8 +40,10 @@ public class LiveChatPlugin: NSObject, FlutterPlugin, LiveChatDelegate, FlutterS LiveChat.email = visitorEmail LiveChat.groupId = groupId - for (key, value) in customParams { - LiveChat.setVariable(withKey: key, value: value) + if(customParams != nil) { + for (key, value) in customParams! { + LiveChat.setVariable(withKey: key, value: value) + } } LiveChat.delegate = self diff --git a/lib/_internal/live_chat_web.dart b/lib/_internal/live_chat_web.dart index 2268843..025d52c 100644 --- a/lib/_internal/live_chat_web.dart +++ b/lib/_internal/live_chat_web.dart @@ -8,8 +8,10 @@ import 'package:js/js_util.dart' as js; /// A web implementation of the LiveChatPlatform of the LiveChat plugin. class LiveChatWeb extends LiveChatPlatform { + /// Constructs LiveChatWeb LiveChatWeb(); + /// Register livechat instance when web. static void registerWith(Registrar registrar) { LiveChatPlatform.instance = LiveChatWeb(); } @@ -30,8 +32,8 @@ class LiveChatWeb extends LiveChatPlatform { } @override - Stream? getLiveChatEventsStream() { - eventProducer.on('event', js.allowInterop((data) { + Stream? getLiveChatEventsStream() { + eventProducer.on('event', js.allowInterop((dynamic data) { _streamController.add(data); })); return _streamController.stream; diff --git a/lib/src/js/js_helper_web.dart b/lib/src/js/js_helper_web.dart index 1531573..c77514e 100644 --- a/lib/src/js/js_helper_web.dart +++ b/lib/src/js/js_helper_web.dart @@ -1,14 +1,19 @@ import 'js_library.dart'; +/// Helper class that handles calling external functions triggered with +/// javascript. class JSHelper { + /// Calls to open live chat window. void callStartLiveChat(String licence, String userName, String email) { startLiveChat(licence, userName, email); } + /// Calls to close live chat window. void callHideWindow() { hideWindow(); } + /// Call to destroy live chat. void callDestroyWindow() { destroyWindow(); } diff --git a/lib/src/js/js_library.dart b/lib/src/js/js_library.dart index fac4c23..4bb2c90 100644 --- a/lib/src/js/js_library.dart +++ b/lib/src/js/js_library.dart @@ -1,18 +1,25 @@ import 'package:js/js.dart'; +/// Producer class that will be called in javascript. @JS() class EventProducer { + /// Triggers whenever a new event is emit in javascript. It should be listened + /// to in dart. external void on(String event, Function listener); } +/// Exposes [eventProducer]. @JS('window.eventProducer') external EventProducer get eventProducer; +/// Triggers opening web live chat. @JS() external void startLiveChat(String licence, String userName, String email); +/// Triggers hiding web live chat. @JS() external void hideWindow(); +/// Triggers destroying web live chat. @JS() external void destroyWindow(); diff --git a/lib/src/live_chat.dart b/lib/src/live_chat.dart index e9ffb3b..8b89741 100644 --- a/lib/src/live_chat.dart +++ b/lib/src/live_chat.dart @@ -1,38 +1,43 @@ import 'package:live_chat_plus/src/live_chat_platform_interface.dart'; +/// Live Chat Plus plugin class. class LiveChat { - static final LiveChat _singleton = LiveChat._internal(); - - factory LiveChat() { - return _singleton; - } + /// Constructs Livechat. + factory LiveChat() => _singleton; LiveChat._internal(); + static final LiveChat _singleton = LiveChat._internal(); + + /// Call to open the live chat window. It requires [licenseId], [username], + /// and [email]. + /// In addition, optional [groupId] and [customParameters] can be passed if + /// needed. Future openChatWindow({ required String licenseId, required String username, required String email, String? groupId, Map? customParameters, - }) async { - return LiveChatPlatform.instance.openChatWindow( - licenseId: licenseId, - username: username, - email: email, - groupId: groupId, - customParameters: customParameters, - ); - } + }) async => + LiveChatPlatform.instance.openChatWindow( + licenseId: licenseId, + username: username, + email: email, + groupId: groupId, + customParameters: customParameters, + ); - Future closeChatWindow() async { - return LiveChatPlatform.instance.closeChatWindow(); - } + /// Call to close/hide the chat window. + Future closeChatWindow() async => + LiveChatPlatform.instance.closeChatWindow(); - Future clearChatSession() async { - return LiveChatPlatform.instance.clearChatSession(); - } + /// Call to clear the chat session, for example, after logout, + Future clearChatSession() async => + LiveChatPlatform.instance.clearChatSession(); + /// Subscribe to events stream coming from live chat windows such as: + /// open, close, message, actual message text, etc. Stream? get onLiveChatEventReceived => LiveChatPlatform.instance.getLiveChatEventsStream(); } diff --git a/lib/src/live_chat_method_channel.dart b/lib/src/live_chat_method_channel.dart index 2adcc64..e34576c 100644 --- a/lib/src/live_chat_method_channel.dart +++ b/lib/src/live_chat_method_channel.dart @@ -18,31 +18,27 @@ class MethodChannelLiveChat extends LiveChatPlatform { required String email, String? groupId, Map? customParameters, - }) { - return _methodChannel.invokeMethod( - openChatWindowKey, - { - licenseIdKey: licenseId, - visitorNameKey: username, - visitorEmailKey: email, - groupIdKey: groupId, - customParamsKey: customParameters, - }, - ); - } + }) => + _methodChannel.invokeMethod( + openChatWindowKey, + { + licenseIdKey: licenseId, + visitorNameKey: username, + visitorEmailKey: email, + groupIdKey: groupId, + customParamsKey: customParameters, + }, + ); @override - Future closeChatWindow() async { - return _methodChannel.invokeMethod(closeChatWindowKey); - } + Future closeChatWindow() async => + _methodChannel.invokeMethod(closeChatWindowKey); @override - Future clearChatSession() async { - return _methodChannel.invokeMethod(clearChatSessionKey); - } + Future clearChatSession() async => + _methodChannel.invokeMethod(clearChatSessionKey); @override - Stream? getLiveChatEventsStream() { - return _eventsChannel.receiveBroadcastStream(); - } + Stream? getLiveChatEventsStream() => + _eventsChannel.receiveBroadcastStream(); } diff --git a/lib/src/live_chat_platform_interface.dart b/lib/src/live_chat_platform_interface.dart index 3ffc294..d179720 100644 --- a/lib/src/live_chat_platform_interface.dart +++ b/lib/src/live_chat_platform_interface.dart @@ -1,7 +1,9 @@ import 'package:live_chat_plus/src/live_chat_method_channel.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +/// LiveChatPlatform contract. abstract class LiveChatPlatform extends PlatformInterface { + /// Constructs the contract. LiveChatPlatform() : super(token: _token); static final Object _token = Object(); @@ -21,6 +23,7 @@ abstract class LiveChatPlatform extends PlatformInterface { _instance = instance; } + /// Open the chat window. Future openChatWindow({ required String licenseId, required String username, @@ -31,15 +34,19 @@ abstract class LiveChatPlatform extends PlatformInterface { throw UnimplementedError('openChatWindow() has not been implemented.'); } + /// Close the chat window. Future closeChatWindow() { throw UnimplementedError('closeChatWindow() has not been implemented.'); } + /// Clea the chat session. Future clearChatSession() { throw UnimplementedError('clearChatSession() has not been implemented.'); } + /// Get the live chat events stream. Stream? getLiveChatEventsStream() { - throw UnimplementedError('getLiveChatEventsStream() has not been implemented.'); + throw UnimplementedError( + 'getLiveChatEventsStream() has not been implemented.'); } } diff --git a/pubspec.yaml b/pubspec.yaml index f35e054..945057b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: live_chat_plus -description: "A Flutter plugin to bring LiveChat functionality to Flutter" -version: 1.0.4 +description: "A Flutter plugin to bring LiveChat functionality to Flutter. It wraps chat-window android and ios SDKs, in addition to support for web" +version: 1.0.5 repository: https://github.com/deriv-com/live-chat issue_tracker: https://github.com/deriv-com/live-chat/issues homepage: https://github.com/deriv-com/live-chat @@ -14,7 +14,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - js: ^0.6.3 + js: ^0.7.1 plugin_platform_interface: ^2.1.8 dev_dependencies: @@ -23,6 +23,9 @@ dev_dependencies: flutter_lints: ^4.0.0 flutter: + assets: + - assets/live_chat.js + plugin: platforms: android: @@ -33,3 +36,4 @@ flutter: web: pluginClass: LiveChatWeb fileName: _internal/live_chat_web.dart +