From 255eb370cbda9eaaaa57674f73f40b74d9dea723 Mon Sep 17 00:00:00 2001 From: Decoder07 Date: Sat, 27 Apr 2024 01:33:42 +0530 Subject: [PATCH 01/15] fixed dart analyze issue --- .../widgets/bottom_sheets/chat_bottom_sheet.dart | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_bottom_sheet.dart index 457bfab82..553f835af 100644 --- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_bottom_sheet.dart +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_bottom_sheet.dart @@ -50,15 +50,13 @@ class _ChatBottomSheetState extends State { void _scrollToEnd() { if (_scrollController.hasClients) { - WidgetsBinding.instance.addPostFrameCallback((_) => { - if (_scrollController.positions.isNotEmpty) - { - _scrollController.animateTo( - _scrollController.position.maxScrollExtent, - duration: const Duration(milliseconds: 200), - curve: Curves.easeInOut) - } - }); + WidgetsBinding.instance.addPostFrameCallback((_) => + _scrollController.positions.isNotEmpty + ? _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: const Duration(milliseconds: 200), + curve: Curves.easeInOut) + : null); } } From af566b182e2e32500928ce400b96bf98a308ad9a Mon Sep 17 00:00:00 2001 From: Yogesh Singh Date: Mon, 29 Apr 2024 19:45:28 +0530 Subject: [PATCH 02/15] bumped package versions --- .../hms_room_kit/example/ios/Podfile.lock | 16 ++--- packages/hms_room_kit/example/pubspec.lock | 2 +- packages/hms_room_kit/example/pubspec.yaml | 2 +- packages/hms_room_kit/pubspec.yaml | 2 +- .../hmssdk_flutter/example/ios/Podfile.lock | 6 +- packages/hmssdk_flutter/example/pubspec.lock | 68 ++++++------------- packages/hmssdk_flutter/example/pubspec.yaml | 2 +- .../lib/assets/sdk-versions.json | 2 +- packages/hmssdk_flutter/pubspec.lock | 66 ++++++------------ packages/hmssdk_flutter/pubspec.yaml | 2 +- 10 files changed, 60 insertions(+), 108 deletions(-) diff --git a/packages/hms_room_kit/example/ios/Podfile.lock b/packages/hms_room_kit/example/ios/Podfile.lock index 1d21584f3..2e9a26455 100644 --- a/packages/hms_room_kit/example/ios/Podfile.lock +++ b/packages/hms_room_kit/example/ios/Podfile.lock @@ -5,16 +5,16 @@ PODS: - HMSHLSPlayerSDK (0.0.2): - HMSAnalyticsSDK (= 0.0.2) - HMSNoiseCancellationModels (1.0.0) - - HMSSDK (1.8.0): + - HMSSDK (1.9.0): - HMSAnalyticsSDK (= 0.0.2) - - HMSWebRTC (= 1.0.5118) - - hmssdk_flutter (1.10.0): + - HMSWebRTC (= 1.0.6168) + - hmssdk_flutter (1.10.1): - Flutter - HMSBroadcastExtensionSDK (= 0.0.9) - HMSHLSPlayerSDK (= 0.0.2) - HMSNoiseCancellationModels (= 1.0.0) - - HMSSDK (= 1.8.0) - - HMSWebRTC (1.0.5118) + - HMSSDK (= 1.9.0) + - HMSWebRTC (1.0.6168) - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS @@ -68,9 +68,9 @@ SPEC CHECKSUMS: HMSBroadcastExtensionSDK: d80fe325f6c928bd8e5176290b5a4b7ae15d6fbb HMSHLSPlayerSDK: 6a54ad4d12f3dc2270d1ecd24019d71282a4f6a3 HMSNoiseCancellationModels: a3bda1405a16015632f4bcabd46ce48f35103b02 - HMSSDK: c893d1381a47ed02760ef6d06625b9aa5251f998 - hmssdk_flutter: 997715f0bedfcb22750fb95549672bf3fea380ff - HMSWebRTC: 4487c7200f1e9358412c1d8cd974edd2766467dc + HMSSDK: 96bdafc1c610aabfecd1155ad7e3c1bc45b3a6cb + hmssdk_flutter: c2ad70779ed9355577afbbe1047fb20f862820ac + HMSWebRTC: a302f0d6c94f7bee94f3265adb7bb1c6569e7ee5 path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 diff --git a/packages/hms_room_kit/example/pubspec.lock b/packages/hms_room_kit/example/pubspec.lock index 5013a3708..c60ae9c75 100644 --- a/packages/hms_room_kit/example/pubspec.lock +++ b/packages/hms_room_kit/example/pubspec.lock @@ -206,7 +206,7 @@ packages: path: ".." relative: true source: path - version: "1.1.1" + version: "1.1.2" hmssdk_flutter: dependency: transitive description: diff --git a/packages/hms_room_kit/example/pubspec.yaml b/packages/hms_room_kit/example/pubspec.yaml index 9a41feb9d..aeb837659 100644 --- a/packages/hms_room_kit/example/pubspec.yaml +++ b/packages/hms_room_kit/example/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.1.1 +version: 1.1.2 environment: sdk: ">=2.19.6 <3.0.0" diff --git a/packages/hms_room_kit/pubspec.yaml b/packages/hms_room_kit/pubspec.yaml index c9ffea667..3c9925bd2 100644 --- a/packages/hms_room_kit/pubspec.yaml +++ b/packages/hms_room_kit/pubspec.yaml @@ -1,6 +1,6 @@ name: hms_room_kit description: 100ms Room Kit provides simple & easy to use UI components to build Live Streaming & Video Conferencing experiences in your apps. -version: 1.1.1 +version: 1.1.2 homepage: https://www.100ms.live/ repository: https://github.com/100mslive/100ms-flutter issue_tracker: https://github.com/100mslive/100ms-flutter/issues diff --git a/packages/hmssdk_flutter/example/ios/Podfile.lock b/packages/hmssdk_flutter/example/ios/Podfile.lock index 64e0f64ba..b71a3d963 100644 --- a/packages/hmssdk_flutter/example/ios/Podfile.lock +++ b/packages/hmssdk_flutter/example/ios/Podfile.lock @@ -132,7 +132,7 @@ PODS: - HMSSDK (1.9.0): - HMSAnalyticsSDK (= 0.0.2) - HMSWebRTC (= 1.0.6168) - - hmssdk_flutter (1.10.0): + - hmssdk_flutter (1.10.1): - Flutter - HMSBroadcastExtensionSDK (= 0.0.9) - HMSHLSPlayerSDK (= 0.0.2) @@ -300,7 +300,7 @@ SPEC CHECKSUMS: HMSHLSPlayerSDK: 6a54ad4d12f3dc2270d1ecd24019d71282a4f6a3 HMSNoiseCancellationModels: a3bda1405a16015632f4bcabd46ce48f35103b02 HMSSDK: 96bdafc1c610aabfecd1155ad7e3c1bc45b3a6cb - hmssdk_flutter: 3febf31ba806e9a5ee540fe299c7331fc43135cf + hmssdk_flutter: c2ad70779ed9355577afbbe1047fb20f862820ac HMSWebRTC: a302f0d6c94f7bee94f3265adb7bb1c6569e7ee5 MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505 @@ -319,4 +319,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 9fb9f6e431a2c6c79942252e94b241ac7972ac90 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/packages/hmssdk_flutter/example/pubspec.lock b/packages/hmssdk_flutter/example/pubspec.lock index 71150e5cd..14aa8b0f0 100644 --- a/packages/hmssdk_flutter/example/pubspec.lock +++ b/packages/hmssdk_flutter/example/pubspec.lock @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" convert: dependency: transitive description: @@ -302,7 +302,7 @@ packages: path: "../../hms_room_kit" relative: true source: path - version: "1.1.1" + version: "1.1.2" hmssdk_flutter: dependency: transitive description: @@ -343,30 +343,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" linkify: dependency: transitive description: @@ -387,26 +363,26 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.9.1" mime: dependency: transitive description: @@ -451,10 +427,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" path_parsing: dependency: transitive description: @@ -688,18 +664,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -720,10 +696,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" tuple: dependency: transitive description: @@ -852,14 +828,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.0+2" - vm_service: + web: dependency: transitive description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "0.1.4-beta" win32: dependency: transitive description: @@ -885,5 +861,5 @@ packages: source: hosted version: "6.3.0" sdks: - dart: ">=3.2.0-0 <4.0.0" + dart: ">=3.1.0 <4.0.0" flutter: ">=3.13.0" diff --git a/packages/hmssdk_flutter/example/pubspec.yaml b/packages/hmssdk_flutter/example/pubspec.yaml index 7be7095df..328138a8f 100644 --- a/packages/hmssdk_flutter/example/pubspec.yaml +++ b/packages/hmssdk_flutter/example/pubspec.yaml @@ -4,7 +4,7 @@ description: Demonstrates how to use the hmssdk_flutter plugin. # The following line prevents the package from being accidentally published to # pub.dev using `pub publish`. This is preferred for private packages. publish_to: "none" # Remove this line if you wish to publish to pub.dev -version: 1.10.1 +version: 1.10.2 environment: sdk: ">=2.16.0 <4.0.0" diff --git a/packages/hmssdk_flutter/lib/assets/sdk-versions.json b/packages/hmssdk_flutter/lib/assets/sdk-versions.json index 17f99841f..bebc1b31e 100644 --- a/packages/hmssdk_flutter/lib/assets/sdk-versions.json +++ b/packages/hmssdk_flutter/lib/assets/sdk-versions.json @@ -4,5 +4,5 @@ "iOSBroadcastExtension": "0.0.9", "iOSHLSPlayerSDK": "0.0.2", "iOSNoiseCancellationModels": "1.0.0", - "android": "2.9.54" + "android": "2.9.55" } diff --git a/packages/hmssdk_flutter/pubspec.lock b/packages/hmssdk_flutter/pubspec.lock index bfac3fa40..2932c9c3b 100644 --- a/packages/hmssdk_flutter/pubspec.lock +++ b/packages/hmssdk_flutter/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" fake_async: dependency: transitive description: @@ -59,30 +59,6 @@ packages: description: flutter source: sdk version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" lints: dependency: "direct dev" description: @@ -95,34 +71,34 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.9.1" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" sky_engine: dependency: transitive description: flutter @@ -140,18 +116,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -172,10 +148,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" vector_math: dependency: transitive description: @@ -184,14 +160,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - vm_service: + web: dependency: transitive description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "0.1.4-beta" sdks: - dart: ">=3.2.0-0 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=2.10.0" diff --git a/packages/hmssdk_flutter/pubspec.yaml b/packages/hmssdk_flutter/pubspec.yaml index c6ebe82a8..38de9eb24 100644 --- a/packages/hmssdk_flutter/pubspec.yaml +++ b/packages/hmssdk_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: hmssdk_flutter description: Add Real Time Audio & Video calls, Interactive Live Streaming & Recording, Chat, HLS, RTMP, PiP, CallKit, VoIP, Video conferencing, Stream Player & WebRTC-based communications API -version: 1.10.1 +version: 1.10.2 homepage: https://www.100ms.live/ repository: https://github.com/100mslive/100ms-flutter issue_tracker: https://github.com/100mslive/100ms-flutter/issues From f734eb11eb742c76ee8bded4f35616444b3786d8 Mon Sep 17 00:00:00 2001 From: Pushpam <93931528+Decoder07@users.noreply.github.com> Date: Tue, 30 Apr 2024 19:01:17 +0530 Subject: [PATCH 03/15] Fixed seek bar issue while calling seekForward in live edge (#1759) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed seek bar issue while calling seekForward in live edge * 🤖 Automated Format and Fix --------- Co-authored-by: Decoder07 --- .../lib/src/hls_viewer/hls_player_seekbar.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_seekbar.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_seekbar.dart index fe28dc1b4..e23176088 100644 --- a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_seekbar.dart +++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_seekbar.dart @@ -49,7 +49,12 @@ class _HLSPlayerSeekbarState extends State { hlsPlayerStore.timeFromLive, hlsPlayerStore.rollingWindow), builder: (_, data, __) { maxValue = data.item2.inSeconds; - seekBarValue = maxValue > 0 ? maxValue - data.item1.inSeconds : 0; + + ///We only subtract the time from live from the rolling window if the time from live is greater than 0 + seekBarValue = maxValue > 0 + ? maxValue - + (data.item1.inSeconds > 0 ? data.item1.inSeconds : 0) + : 0; minValue = 0; return (maxValue > 0 && seekBarValue > 0) ? SliderTheme( From 8c2e658cc966741f814535c3e83f56fbf700ff15 Mon Sep 17 00:00:00 2001 From: Pushpam <93931528+Decoder07@users.noreply.github.com> Date: Wed, 1 May 2024 13:38:27 +0530 Subject: [PATCH 04/15] FLUT-297: Quality Selector for HLS Player (#1760) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added layer selector APIs * Added required changes * Added bottom sheet for hls quality * Added check tick on selected layer * Updated changes * released sample app version 1.5.186 (486) 🍀 * 🤖 Automated Format and Fix * updated changelog * updated packages --------- Co-authored-by: Yogesh Singh Co-authored-by: ygit --- .java-version | 2 +- packages/hms_room_kit/example/pubspec.lock | 7 +- .../lib/src/hls_viewer/hls_player_store.dart | 59 +- .../lib/src/hls_viewer/hls_viewer_header.dart | 44 +- ..._viewer_quality_selector_bottom_sheet.dart | 138 +++++ packages/hms_room_kit/pubspec.lock | 7 +- packages/hms_room_kit/pubspec.yaml | 3 +- .../hmssdk_flutter/HMSHLSLayerExtension.kt | 24 + .../hms/hmssdk_flutter/HmssdkFlutterPlugin.kt | 2 +- .../hls_player/HMSHLSPlayerAction.kt | 37 ++ .../hls_player/IHLSPlayerActionInterface.kt | 7 + .../hms/hmssdk_flutter/views/HMSHLSPlayer.kt | 32 ++ .../example/ExampleAppChangelog.txt | 19 +- .../example/android/Gemfile.lock | 16 +- .../example/android/app/build.gradle | 4 +- .../hmssdk_flutter/example/ios/Gemfile.lock | 16 +- .../example/ios/Runner/Info.plist | 4 +- .../example/lib/foreground_task_handler.dart | 6 +- packages/hmssdk_flutter/example/pubspec.lock | 75 ++- .../HLSPlayer/HMSHLSPlayerAction.swift | 536 ++++++++++++++---- .../Classes/SwiftHmssdkFlutterPlugin.swift | 3 +- .../ios/Classes/Views/HMSHLSPlayerView.swift | 11 + .../hmssdk_flutter/lib/hmssdk_flutter.dart | 1 + .../lib/src/common/platform_methods.dart | 15 + .../src/model/hls_player/hms_hls_layer.dart | 20 + .../hls_player/hms_hls_player_controller.dart | 28 + packages/hmssdk_flutter/pubspec.lock | 66 ++- 27 files changed, 973 insertions(+), 209 deletions(-) create mode 100644 packages/hms_room_kit/lib/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart create mode 100644 packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSLayerExtension.kt create mode 100644 packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_layer.dart diff --git a/.java-version b/.java-version index c839b6586..392ea27c7 100644 --- a/.java-version +++ b/.java-version @@ -1 +1 @@ -openjdk64-17.0.10 +openjdk64-17.0.11 diff --git a/packages/hms_room_kit/example/pubspec.lock b/packages/hms_room_kit/example/pubspec.lock index c60ae9c75..129792546 100644 --- a/packages/hms_room_kit/example/pubspec.lock +++ b/packages/hms_room_kit/example/pubspec.lock @@ -210,10 +210,9 @@ packages: hmssdk_flutter: dependency: transitive description: - name: hmssdk_flutter - sha256: bfa6e6ec411d6f86f6cc054936fb2163c4cd3f8703f8848099689652b3794376 - url: "https://pub.dev" - source: hosted + path: "../../hmssdk_flutter" + relative: true + source: path version: "1.10.1" http: dependency: transitive diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart index c91f32a35..3b025de0b 100644 --- a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart +++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart @@ -8,6 +8,7 @@ import 'dart:io'; ///Package imports import 'package:flutter/material.dart'; import 'package:hmssdk_flutter/hmssdk_flutter.dart'; +import 'package:collection/collection.dart'; ///Project imports import 'package:hms_room_kit/src/layout_api/hms_room_layout.dart'; @@ -75,6 +76,10 @@ class HLSPlayerStore extends ChangeNotifier String? caption; + Map layerMap = {}; + + HMSHLSLayer? selectedLayer; + ///This method starts a timer for 5 seconds and then hides the buttons /// ///[isStreamPlaying] is used to check if the video is playing or not @@ -215,6 +220,56 @@ class HLSPlayerStore extends ChangeNotifier notifyListeners(); } + ///[getHLSLayers] gets the HLS Layers + void getHLSLayers() async { + var layers = await HMSHLSPlayerController.getHLSLayers(); + int layersSize = layers.length; + if (layersSize > 0) { + ///This sorts the layers in descending order of bitrate + layers.sort((a, b) => (b.bitrate ?? 0).compareTo(a.bitrate ?? 0)); + + ///This checks for layer with zero or null bitrate and sets it to + ///"AUTO" key + if (layers[layersSize - 1].bitrate == 0 || + layers[layersSize - 1].bitrate == null) { + layerMap["AUTO"] = layers[layersSize - 1]; + } + + ///This picks up the highest bitrate layer from the sorted layers + layerMap["HIGH"] = layers[0]; + + ///This picks up the mid layer from the sorted layers + layerMap["MEDIUM"] = layers[layersSize ~/ 2]; + + ///This picks up the lowest bitrate layer from the sorted layers + if (layersSize > 1) { + layerMap["LOW"] = layers[layersSize - 2]; + } + } + } + + ///[getCurrentHLSLayer] gets the current HLS Layer + void getCurrentHLSLayer() async { + var layer = await HMSHLSPlayerController.getCurrentHLSLayer(); + + ///Here we are finding the layer with the same bitrate as the current layer + var layerSelected = layerMap.entries.firstWhereIndexedOrNull( + (index, element) => (element.value.bitrate == layer?.bitrate)); + + ///If the layer is found we set the selected layer to that layer + if (layerSelected != null) { + selectedLayer = layerSelected.value; + } + notifyListeners(); + } + + ///[setHLSLayer] sets the HLS Layer + void setHLSLayer(HMSHLSLayer hmsHLSLayer) async { + selectedLayer = hmsHLSLayer; + await HMSHLSPlayerController.setHLSLayer(hmsHLSLayer: hmsHLSLayer); + notifyListeners(); + } + @override void onCue({required HMSHLSCue hlsCue}) {} @@ -223,7 +278,7 @@ class HLSPlayerStore extends ChangeNotifier @override void onHLSEventUpdate({required HMSHLSPlayerStats playerStats}) { - log("onHLSEventUpdate-> distanceFromLive: ${playerStats.distanceFromLive} buffered duration: ${playerStats.bufferedDuration}"); + log("onHLSEventUpdate-> distanceFromLive: ${playerStats.distanceFromLive}ms buffered duration: ${playerStats.bufferedDuration}ms bitrate: ${playerStats.averageBitrate}"); isLive = playerStats.distanceFromLive < timeBeforeLive; timeFromLive = Duration(milliseconds: playerStats.distanceFromLive.toInt()); hlsPlayerStats = playerStats; @@ -244,6 +299,8 @@ class HLSPlayerStore extends ChangeNotifier areClosedCaptionsSupported(); setHLSPlayerStats(true); startTimer(); + getHLSLayers(); + getCurrentHLSLayer(); isStreamPlaying = true; isPlayerFailed = false; break; diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_header.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_header.dart index f72197030..a608a266d 100644 --- a/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_header.dart +++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_header.dart @@ -3,6 +3,8 @@ library; ///Package imports import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hms_room_kit/src/meeting/meeting_store.dart'; +import 'package:hms_room_kit/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart'; import 'package:provider/provider.dart'; ///Project imports @@ -87,18 +89,38 @@ class HLSViewerHeader extends StatelessWidget { }), ///This will be added later - // const SizedBox( - // width: 16, - // ), + const SizedBox( + width: 16, + ), - // ///This renders the settings button - // SvgPicture.asset( - // "packages/hms_room_kit/lib/src/assets/icons/settings.svg", - // colorFilter: ColorFilter.mode( - // HMSThemeColors.onSurfaceHighEmphasis, - // BlendMode.srcIn), - // semanticsLabel: "caption_toggle_button", - // ) + ///This renders the settings button + GestureDetector( + onTap: () { + var _meetingStore = + context.read(); + var _hlsPlayerStore = + context.read(); + showModalBottomSheet( + isScrollControlled: true, + backgroundColor: Colors.transparent, + context: context, + builder: (ctx) => + ChangeNotifierProvider.value( + value: _meetingStore, + child: ChangeNotifierProvider.value( + value: _hlsPlayerStore, + child: + HLSViewerQualitySelectorBottomSheet()), + )); + }, + child: SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/settings.svg", + colorFilter: ColorFilter.mode( + HMSThemeColors.onSurfaceHighEmphasis, + BlendMode.srcIn), + semanticsLabel: "caption_toggle_button", + ), + ) ], ) ], diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart new file mode 100644 index 000000000..374c2cfcf --- /dev/null +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart @@ -0,0 +1,138 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hms_room_kit/src/hls_viewer/hls_player_store.dart'; +import 'package:hms_room_kit/src/layout_api/hms_theme_colors.dart'; +import 'package:hms_room_kit/src/meeting/meeting_store.dart'; +import 'package:hms_room_kit/src/widgets/common_widgets/hms_cross_button.dart'; +import 'package:hms_room_kit/src/widgets/common_widgets/hms_subtitle_text.dart'; +import 'package:hms_room_kit/src/widgets/common_widgets/hms_title_text.dart'; +import 'package:hmssdk_flutter/hmssdk_flutter.dart'; +import 'package:provider/provider.dart'; +import 'package:tuple/tuple.dart'; + +class HLSViewerQualitySelectorBottomSheet extends StatefulWidget { + @override + State createState() => + _HLSViewerQualitySelectorBottomSheetState(); +} + +class _HLSViewerQualitySelectorBottomSheetState + extends State { + @override + void initState() { + super.initState(); + context.read().addBottomSheet(context); + } + + @override + void deactivate() { + context.read().removeBottomSheet(context); + super.deactivate(); + } + + @override + Widget build(BuildContext context) { + double height = MediaQuery.of(context).size.height; + return SizedBox( + height: MediaQuery.of(context).orientation == Orientation.landscape + ? height * 0.8 + : height * 0.4, + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), topRight: Radius.circular(16)), + color: HMSThemeColors.backgroundDefault, + ), + child: Selector, int>>( + selector: (_, hlsPlayerStore) => Tuple2( + hlsPlayerStore.layerMap, hlsPlayerStore.layerMap.length), + builder: (context, data, _) { + return Padding( + padding: + const EdgeInsets.only(top: 24.0, left: 16, right: 16), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + HMSTitleText( + text: "Quality", + textColor: HMSThemeColors.onSurfaceHighEmphasis, + letterSpacing: 0.15, + ), + ], + ), + const Row( + children: [HMSCrossButton()], + ), + ], + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: Divider( + color: HMSThemeColors.borderDefault, + height: 5, + ), + ), + Expanded( + child: ListView.builder( + itemCount: data.item2, + itemBuilder: (context, index) { + return GestureDetector( + onTap: () { + context.read().setHLSLayer( + data.item1.entries + .elementAt(index) + .value); + Navigator.pop(context); + }, + child: ListTile( + horizontalTitleGap: 2, + enabled: false, + contentPadding: EdgeInsets.zero, + title: HMSSubtitleText( + text: + data.item1.entries.elementAt(index).key, + fontSize: 14, + lineHeight: 20, + letterSpacing: 0.10, + fontWeight: FontWeight.w600, + textColor: + HMSThemeColors.onSurfaceHighEmphasis, + ), + trailing: context + .read() + .selectedLayer == + data.item1.entries + .elementAt(index) + .value + ? SizedBox( + height: 24, + width: 24, + child: SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/tick.svg", + fit: BoxFit.scaleDown, + colorFilter: ColorFilter.mode( + HMSThemeColors + .onSurfaceHighEmphasis, + BlendMode.srcIn), + ), + ) + : const SizedBox( + height: 24, + width: 24, + ), + ), + ); + }), + ) + ], + ), + ); + }), + )); + } +} diff --git a/packages/hms_room_kit/pubspec.lock b/packages/hms_room_kit/pubspec.lock index 287ab5d9f..a483faed0 100644 --- a/packages/hms_room_kit/pubspec.lock +++ b/packages/hms_room_kit/pubspec.lock @@ -187,10 +187,9 @@ packages: hmssdk_flutter: dependency: "direct main" description: - name: hmssdk_flutter - sha256: bfa6e6ec411d6f86f6cc054936fb2163c4cd3f8703f8848099689652b3794376 - url: "https://pub.dev" - source: hosted + path: "../hmssdk_flutter" + relative: true + source: path version: "1.10.1" http: dependency: transitive diff --git a/packages/hms_room_kit/pubspec.yaml b/packages/hms_room_kit/pubspec.yaml index 3c9925bd2..b2c7b853b 100644 --- a/packages/hms_room_kit/pubspec.yaml +++ b/packages/hms_room_kit/pubspec.yaml @@ -14,7 +14,8 @@ dependencies: flutter: sdk: flutter - hmssdk_flutter: 1.10.1 + hmssdk_flutter: + path: ../hmssdk_flutter intl: ^0.18.0 permission_handler: ^11.0.0 provider: ^6.0.5 diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSLayerExtension.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSLayerExtension.kt new file mode 100644 index 000000000..0385bf5dd --- /dev/null +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSLayerExtension.kt @@ -0,0 +1,24 @@ +package live.hms.hmssdk_flutter + +import live.hms.hls_player.HmsHlsLayer + +class HMSHLSLayerExtension { + + companion object{ + fun toDictionary(hmsHLSLayer :HmsHlsLayer?): HashMap?{ + + if(hmsHLSLayer == null){ + return null; + } + val map = HashMap() + if(hmsHLSLayer == HmsHlsLayer.AUTO){ + return map + } + (hmsHLSLayer as HmsHlsLayer.LayerInfo?)?.let { + map["resolution"] = HMSVideoResolutionExtension.toDictionary(it.resolution) + map["bitrate"] = it.bitrate + } + return map + } + } +} \ No newline at end of file diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt index d1dc5b060..dc2a40e8c 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt @@ -252,7 +252,7 @@ class HmssdkFlutterPlugin : "remove_key_change_listener" -> { removeKeyChangeListener(call, result) } - "start_hls_player", "stop_hls_player", "pause_hls_player", "resume_hls_player", "seek_to_live_position", "seek_forward", "seek_backward", "set_hls_player_volume", "add_hls_stats_listener", "remove_hls_stats_listener", "are_closed_captions_supported", "enable_closed_captions", "disable_closed_captions", "get_stream_properties" -> { + "start_hls_player", "stop_hls_player", "pause_hls_player", "resume_hls_player", "seek_to_live_position", "seek_forward", "seek_backward", "set_hls_player_volume", "add_hls_stats_listener", "remove_hls_stats_listener", "are_closed_captions_supported", "enable_closed_captions", "disable_closed_captions", "get_stream_properties","get_hls_layers", "set_hls_layer", "get_current_hls_layer" -> { HMSHLSPlayerAction.hlsPlayerAction(call, result) } "toggle_always_screen_on" -> { diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/HMSHLSPlayerAction.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/HMSHLSPlayerAction.kt index 55fb06fce..d78aee51b 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/HMSHLSPlayerAction.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/HMSHLSPlayerAction.kt @@ -2,6 +2,7 @@ package live.hms.hmssdk_flutter.hls_player import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel.Result +import live.hms.hls_player.HmsHlsLayer import live.hms.hmssdk_flutter.HMSErrorLogger import java.lang.ref.WeakReference @@ -32,6 +33,9 @@ class HMSHLSPlayerAction { "enable_closed_captions" -> enableClosedCaptions(result) "disable_closed_captions" -> disableClosedCaptions(result) "get_stream_properties" -> getStreamProperties(result) + "get_hls_layers" -> getHLSLayers(result) + "set_hls_layer" -> setHLSLayer(call,result) + "get_current_hls_layer" -> getCurrentHLSLayer(result) else -> { result.notImplemented() } @@ -260,5 +264,38 @@ class HMSHLSPlayerAction { HMSErrorLogger.logError("getStreamProperties", "hlsActions is NULL", "NULL Error") } } + + private fun getHLSLayers(result: Result){ + hlsActions?.let { + it.get()?.getHLSLayers(result) + } ?: run { + HMSErrorLogger.logError("getHLSLayers", "hlsActions is NULL", "NULL Error") + } + } + + private fun setHLSLayer(call: MethodCall,result: Result){ + + val layerMap = call.argument?>("layer") + + layerMap?.let { + if(layerMap["resolution"] != null && layerMap["bitrate"] != null){ + hlsActions?.let { + it.get()?.setHLSLayer(layerMap,result) + } ?: run { + HMSErrorLogger.logError("getCurrentHLSLayer", "hlsActions is NULL", "NULL Error") + } + } + }?:run { + HMSErrorLogger.returnArgumentsError("hmsHLSLayer is null in setHLSLayer") + } + } + + private fun getCurrentHLSLayer(result: Result){ + hlsActions?.let { + it.get()?.getCurrentHLSLayer(result) + } ?: run { + HMSErrorLogger.logError("getCurrentHLSLayer", "hlsActions is NULL", "NULL Error") + } + } } } diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/IHLSPlayerActionInterface.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/IHLSPlayerActionInterface.kt index 86bf25099..686ab187b 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/IHLSPlayerActionInterface.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/IHLSPlayerActionInterface.kt @@ -1,6 +1,7 @@ package live.hms.hmssdk_flutter.hls_player import io.flutter.plugin.common.MethodChannel.Result +import live.hms.hls_player.HmsHlsLayer /** * [IHLSPlayerActionInterface] contains HLS Player methods @@ -47,4 +48,10 @@ interface IHLSPlayerActionInterface { fun disableClosedCaptions(result: Result) fun getStreamProperties(result: Result) + + fun getHLSLayers(result: Result) + + fun setHLSLayer(hlsLayer:HashMap,result: Result) + + fun getCurrentHLSLayer(result: Result) } diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/views/HMSHLSPlayer.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/views/HMSHLSPlayer.kt index 9cdb44355..31e7c12d9 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/views/HMSHLSPlayer.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/views/HMSHLSPlayer.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import live.hms.hls_player.* import live.hms.hmssdk_flutter.HMSErrorLogger +import live.hms.hmssdk_flutter.HMSHLSLayerExtension import live.hms.hmssdk_flutter.HmssdkFlutterPlugin import live.hms.hmssdk_flutter.R import live.hms.hmssdk_flutter.hls_player.HLSStatsHandler @@ -379,6 +380,37 @@ class HMSHLSPlayer( result.success(map) } + + override fun getHLSLayers(result: Result) { + val layers = hlsPlayer?.getHmsHlsLayers() + val map = HashMap() + val layersList = ArrayList>() + layers?.forEach { layer -> + val args = HMSHLSLayerExtension.toDictionary(layer) + args?.let { + layersList.add(it) + } + } + map["layers"] = layersList + result.success(map) + } + + override fun setHLSLayer(hlsLayer:HashMap, result: Result) { + val layers = hlsPlayer?.getHmsHlsLayers() + layers?.forEach { layer -> + (layer as HmsHlsLayer.LayerInfo?)?.let { + if(it.bitrate == hlsLayer["bitrate"]){ + hlsPlayer?.setHmsHlsLayer(it) + result.success(null) + return + } + } + } + } + + override fun getCurrentHLSLayer(result: Result) { + result.success(HMSHLSLayerExtension.toDictionary(hlsPlayer?.getCurrentHmsHlsLayer())) + } } } /********************************************/ diff --git a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt index db9ffb8f0..773eb7d50 100644 --- a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt +++ b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt @@ -1,18 +1,9 @@ Board: https://100ms.atlassian.net/jira/software/projects/FLUT/boards/34/ -- Added Captions in HLS Player -https://100ms.atlassian.net/browse/FLUT-265 +- Add Quality Selector sheet in HLS Player +https://100ms.atlassian.net/browse/FLUT-297 -- Pinch & Zoom on HLS Player -https://100ms.atlassian.net/browse/FLUT-268 - -- Full Screen Landscape UI -https://100ms.atlassian.net/browse/FLUT-269 - -- Seek Bar + Go Live Button behaviour (Polling) -https://100ms.atlassian.net/browse/FLUT-272 - -Room Kit: 1.1.1 -Core SDK: 1.10.1 -Android SDK: 2.9.54 +Room Kit: 1.1.2 +Core SDK: 1.10.2 +Android SDK: 2.9.55 iOS SDK: 1.9.0 \ No newline at end of file diff --git a/packages/hmssdk_flutter/example/android/Gemfile.lock b/packages/hmssdk_flutter/example/android/Gemfile.lock index 4e4043c3b..8694f0a0b 100644 --- a/packages/hmssdk_flutter/example/android/Gemfile.lock +++ b/packages/hmssdk_flutter/example/android/Gemfile.lock @@ -15,17 +15,17 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.916.0) - aws-sdk-core (3.192.1) + aws-partitions (1.922.0) + aws-sdk-core (3.194.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.79.0) - aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-kms (1.80.0) + aws-sdk-core (~> 3, >= 3.193.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.147.0) - aws-sdk-core (~> 3, >= 3.192.0) + aws-sdk-s3 (1.149.0) + aws-sdk-core (~> 3, >= 3.194.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) aws-sigv4 (1.8.0) @@ -115,7 +115,7 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) - fastlane-plugin-firebase_app_distribution (0.9.0) + fastlane-plugin-firebase_app_distribution (0.9.1) google-apis-firebaseappdistribution_v1 (~> 0.3.0) google-apis-firebaseappdistribution_v1alpha (~> 0.2.0) gh_inspector (1.1.3) @@ -234,4 +234,4 @@ DEPENDENCIES fastlane-plugin-firebase_app_distribution BUNDLED WITH - 2.5.7 + 2.5.9 diff --git a/packages/hmssdk_flutter/example/android/app/build.gradle b/packages/hmssdk_flutter/example/android/app/build.gradle index 863fc41b4..52e4f4e54 100644 --- a/packages/hmssdk_flutter/example/android/app/build.gradle +++ b/packages/hmssdk_flutter/example/android/app/build.gradle @@ -36,8 +36,8 @@ android { applicationId "live.hms.flutter" minSdkVersion 21 targetSdkVersion 34 - versionCode 483 - versionName "1.5.183" + versionCode 486 + versionName "1.5.186" } signingConfigs { diff --git a/packages/hmssdk_flutter/example/ios/Gemfile.lock b/packages/hmssdk_flutter/example/ios/Gemfile.lock index 85288e6db..f98d835d7 100644 --- a/packages/hmssdk_flutter/example/ios/Gemfile.lock +++ b/packages/hmssdk_flutter/example/ios/Gemfile.lock @@ -15,17 +15,17 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.916.0) - aws-sdk-core (3.192.1) + aws-partitions (1.922.0) + aws-sdk-core (3.194.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.79.0) - aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-kms (1.80.0) + aws-sdk-core (~> 3, >= 3.193.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.147.0) - aws-sdk-core (~> 3, >= 3.192.0) + aws-sdk-s3 (1.149.0) + aws-sdk-core (~> 3, >= 3.194.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) aws-sigv4 (1.8.0) @@ -115,7 +115,7 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) - fastlane-plugin-firebase_app_distribution (0.9.0) + fastlane-plugin-firebase_app_distribution (0.9.1) google-apis-firebaseappdistribution_v1 (~> 0.3.0) google-apis-firebaseappdistribution_v1alpha (~> 0.2.0) fastlane-plugin-versioning (0.5.2) @@ -236,4 +236,4 @@ DEPENDENCIES fastlane-plugin-versioning BUNDLED WITH - 2.5.7 + 2.5.9 diff --git a/packages/hmssdk_flutter/example/ios/Runner/Info.plist b/packages/hmssdk_flutter/example/ios/Runner/Info.plist index e5a655037..8f23eaedb 100644 --- a/packages/hmssdk_flutter/example/ios/Runner/Info.plist +++ b/packages/hmssdk_flutter/example/ios/Runner/Info.plist @@ -21,7 +21,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.5.183 + 1.5.186 CFBundleSignature ???? CFBundleURLTypes @@ -48,7 +48,7 @@ CFBundleVersion - 483 + 486 ITSAppUsesNonExemptEncryption LSApplicationCategoryType diff --git a/packages/hmssdk_flutter/example/lib/foreground_task_handler.dart b/packages/hmssdk_flutter/example/lib/foreground_task_handler.dart index 1648758f1..ade4caddb 100644 --- a/packages/hmssdk_flutter/example/lib/foreground_task_handler.dart +++ b/packages/hmssdk_flutter/example/lib/foreground_task_handler.dart @@ -13,11 +13,6 @@ class ForegroundTaskHandler extends TaskHandler { @override void onStart(DateTime timestamp, SendPort? sendPort) async { _sendPort = sendPort; - - // You can use the getData function to get the stored data. - final customData = - await FlutterForegroundTask.getData(key: 'customData'); - print('customData: $customData'); } // Called every [interval] milliseconds in [ForegroundTaskOptions]. @@ -51,6 +46,7 @@ class ForegroundTaskHandler extends TaskHandler { } } +///[initForegroundTask] initializes the foreground task Future initForegroundTask() async { bool isPermissionsGiven = await Utilities.getPermissions(); if (isPermissionsGiven) { diff --git a/packages/hmssdk_flutter/example/pubspec.lock b/packages/hmssdk_flutter/example/pubspec.lock index 14aa8b0f0..085e6fe80 100644 --- a/packages/hmssdk_flutter/example/pubspec.lock +++ b/packages/hmssdk_flutter/example/pubspec.lock @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" convert: dependency: transitive description: @@ -306,11 +306,10 @@ packages: hmssdk_flutter: dependency: transitive description: - name: hmssdk_flutter - sha256: bfa6e6ec411d6f86f6cc054936fb2163c4cd3f8703f8848099689652b3794376 - url: "https://pub.dev" - source: hosted - version: "1.10.1" + path: ".." + relative: true + source: path + version: "1.10.2" http: dependency: transitive description: @@ -343,6 +342,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" linkify: dependency: transitive description: @@ -363,26 +386,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.11.0" mime: dependency: transitive description: @@ -427,10 +450,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -664,18 +687,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -696,10 +719,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" tuple: dependency: transitive description: @@ -828,14 +851,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.0+2" - web: + vm_service: dependency: transitive description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "13.0.0" win32: dependency: transitive description: @@ -861,5 +884,5 @@ packages: source: hosted version: "6.3.0" sdks: - dart: ">=3.1.0 <4.0.0" + dart: ">=3.2.0-0 <4.0.0" flutter: ">=3.13.0" diff --git a/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift b/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift index 6bb5fac4e..9c78e56fc 100644 --- a/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift +++ b/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift @@ -13,60 +13,106 @@ import HMSSDK * We use notifications to forward the request to HMSHLSPlayer */ class HMSHLSPlayerAction { - + static let HLS_PLAYER_METHOD = "HLS_PLAYER" static let METHOD_CALL = "method_name" - - static func hlsPlayerAction(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { + + static func hlsPlayerAction( + _ call: FlutterMethodCall, + _ result: @escaping FlutterResult + ) { switch call.method { case "start_hls_player": - start(call, result) - + start( + call, + result + ) + case "stop_hls_player": - stop(result) - + stop( + result + ) + case "pause_hls_player": - pause(result) - + pause( + result + ) + case "resume_hls_player": - resume(result) - + resume( + result + ) + case "seek_to_live_position": - seekToLivePosition(result) - + seekToLivePosition( + result + ) + case "seek_forward": - seekForward(call, result) - + seekForward( + call, + result + ) + case "seek_backward": - seekBackward(call, result) - + seekBackward( + call, + result + ) + case "set_hls_player_volume": - setVolume(call, result) - + setVolume( + call, + result + ) + case "add_hls_stats_listener": - addHLSStatsListener(result) - + addHLSStatsListener( + result + ) + case "remove_hls_stats_listener": - removeHLSStatsListener(result) - + removeHLSStatsListener( + result + ) + case "are_closed_captions_supported": - areClosedCaptionsSupported(result) + areClosedCaptionsSupported( + result + ) case "enable_closed_captions": - enableClosedCaptions(result) - + enableClosedCaptions( + result + ) + case "disable_closed_captions": - disableClosedCaptions(result) + disableClosedCaptions( + result + ) case "get_stream_properties": - getStreamProperties(result) + getStreamProperties( + result + ) + + case "get_hls_layers": + getHLSLayers(result) + + case "set_hls_layer": + setHLSLayer(call, result) + + case "get_current_hls_layer": + getCurrentHLSLayer(result) default: - result(FlutterMethodNotImplemented) + result( + FlutterMethodNotImplemented + ) } - + } - + /** * Starts the HLS player by posting a notification with the specified method call and HLS URL. * @@ -74,60 +120,120 @@ class HMSHLSPlayerAction { * - call: The method call object containing the HLS URL as an argument. * - result: The result object to be returned after starting the player. */ - static private func start(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - + static private func start( + _ call: FlutterMethodCall, + _ result: @escaping FlutterResult + ) { + guard let arguments = call.arguments as? [AnyHashable: Any] else { - HMSErrorLogger.logError(#function, "No arguments found", "NULL_ERROR") - result(nil) + HMSErrorLogger.logError( + #function, + "No arguments found", + "NULL_ERROR" + ) + result( + nil + ) return } - + let hlsUrl = arguments["hls_url"] as? String - - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "start_hls_player", "hls_url": hlsUrl as Any]) - result(nil) + + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [ + METHOD_CALL: "start_hls_player", + "hls_url": hlsUrl as Any + ] + ) + result( + nil + ) } - + /** * Stops the HLS player by posting a notification with the specified method call. * * - Parameter result: The result object to be returned after stopping the player. */ - static private func stop(_ result: @escaping FlutterResult) { - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "stop_hls_player"]) - result(nil) + static private func stop( + _ result: @escaping FlutterResult + ) { + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [METHOD_CALL: "stop_hls_player"] + ) + result( + nil + ) } - + /** * Pauses the HLS player by posting a notification with the specified method call. * * - Parameter result: The result object to be returned after pausing the player. */ - static private func pause(_ result: @escaping FlutterResult) { - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "pause_hls_player"]) - result(nil) + static private func pause( + _ result: @escaping FlutterResult + ) { + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [METHOD_CALL: "pause_hls_player"] + ) + result( + nil + ) } - + /** * Resumes the HLS player by posting a notification with the specified method call. * * - Parameter result: The result object to be returned after resuming the player. */ - static private func resume(_ result: @escaping FlutterResult) { - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "resume_hls_player"]) - result(nil) + static private func resume( + _ result: @escaping FlutterResult + ) { + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [METHOD_CALL: "resume_hls_player"] + ) + result( + nil + ) } - + /** * Seeks to the live position in the HLS player by posting a notification with the specified method call. * * - Parameter result: The result object to be returned after seeking to the live position. */ - static private func seekToLivePosition(_ result: @escaping FlutterResult) { - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "seek_to_live_position"]) - result(nil) + static private func seekToLivePosition( + _ result: @escaping FlutterResult + ) { + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [METHOD_CALL: "seek_to_live_position"] + ) + result( + nil + ) } - + /** * Seeks forward in the HLS player by the specified number of seconds, posting a notification with the seek duration. * @@ -135,19 +241,39 @@ class HMSHLSPlayerAction { * - call: The method call object containing the number of seconds to seek forward as an argument. * - result: The result object to be returned after seeking forward. */ - static private func seekForward(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - + static private func seekForward( + _ call: FlutterMethodCall, + _ result: @escaping FlutterResult + ) { + guard let arguments = call.arguments as? [AnyHashable: Any], - let seconds = arguments["seconds"] as? Int else { - HMSErrorLogger.logError(#function, "seconds parameter is null", "NULL_ERROR") - result(nil) + let seconds = arguments["seconds"] as? Int else { + HMSErrorLogger.logError( + #function, + "seconds parameter is null", + "NULL_ERROR" + ) + result( + nil + ) return } - - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "seek_forward", "seconds": seconds]) - result(nil) + + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [ + METHOD_CALL: "seek_forward", + "seconds": seconds + ] + ) + result( + nil + ) } - + /** * Seeks backward in the HLS player by the specified number of seconds, posting a notification with the seek duration. * @@ -155,19 +281,39 @@ class HMSHLSPlayerAction { * - call: The method call object containing the number of seconds to seek backward as an argument. * - result: The result object to be returned after seeking backward. */ - static private func seekBackward(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - + static private func seekBackward( + _ call: FlutterMethodCall, + _ result: @escaping FlutterResult + ) { + guard let arguments = call.arguments as? [AnyHashable: Any], - let seconds = arguments["seconds"] as? Int else { - HMSErrorLogger.logError(#function, "seconds parameter is null", "NULL_ERROR") - result(nil) + let seconds = arguments["seconds"] as? Int else { + HMSErrorLogger.logError( + #function, + "seconds parameter is null", + "NULL_ERROR" + ) + result( + nil + ) return } - - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "seek_backward", "seconds": seconds]) - result(nil) + + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [ + METHOD_CALL: "seek_backward", + "seconds": seconds + ] + ) + result( + nil + ) } - + /** * Sets the volume level of the HLS player by posting a notification with the specified volume value. * @@ -175,53 +321,245 @@ class HMSHLSPlayerAction { * - call: The method call object containing the volume level as an argument. * - result: The result object to be returned after setting the volume. */ - static private func setVolume(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - + static private func setVolume( + _ call: FlutterMethodCall, + _ result: @escaping FlutterResult + ) { + guard let arguments = call.arguments as? [AnyHashable: Any], - let volume = arguments["volume"] as? Int else { - HMSErrorLogger.logError(#function, "volume parameter is null", "NULL_ERROR") - result(nil) + let volume = arguments["volume"] as? Int else { + HMSErrorLogger.logError( + #function, + "volume parameter is null", + "NULL_ERROR" + ) + result( + nil + ) return } - - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "set_hls_player_volume", "volume": volume]) - result(nil) + + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [ + METHOD_CALL: "set_hls_player_volume", + "volume": volume + ] + ) + result( + nil + ) } /** * Adds a listener to receive HLS player statistics by posting a notification with the corresponding method call. * * - Parameter result: The result object to be returned after adding the HLS stats listener. */ - static private func addHLSStatsListener(_ result: @escaping FlutterResult) { - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "add_hls_stats_listener"]) - result(nil) + static private func addHLSStatsListener( + _ result: @escaping FlutterResult + ) { + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [METHOD_CALL: "add_hls_stats_listener"] + ) + result( + nil + ) } - + /** * Removes the listener for HLS player statistics by posting a notification with the corresponding method call. * * - Parameter result: The result object to be returned after removing the HLS stats listener. */ - static private func removeHLSStatsListener(_ result: @escaping FlutterResult) { - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "remove_hls_stats_listener"]) - result(nil) + static private func removeHLSStatsListener( + _ result: @escaping FlutterResult + ) { + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [METHOD_CALL: "remove_hls_stats_listener"] + ) + result( + nil + ) } - static private func areClosedCaptionsSupported(_ result: @escaping FlutterResult){ - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "are_closed_captions_supported", "result": result]) + static private func areClosedCaptionsSupported( + _ result: @escaping FlutterResult + ){ + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [ + METHOD_CALL: "are_closed_captions_supported", + "result": result + ] + ) } - static private func enableClosedCaptions(_ result: @escaping FlutterResult){ - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "enable_closed_captions"]) - result(nil) + static private func enableClosedCaptions( + _ result: @escaping FlutterResult + ){ + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [METHOD_CALL: "enable_closed_captions"] + ) + result( + nil + ) } - static private func disableClosedCaptions(_ result: @escaping FlutterResult){ - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "disable_closed_captions"]) - result(nil) + static private func disableClosedCaptions( + _ result: @escaping FlutterResult + ){ + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [METHOD_CALL: "disable_closed_captions"] + ) + result( + nil + ) + } + + static private func getStreamProperties( + _ result: @escaping FlutterResult + ){ + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [ + METHOD_CALL: "get_stream_properties", + "result": result + ] + ) } - static private func getStreamProperties(_ result: @escaping FlutterResult){ - NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "get_stream_properties", "result": result]) + static private var layersMap = [ + + [ + "resolution": [ + "height": 1080.0, + "width": 1920.0 + ], + "bitrate": 4000 * 1000 + ], + [ + "resolution": [ + "height": 720.0, + "width": 1280.0 + ], + "bitrate": 1500 * 1000 + ], + [ + "resolution": [ + "height": 540.0, + "width": 960.0 + ], + "bitrate": 1000 * 1000 + ], + [ + "resolution": [ + "height": 480.0, + "width": 852.0 + ], + "bitrate": 850 * 1000 + ], + [ + "resolution": [ + "height": 360.0, + "width": 640.0 + ], + "bitrate": 450 * 1000 + ], + [ + "resolution": [ + "height": 240.0, + "width": 426.0 + ], + "bitrate": 300 * 1000 + ], + [ + "resolution": [ + "height": 144.0, + "width": 256.0 + ], + "bitrate": 200 * 1000 + ], + [ + "bitrate": nil + ] + + ] + + static private var currentBitrate : Any? = [ + "bitrate": nil + ] + + static private func getHLSLayers( + _ result: @escaping FlutterResult + ){ + var layers = [String:Any]() + layers["layers"] = layersMap + result(layers) + } + + static private func setHLSLayer( + _ call: FlutterMethodCall, + _ result: @escaping FlutterResult + ){ + guard let arguments = call.arguments as? [AnyHashable: Any], + let layer = arguments["layer"] as? [String:Any] else { + HMSErrorLogger.returnArgumentsError("hmsHLSLayer parameter is null") + return + } + + /* + Here if the bitrate is nil + we set it as zero otherwise the given bitrate is applied + */ + currentBitrate = layer["bitrate"] + NotificationCenter.default.post( + name: NSNotification.Name( + HLS_PLAYER_METHOD + ), + object: nil, + userInfo: [ + METHOD_CALL: "set_hls_layer", + "result": result, + "bitrate": layer["bitrate"] ?? 0 + ] + ) + } + + + static private func getCurrentHLSLayer( + _ result: @escaping FlutterResult + ){ + if let currentBitrate = currentBitrate as? Int { + let layer = layersMap.first { $0["bitrate"] as? Int == currentBitrate + } + result(layer) + return + } + result(nil) } } diff --git a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift index 67b265427..cbd25b182 100644 --- a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift +++ b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift @@ -300,7 +300,8 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene // MARK: - HLS Player - case "start_hls_player", "stop_hls_player", "pause_hls_player", "resume_hls_player", "seek_to_live_position", "seek_forward", "seek_backward", "set_hls_player_volume", "add_hls_stats_listener", "remove_hls_stats_listener", "are_closed_captions_supported", "enable_closed_captions", "disable_closed_captions", "get_stream_properties": + case "start_hls_player", "stop_hls_player", "pause_hls_player", "resume_hls_player", "seek_to_live_position", "seek_forward", "seek_backward", "set_hls_player_volume", "add_hls_stats_listener", "remove_hls_stats_listener", "are_closed_captions_supported", "enable_closed_captions", "disable_closed_captions", "get_stream_properties", + "get_hls_layers", "set_hls_layer", "get_current_hls_layer": HMSHLSPlayerAction.hlsPlayerAction(call, result) case "toggle_always_screen_on": diff --git a/packages/hmssdk_flutter/ios/Classes/Views/HMSHLSPlayerView.swift b/packages/hmssdk_flutter/ios/Classes/Views/HMSHLSPlayerView.swift index fc86ffa8d..7cf319b83 100644 --- a/packages/hmssdk_flutter/ios/Classes/Views/HMSHLSPlayerView.swift +++ b/packages/hmssdk_flutter/ios/Classes/Views/HMSHLSPlayerView.swift @@ -231,6 +231,17 @@ class HMSHLSPlayerView: NSObject, FlutterPlatformView { map["stream_duration"] = duration.seconds } result?(map) + + case "set_hls_layer": + + let result = notification.userInfo?["result"] as? FlutterResult + if let bitrate = notification.userInfo?["bitrate"] as? Int{ + hlsPlayer?._nativePlayer.currentItem?.preferredPeakBitRate = Double(bitrate) + result?(nil) + } else{ + HMSErrorLogger.logError("setHLSLayer", "bitrate is null", "NULL ERROR") + result?(nil) + } default: return diff --git a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart index 0107e3c6a..4fd3f1956 100644 --- a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart +++ b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart @@ -116,6 +116,7 @@ export 'src/model/polls/hms_poll_leaderboard_summary.dart'; export 'src/model/polls/hms_poll_peer_info_response.dart'; export 'src/model/hms_noise_cancellation_controller.dart'; export 'src/model/hls_stream_properties.dart'; +export 'src/model/hls_player/hms_hls_layer.dart'; //Views export 'src/ui/meeting/hms_texture_view.dart'; diff --git a/packages/hmssdk_flutter/lib/src/common/platform_methods.dart b/packages/hmssdk_flutter/lib/src/common/platform_methods.dart index 3b32138d3..74d11b5ea 100644 --- a/packages/hmssdk_flutter/lib/src/common/platform_methods.dart +++ b/packages/hmssdk_flutter/lib/src/common/platform_methods.dart @@ -188,6 +188,9 @@ enum PlatformMethod { enableClosedCaptions, disableClosedCaptions, getStreamProperties, + getHLSLayers, + setHLSLayer, + getCurrentHLSLayer, switchAudioOutputUsingiOSUI, sendHLSTimedMetadata, @@ -509,6 +512,12 @@ extension PlatformMethodValues on PlatformMethod { return "disable_closed_captions"; case PlatformMethod.getStreamProperties: return "get_stream_properties"; + case PlatformMethod.getHLSLayers: + return "get_hls_layers"; + case PlatformMethod.setHLSLayer: + return "set_hls_layer"; + case PlatformMethod.getCurrentHLSLayer: + return "get_current_hls_layer"; case PlatformMethod.switchAudioOutputUsingiOSUI: return "switch_audio_output_using_ios_ui"; @@ -856,6 +865,12 @@ extension PlatformMethodValues on PlatformMethod { return PlatformMethod.disableClosedCaptions; case "get_stream_properties": return PlatformMethod.getStreamProperties; + case "get_hls_layers": + return PlatformMethod.getHLSLayers; + case "set_hls_layer": + return PlatformMethod.setHLSLayer; + case "get_current_hls_layer": + return PlatformMethod.getCurrentHLSLayer; case "switch_audio_output_using_ios_ui": return PlatformMethod.switchAudioOutputUsingiOSUI; diff --git a/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_layer.dart b/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_layer.dart new file mode 100644 index 000000000..ec37783fd --- /dev/null +++ b/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_layer.dart @@ -0,0 +1,20 @@ +import 'package:hmssdk_flutter/hmssdk_flutter.dart'; + +class HMSHLSLayer { + HMSResolution? resolution; + int? bitrate; + + HMSHLSLayer({this.resolution, this.bitrate}); + + factory HMSHLSLayer.fromMap(Map map) { + return HMSHLSLayer( + resolution: map['resolution'] != null + ? HMSResolution.fromMap(map['resolution']) + : null, + bitrate: map['bitrate']); + } + + Map toMap() { + return {'resolution': this.resolution?.toMap(), 'bitrate': this.bitrate}; + } +} diff --git a/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_player_controller.dart b/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_player_controller.dart index e57192357..a849e0df6 100644 --- a/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_player_controller.dart +++ b/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_player_controller.dart @@ -143,4 +143,32 @@ class HMSHLSPlayerController { await PlatformService.invokeMethod(PlatformMethod.getStreamProperties); return HLSStreamProperties.fromMap(result); } + + static Future> getHLSLayers() async { + var result = + await PlatformService.invokeMethod(PlatformMethod.getHLSLayers); + List layers = []; + var hlsLayers = result?["layers"]; + if (hlsLayers != null) { + for (var layer in hlsLayers) { + layers.add(HMSHLSLayer.fromMap(layer)); + } + } + return layers; + } + + static Future setHLSLayer({required HMSHLSLayer hmsHLSLayer}) async { + await PlatformService.invokeMethod(PlatformMethod.setHLSLayer, + arguments: {"layer": hmsHLSLayer.toMap()}); + } + + static Future getCurrentHLSLayer() async { + var result = + await PlatformService.invokeMethod(PlatformMethod.getCurrentHLSLayer); + + if (result != null) { + return HMSHLSLayer.fromMap(result); + } + return null; + } } diff --git a/packages/hmssdk_flutter/pubspec.lock b/packages/hmssdk_flutter/pubspec.lock index 2932c9c3b..bfac3fa40 100644 --- a/packages/hmssdk_flutter/pubspec.lock +++ b/packages/hmssdk_flutter/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" fake_async: dependency: transitive description: @@ -59,6 +59,30 @@ packages: description: flutter source: sdk version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: "direct dev" description: @@ -71,34 +95,34 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.11.0" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" sky_engine: dependency: transitive description: flutter @@ -116,18 +140,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -148,10 +172,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" vector_math: dependency: transitive description: @@ -160,14 +184,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - web: + vm_service: dependency: transitive description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "13.0.0" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" + dart: ">=3.2.0-0 <4.0.0" flutter: ">=2.10.0" From bbb84caf8bbdf86e615bbaa91afeaac257ce08b7 Mon Sep 17 00:00:00 2001 From: Pushpam <93931528+Decoder07@users.noreply.github.com> Date: Tue, 7 May 2024 17:33:54 +0530 Subject: [PATCH 05/15] FLUT-284: Added `onPeerListUpdate` callback in preview (#1762) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added onPeerListUpdate callback in preview * 🤖 Automated Format and Fix * Merged branch * 🤖 Automated Format and Fix --------- Co-authored-by: Decoder07 --- .../lib/src/preview/preview_store.dart | 7 +++++ .../hms/hmssdk_flutter/HmssdkFlutterPlugin.kt | 28 +++++++++++++++++++ .../Classes/SwiftHmssdkFlutterPlugin.swift | 7 ++++- .../hms_preview_update_listener_method.dart | 3 ++ .../lib/src/model/hms_preview_listener.dart | 9 ++++++ .../lib/src/service/platform_service.dart | 27 ++++++++++++++++++ 6 files changed, 80 insertions(+), 1 deletion(-) diff --git a/packages/hms_room_kit/lib/src/preview/preview_store.dart b/packages/hms_room_kit/lib/src/preview/preview_store.dart index 0dd725855..9b2cbe847 100644 --- a/packages/hms_room_kit/lib/src/preview/preview_store.dart +++ b/packages/hms_room_kit/lib/src/preview/preview_store.dart @@ -316,4 +316,11 @@ class PreviewStore extends ChangeNotifier } notifyListeners(); } + + @override + void onPeerListUpdate( + {required List addedPeers, + required List removedPeers}) { + log("onPeerListUpdate -> addedPeers: $addedPeers removedPeers: $removedPeers"); + } } diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt index dc2a40e8c..1ecd8a21c 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt @@ -1516,6 +1516,34 @@ class HmssdkFlutterPlugin : } } } + + override fun peerListUpdated(addedPeers: ArrayList?, removedPeers: ArrayList?){ + val args = HashMap() + args["event_name"] = "on_peer_list_update" + val parameters = HashMap() + val peersAdded = ArrayList?>() + val peersRemoved = ArrayList?>() + /** + * Here we add peers to the list after parsing the + * peer object + */ + addedPeers?.forEach { peer -> + peersAdded.add(HMSPeerExtension.toDictionary(peer)) + } + + removedPeers?.forEach { peer -> + peersRemoved.add(HMSPeerExtension.toDictionary(peer)) + } + + parameters["added_peers"] = peersAdded + parameters["removed_peers"] = peersRemoved + + args["data"] = parameters + + CoroutineScope(Dispatchers.Main).launch { + previewSink?.success(args) + } + } } /*** diff --git a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift index cbd25b182..3fff710f8 100644 --- a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift +++ b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift @@ -1276,6 +1276,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene previewEnded = false previewSink?(data) } + var previewEnded = false public func on(join room: HMSRoom) { previewEnded = true @@ -1496,7 +1497,11 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene let data = ["event_name": "on_peer_list_update", "data": parameters] as [String: Any] - eventSink?(data) + if(previewEnded){ + eventSink?(data) + }else{ + previewSink?(data) + } } // MARK: - RTC Stats Listeners diff --git a/packages/hmssdk_flutter/lib/src/enum/hms_preview_update_listener_method.dart b/packages/hmssdk_flutter/lib/src/enum/hms_preview_update_listener_method.dart index 6fde86e34..9790a350d 100644 --- a/packages/hmssdk_flutter/lib/src/enum/hms_preview_update_listener_method.dart +++ b/packages/hmssdk_flutter/lib/src/enum/hms_preview_update_listener_method.dart @@ -4,6 +4,7 @@ enum HMSPreviewUpdateListenerMethod { onPeerUpdate, onRoomUpdate, onAudioDeviceChanged, + onPeerListUpdate, unknown } @@ -21,6 +22,8 @@ extension HMSPreviewUpdateListenerMethodValues return HMSPreviewUpdateListenerMethod.onRoomUpdate; case 'on_audio_device_changed': return HMSPreviewUpdateListenerMethod.onAudioDeviceChanged; + case 'on_peer_list_update': + return HMSPreviewUpdateListenerMethod.onPeerListUpdate; default: return HMSPreviewUpdateListenerMethod.unknown; } diff --git a/packages/hmssdk_flutter/lib/src/model/hms_preview_listener.dart b/packages/hmssdk_flutter/lib/src/model/hms_preview_listener.dart index 24229d226..4cabc9d82 100644 --- a/packages/hmssdk_flutter/lib/src/model/hms_preview_listener.dart +++ b/packages/hmssdk_flutter/lib/src/model/hms_preview_listener.dart @@ -50,4 +50,13 @@ abstract class HMSPreviewListener { void onAudioDeviceChanged( {HMSAudioDevice? currentAudioDevice, List? availableAudioDevice}); + + ///Upon joining a room with existing peers, onPeerListUpdated will be called with the list of peers present + ///in the room instead of getting onPeerUpdate for each peer in the room. + ///Subsequent peer joins/leaves would be notified via both onPeerUpdate and onPeerListUpdated + /// - Parameters: + /// - addedPeers: List of peers who joined the room + /// - removedPeers: List of peers who left the room + void onPeerListUpdate( + {required List addedPeers, required List removedPeers}); } diff --git a/packages/hmssdk_flutter/lib/src/service/platform_service.dart b/packages/hmssdk_flutter/lib/src/service/platform_service.dart index 959ba0557..a9b01ea4a 100644 --- a/packages/hmssdk_flutter/lib/src/service/platform_service.dart +++ b/packages/hmssdk_flutter/lib/src/service/platform_service.dart @@ -412,6 +412,27 @@ abstract class PlatformService { : null }); break; + case HMSPreviewUpdateListenerMethod.onPeerListUpdate: + List addedPeers = []; + List removedPeers = []; + + if (event.data.containsKey("added_peers") && + event.data["added_peers"] != null) { + for (var peer in event.data["added_peers"]) { + addedPeers.add(HMSPeer.fromMap(peer)); + } + } + + if (event.data.containsKey("removed_peers") && + event.data["removed_peers"] != null) { + for (var peer in event.data["removed_peers"]) { + removedPeers.add(HMSPeer.fromMap(peer)); + } + } + + notifyPreviewListeners(method, + {"added_peers": addedPeers, "removed_peers": removedPeers}); + break; } }); @@ -614,6 +635,12 @@ abstract class PlatformService { availableAudioDevice: arguments["available_audio_device"]); }); break; + case HMSPreviewUpdateListenerMethod.onPeerListUpdate: + previewListeners.forEach((e) { + e.onPeerListUpdate( + addedPeers: arguments["added_peers"], + removedPeers: arguments["removed_peers"]); + }); } } From 5b12fa4183990bdf278f376bc0f81a6ac88b1a83 Mon Sep 17 00:00:00 2001 From: Pushpam <93931528+Decoder07@users.noreply.github.com> Date: Fri, 10 May 2024 12:53:09 +0530 Subject: [PATCH 06/15] FLUT-298: Whiteboard Support in flutter SDK and prebuilt (#1761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added whiteboard methods * Added whiteboard methods * Added whiteboard option * Added whiteboard option * Fixed whiteboard bug * Handled screenshare * Added screenshare check * Updated build version * released sample app version 1.5.187 (487) 🍀 * 🤖 Automated Format and Fix * 🤖 Automated Format and Fix * Removed action result listener usage (#1763) * 🤖 Automated Format and Fix * updated branch * Updated gemfile * released sample app version 1.5.188 (488) 🍀 * 🤖 Automated Format and Fix * updated iOS SDK * released sample app version 1.5.189 (489) 🍀 * released sample app version 1.5.191 (491) 🍀 --------- Co-authored-by: Decoder07 Co-authored-by: ygit Co-authored-by: Yogesh Singh --- packages/hms_room_kit/example/pubspec.lock | 66 ++- .../lib/src/meeting/meeting_store.dart | 469 ++++++++++-------- .../app_utilities_bottom_sheet.dart | 40 ++ .../screen_share_grid_layout.dart | 283 ++++++----- .../meeting_modes/custom_one_to_one_grid.dart | 47 +- .../whiteboard_screenshare_store.dart | 14 + .../whiteboard_tile.dart | 65 +++ .../whiteboard_webview.dart | 46 ++ packages/hms_room_kit/pubspec.lock | 66 ++- packages/hms_room_kit/pubspec.yaml | 2 + packages/hmssdk_flutter/android/build.gradle | 12 +- .../hms/hmssdk_flutter/HMSRoleExtension.kt | 11 +- .../hmssdk_flutter/HMSWhiteboardExtension.kt | 25 + .../hms/hmssdk_flutter/HmssdkFlutterPlugin.kt | 69 +++ .../PermissionParamsExtension.kt | 14 + .../methods/HMSWhiteboardAction.kt | 35 ++ .../example/ExampleAppChangelog.txt | 8 +- .../example/android/app/build.gradle | 4 +- .../plugins/GeneratedPluginRegistrant.java | 5 + .../hmssdk_flutter/example/ios/Gemfile.lock | 10 +- .../hmssdk_flutter/example/ios/Podfile.lock | 77 +-- .../example/ios/Runner/Info.plist | 4 +- packages/hmssdk_flutter/example/pubspec.lock | 68 ++- packages/hmssdk_flutter/example/pubspec.yaml | 2 + .../Classes/Actions/HMSWhiteboardAction.swift | 69 +++ .../Models/HMSPermissionExtension.swift | 25 +- .../Models/HMSWhiteboardExtension.swift | 31 ++ .../Classes/SwiftHmssdkFlutterPlugin.swift | 62 ++- .../lib/assets/sdk-versions.json | 2 +- .../hmssdk_flutter/lib/hmssdk_flutter.dart | 6 +- .../lib/src/common/platform_methods.dart | 29 +- .../enum/hms_whiteboard_listener_method.dart | 19 + .../lib/src/model/hms_permissions.dart | 26 +- .../src/model/platform_method_response.dart | 11 + .../whiteboard/hms_whiteboard_controller.dart | 36 ++ .../whiteboard/hms_whiteboard_model.dart | 27 + .../whiteboard/hms_whiteboard_permission.dart | 15 + .../hms_whiteboard_update_listener.dart | 7 + .../lib/src/service/platform_service.dart | 41 ++ 39 files changed, 1410 insertions(+), 438 deletions(-) create mode 100644 packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_screenshare_store.dart create mode 100644 packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_tile.dart create mode 100644 packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_webview.dart create mode 100644 packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt create mode 100644 packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSWhiteboardAction.kt create mode 100644 packages/hmssdk_flutter/ios/Classes/Actions/HMSWhiteboardAction.swift create mode 100644 packages/hmssdk_flutter/ios/Classes/Models/HMSWhiteboardExtension.swift create mode 100644 packages/hmssdk_flutter/lib/src/enum/hms_whiteboard_listener_method.dart create mode 100644 packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart create mode 100644 packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_model.dart create mode 100644 packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_permission.dart create mode 100644 packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_update_listener.dart diff --git a/packages/hms_room_kit/example/pubspec.lock b/packages/hms_room_kit/example/pubspec.lock index 129792546..9570935fd 100644 --- a/packages/hms_room_kit/example/pubspec.lock +++ b/packages/hms_room_kit/example/pubspec.lock @@ -213,7 +213,7 @@ packages: path: "../../hmssdk_flutter" relative: true source: path - version: "1.10.1" + version: "1.10.2" http: dependency: transitive description: @@ -438,6 +438,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pointer_interceptor: + dependency: transitive + description: + name: pointer_interceptor + sha256: bd18321519718678d5fa98ad3a3359cbc7a31f018554eab80b73d08a7f0c165a + url: "https://pub.dev" + source: hosted + version: "0.10.1" + pointer_interceptor_ios: + dependency: transitive + description: + name: pointer_interceptor_ios + sha256: "2e73c39452830adc4695757130676a39412a3b7f3c34e3f752791b5384770877" + url: "https://pub.dev" + source: hosted + version: "0.10.0+2" + pointer_interceptor_platform_interface: + dependency: transitive + description: + name: pointer_interceptor_platform_interface + sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506" + url: "https://pub.dev" + source: hosted + version: "0.10.0+1" + pointer_interceptor_web: + dependency: transitive + description: + name: pointer_interceptor_web + sha256: "2a8a069206f7b234a895d30ccab8b18ea267eeb79a832e5e3d1b6464d659eb6a" + url: "https://pub.dev" + source: hosted + version: "0.10.0" pointycastle: dependency: transitive description: @@ -723,6 +755,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.4-beta" + webview_flutter: + dependency: transitive + description: + name: webview_flutter + sha256: d81b68e88cc353e546afb93fb38958e3717282c5ac6e5d3be4a4aef9fc3c1413 + url: "https://pub.dev" + source: hosted + version: "4.5.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: dad3313c9ead95517bb1cae5e1c9d20ba83729d5a59e5e83c0a2d66203f27f91 + url: "https://pub.dev" + source: hosted + version: "3.16.1" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + url: "https://pub.dev" + source: hosted + version: "2.10.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: "4d062ad505390ecef1c4bfb6001cd857a51e00912cc9dfb66edb1886a9ebd80c" + url: "https://pub.dev" + source: hosted + version: "3.10.2" win32: dependency: transitive description: diff --git a/packages/hms_room_kit/lib/src/meeting/meeting_store.dart b/packages/hms_room_kit/lib/src/meeting/meeting_store.dart index 95a80691a..cf43e2ce9 100644 --- a/packages/hms_room_kit/lib/src/meeting/meeting_store.dart +++ b/packages/hms_room_kit/lib/src/meeting/meeting_store.dart @@ -36,7 +36,8 @@ class MeetingStore extends ChangeNotifier HMSLogListener, HMSKeyChangeListener, HMSHLSPlaybackEventsListener, - HMSPollListener { + HMSPollListener, + HMSWhiteboardUpdateListener { late HMSSDKInteractor _hmsSDKInteractor; MeetingStore({required HMSSDKInteractor hmsSDKInteractor}) { @@ -45,6 +46,8 @@ class MeetingStore extends ChangeNotifier bool isSpeakerOn = true; + ///Integer to store the number of screenshare in the meeting + ///This does not count the local screenshare int screenShareCount = 0; HMSException? hmsException; @@ -263,6 +266,12 @@ class MeetingStore extends ChangeNotifier ///Boolean to track whether noise cancellation is enabled or not bool isNoiseCancellationEnabled = false; + ///Boolean to track whether whiteboard is enabled or not + bool isWhiteboardEnabled = false; + + ///variable to store whiteboard model + HMSWhiteboardModel? whiteboardModel; + Future join(String userName, String? tokenData) async { late HMSConfig joinConfig; @@ -892,6 +901,7 @@ class MeetingStore extends ChangeNotifier setViewControllers(); notifyListeners(); fetchPollList(HMSPollState.stopped); + HMSWhiteboardController.addHMSWhiteboardUpdateListener(listener: this); if (HMSRoomLayout.roleLayoutData?.screens?.preview?.joinForm?.joinBtnType == JoinButtonType.JOIN_BTN_TYPE_JOIN_AND_GO_LIVE && @@ -1380,6 +1390,7 @@ class MeetingStore extends ChangeNotifier _hmsSDKInteractor.removeHMSLogger(); HMSHLSPlayerController.removeHMSHLSPlaybackEventsListener(this); HMSPollInteractivityCenter.removePollUpdateListener(); + HMSWhiteboardController.removeHMSWhiteboardUpdateListener(); } ///Function to toggle screen share @@ -1702,6 +1713,16 @@ class MeetingStore extends ChangeNotifier switch (update) { case HMSTrackUpdate.trackAdded: if (track.source != "REGULAR") { + ///whenever a screen is shared and if the whiteboard is enabled + ///we check whether the whiteboard is started by us and if yes + ///we stop the whiteboard + if (isWhiteboardEnabled) { + if (whiteboardModel?.owner?.customerUserId == + localPeer?.customerUserId) { + HMSWhiteboardController.stop(); + } + } + if (!peer.isLocal) { int peerIndex = peerTracks.indexWhere( (element) => element.uid == peer.peerId + track.trackId); @@ -2394,6 +2415,245 @@ class MeetingStore extends ChangeNotifier notifyListeners(); } + void toggleWhiteboard() async { + if (isWhiteboardEnabled) { + if (localPeer?.peerId == whiteboardModel?.owner?.peerId) { + HMSException? error = await HMSWhiteboardController.stop(); + if (error != null) { + log("HMSWhiteboardController.stop error: ${error.description}"); + } + } + } else if (!isScreenShareOn && screenShareCount == 0) { + HMSException? error = + await HMSWhiteboardController.start(title: "Whiteboard From Flutter"); + if (error != null) { + log("HMSWhiteboardController.start error: ${error.description}"); + } + } + notifyListeners(); + } + + @override + void onLogMessage({required HMSLogList hmsLogList}) { + notifyListeners(); + } + + @override + void onVideoSizeChanged({required Size size}) {} + + @override + void onCue({required HMSHLSCue hlsCue}) { + log("onCue -> payload:${hlsCue.startDate}"); + + if (hlsCue.payload != null) { + /* + * Below code shows the poll for hls-viewer who are viewing stream at a delay. + * Here we get pollId from the payload and we find the poll object + * from `onPollUpdate` we use this object to show the toast for the poll. + * Mock payload for poll looks like "poll:{poll_id}" + */ + if (hlsCue.payload!.startsWith("poll:")) { + var pollId = hlsCue.payload?.replaceFirst(RegExp(r'^poll:'), ""); + int? index = hlsViewerPolls + .indexWhere((element) => element.poll.pollId == pollId); + if (index != -1) { + toasts.add(HMSToastModel(hlsViewerPolls[index], + hmsToastType: HMSToastsType.pollStartedToast)); + pollQuestions.add(hlsViewerPolls[index]); + hlsViewerPolls.removeAt(index); + notifyListeners(); + } + } + + /*******************************This is the implementation for showing emoji's in HLS *******************/ + /** + * Generally we are assuming that the timed metadata payload will be a JSON String + * but if it's a normal string then this throws the format exception + * Hence we catch it and display the payload as string on toast. + * The toast is displayed for the time duration hlsCue.endDate - hlsCue.startDate + * If endDate is null then toast is displayed for 2 seconds by default + */ + // try { + // final Map data = jsonDecode(hlsCue.payload!); + // Utilities.showTimedMetadata( + // Utilities.getTimedMetadataEmojiFromId(data["emojiId"]), + // time: hlsCue.endDate == null + // ? 2 + // : (hlsCue.endDate!.difference(hlsCue.startDate)).inSeconds, + // align: Utilities.timedMetadataAlignment[math.Random() + // .nextInt(Utilities.timedMetadataAlignment.length)]); + // } catch (e) { + // Utilities.showTimedMetadata(hlsCue.payload!, + // time: hlsCue.endDate == null + // ? 2 + // : (hlsCue.endDate!.difference(hlsCue.startDate)).inSeconds, + // align: Utilities.timedMetadataAlignment[math.Random() + // .nextInt(Utilities.timedMetadataAlignment.length)]); + // } + /************************************************************************************************************/ + } + } + + @override + void onPlaybackFailure({required String? error}) {} + + @override + void onPlaybackStateChanged({required HMSHLSPlaybackState playbackState}) {} + + @override + void onHLSError({required HMSException hlsException}) {} + + @override + void onHLSEventUpdate({required HMSHLSPlayerStats playerStats}) {} + + ///Insert poll question + void insertPollQuestion(HMSPollStore store) { + pollQuestions.add(store); + sortPollQuestions(); + } + + ///Function to sort poll questions based on state and startedAt time + void sortPollQuestions() { + pollQuestions.sort((a, b) { + if (a.poll.state != b.poll.state) { + return a.poll.state == HMSPollState.started + ? 1 + : a.poll.state == HMSPollState.created + ? 2 + : -1; + } else { + if (a.poll.startedAt != null && b.poll.startedAt != null) { + return a.poll.startedAt!.compareTo(b.poll.startedAt!); + } + } + return 1; + }); + notifyListeners(); + } + + @override + void onPeerListUpdate( + {required List addedPeers, + required List removedPeers}) { + log("onPeerListUpdate -> addedPeers: $addedPeers removedPeers: $removedPeers"); + for (var peer in addedPeers) { + addPeer(peer); + } + } + + @override + void onPollUpdate( + {required HMSPoll poll, required HMSPollUpdateType pollUpdateType}) { + log("onPollUpdate -> poll $poll updateType: $pollUpdateType}"); + switch (pollUpdateType) { + ///If the poll is started we add the poll in questions list + case HMSPollUpdateType.started: + if (poll.createdBy?.peerId == localPeer?.peerId) { + ///Send timed metadata for polls/quiz created by local peer. + sendHLSTimedMetadata([ + HMSHLSTimedMetadata( + metadata: "poll:${poll.pollId}", duration: _hlsCueDuration) + ]); + } + + /* + * Here we check whether the peer has permission to view polls + * Then if the user is a realtime user we show the poll immediately + * while for hls viewer we show the poll based on the `onCue` event i.e. + * timed metadata event for poll + */ + if ((localPeer?.role.permissions.pollRead ?? false) || + (localPeer?.role.permissions.pollWrite ?? false)) { + int index = pollQuestions + .indexWhere((element) => element.poll.pollId == poll.pollId); + if (index == -1) { + HMSPollStore store = HMSPollStore(poll: poll); + if (HMSRoomLayout.peerType == PeerRoleType.conferencing) { + insertPollQuestion(store); + toasts.add(HMSToastModel(store, + hmsToastType: HMSToastsType.pollStartedToast)); + notifyListeners(); + } else { + /* + * Here we check whether the poll start time is + * more than 20 secs older from now or not. We have kept 20 secs + * since the stream playback rolling window time is + * set to 20 by default i.e. if the time difference is less than 20 secs + * we will get the [onCue] callback again. If its greater than 20 + * we show the toast immediately for the user to vote. + */ + if (poll.startedAt != null && + (DateTime.now().difference(poll.startedAt!) > + Duration(seconds: _hlsCueDuration))) { + insertPollQuestion(store); + toasts.add(HMSToastModel(store, + hmsToastType: HMSToastsType.pollStartedToast)); + } else { + hlsViewerPolls.add(store); + } + } + } else { + ///This handles the draft polls since they are already in the list + ///Here we update the poll in HMSPollStore and add toast as the poll state changes + ///from `created` to `started`. + pollQuestions[index].updateState(poll); + sortPollQuestions(); + toasts.add(HMSToastModel(pollQuestions[index], + hmsToastType: HMSToastsType.pollStartedToast)); + } + } + break; + + ///In other cases we just update the state of the poll + case HMSPollUpdateType.resultsupdated: + int index = pollQuestions + .indexWhere((element) => element.poll.pollId == poll.pollId); + if (index != -1) { + pollQuestions[index].updateState(poll); + } + notifyListeners(); + break; + + case HMSPollUpdateType.stopped: + + ///If it's a quiz we fetch the leaderboard + if (poll.category == HMSPollCategory.quiz) { + fetchLeaderboard(poll); + } + + ///Here we remove the toast if it's present + ///update the poll in HMSPollStore and sort the poll questions + removeToast(HMSToastsType.pollStartedToast, data: poll.pollId); + int index = pollQuestions + .indexWhere((element) => element.poll.pollId == poll.pollId); + if (index != -1) { + pollQuestions[index].updateState(poll); + sortPollQuestions(); + } + notifyListeners(); + break; + } + } + + @override + void onCues({required List subtitles}) {} + + @override + void onWhiteboardStart({required HMSWhiteboardModel hmsWhiteboardModel}) { + isWhiteboardEnabled = true; + whiteboardModel = hmsWhiteboardModel; + log("onWhiteboardStart -> peerId: ${hmsWhiteboardModel.owner?.peerId} localPeer: ${localPeer?.peerId} title: ${hmsWhiteboardModel.title}"); + notifyListeners(); + } + + @override + void onWhiteboardStop({required HMSWhiteboardModel hmsWhiteboardModel}) { + isWhiteboardEnabled = false; + whiteboardModel = null; + log("onWhiteboardStop -> peerId: ${hmsWhiteboardModel.owner?.peerId} localPeer: ${localPeer?.peerId} title: ${hmsWhiteboardModel.title}"); + notifyListeners(); + } + //Get onSuccess or onException callbacks for HMSActionResultListenerMethod @override void onSuccess( @@ -2698,211 +2958,4 @@ class MeetingStore extends ChangeNotifier // notifyListeners(); // } } - - @override - void onLogMessage({required HMSLogList hmsLogList}) { - notifyListeners(); - } - - @override - void onVideoSizeChanged({required Size size}) {} - - @override - void onCue({required HMSHLSCue hlsCue}) { - log("onCue -> payload:${hlsCue.startDate}"); - - if (hlsCue.payload != null) { - /* - * Below code shows the poll for hls-viewer who are viewing stream at a delay. - * Here we get pollId from the payload and we find the poll object - * from `onPollUpdate` we use this object to show the toast for the poll. - * Mock payload for poll looks like "poll:{poll_id}" - */ - if (hlsCue.payload!.startsWith("poll:")) { - var pollId = hlsCue.payload?.replaceFirst(RegExp(r'^poll:'), ""); - int? index = hlsViewerPolls - .indexWhere((element) => element.poll.pollId == pollId); - if (index != -1) { - toasts.add(HMSToastModel(hlsViewerPolls[index], - hmsToastType: HMSToastsType.pollStartedToast)); - pollQuestions.add(hlsViewerPolls[index]); - hlsViewerPolls.removeAt(index); - notifyListeners(); - } - } - - /*******************************This is the implementation for showing emoji's in HLS *******************/ - /** - * Generally we are assuming that the timed metadata payload will be a JSON String - * but if it's a normal string then this throws the format exception - * Hence we catch it and display the payload as string on toast. - * The toast is displayed for the time duration hlsCue.endDate - hlsCue.startDate - * If endDate is null then toast is displayed for 2 seconds by default - */ - // try { - // final Map data = jsonDecode(hlsCue.payload!); - // Utilities.showTimedMetadata( - // Utilities.getTimedMetadataEmojiFromId(data["emojiId"]), - // time: hlsCue.endDate == null - // ? 2 - // : (hlsCue.endDate!.difference(hlsCue.startDate)).inSeconds, - // align: Utilities.timedMetadataAlignment[math.Random() - // .nextInt(Utilities.timedMetadataAlignment.length)]); - // } catch (e) { - // Utilities.showTimedMetadata(hlsCue.payload!, - // time: hlsCue.endDate == null - // ? 2 - // : (hlsCue.endDate!.difference(hlsCue.startDate)).inSeconds, - // align: Utilities.timedMetadataAlignment[math.Random() - // .nextInt(Utilities.timedMetadataAlignment.length)]); - // } - /************************************************************************************************************/ - } - } - - @override - void onPlaybackFailure({required String? error}) {} - - @override - void onPlaybackStateChanged({required HMSHLSPlaybackState playbackState}) {} - - @override - void onHLSError({required HMSException hlsException}) {} - - @override - void onHLSEventUpdate({required HMSHLSPlayerStats playerStats}) {} - - ///Insert poll question - void insertPollQuestion(HMSPollStore store) { - pollQuestions.add(store); - sortPollQuestions(); - } - - ///Function to sort poll questions based on state and startedAt time - void sortPollQuestions() { - pollQuestions.sort((a, b) { - if (a.poll.state != b.poll.state) { - return a.poll.state == HMSPollState.started - ? 1 - : a.poll.state == HMSPollState.created - ? 2 - : -1; - } else { - if (a.poll.startedAt != null && b.poll.startedAt != null) { - return a.poll.startedAt!.compareTo(b.poll.startedAt!); - } - } - return 1; - }); - notifyListeners(); - } - - @override - void onPeerListUpdate( - {required List addedPeers, - required List removedPeers}) { - log("onPeerListUpdate -> addedPeers: $addedPeers removedPeers: $removedPeers"); - for (var peer in addedPeers) { - addPeer(peer); - } - } - - @override - void onPollUpdate( - {required HMSPoll poll, required HMSPollUpdateType pollUpdateType}) { - log("onPollUpdate -> poll $poll updateType: $pollUpdateType}"); - switch (pollUpdateType) { - ///If the poll is started we add the poll in questions list - case HMSPollUpdateType.started: - if (poll.createdBy?.peerId == localPeer?.peerId) { - ///Send timed metadata for polls/quiz created by local peer. - sendHLSTimedMetadata([ - HMSHLSTimedMetadata( - metadata: "poll:${poll.pollId}", duration: _hlsCueDuration) - ]); - } - - /* - * Here we check whether the peer has permission to view polls - * Then if the user is a realtime user we show the poll immediately - * while for hls viewer we show the poll based on the `onCue` event i.e. - * timed metadata event for poll - */ - if ((localPeer?.role.permissions.pollRead ?? false) || - (localPeer?.role.permissions.pollWrite ?? false)) { - int index = pollQuestions - .indexWhere((element) => element.poll.pollId == poll.pollId); - if (index == -1) { - HMSPollStore store = HMSPollStore(poll: poll); - if (HMSRoomLayout.peerType == PeerRoleType.conferencing) { - insertPollQuestion(store); - toasts.add(HMSToastModel(store, - hmsToastType: HMSToastsType.pollStartedToast)); - notifyListeners(); - } else { - /* - * Here we check whether the poll start time is - * more than 20 secs older from now or not. We have kept 20 secs - * since the stream playback rolling window time is - * set to 20 by default i.e. if the time difference is less than 20 secs - * we will get the [onCue] callback again. If its greater than 20 - * we show the toast immediately for the user to vote. - */ - if (poll.startedAt != null && - (DateTime.now().difference(poll.startedAt!) > - Duration(seconds: _hlsCueDuration))) { - insertPollQuestion(store); - toasts.add(HMSToastModel(store, - hmsToastType: HMSToastsType.pollStartedToast)); - } else { - hlsViewerPolls.add(store); - } - } - } else { - ///This handles the draft polls since they are already in the list - ///Here we update the poll in HMSPollStore and add toast as the poll state changes - ///from `created` to `started`. - pollQuestions[index].updateState(poll); - sortPollQuestions(); - toasts.add(HMSToastModel(pollQuestions[index], - hmsToastType: HMSToastsType.pollStartedToast)); - } - } - break; - - ///In other cases we just update the state of the poll - case HMSPollUpdateType.resultsupdated: - int index = pollQuestions - .indexWhere((element) => element.poll.pollId == poll.pollId); - if (index != -1) { - pollQuestions[index].updateState(poll); - } - notifyListeners(); - break; - - case HMSPollUpdateType.stopped: - - ///If it's a quiz we fetch the leaderboard - if (poll.category == HMSPollCategory.quiz) { - fetchLeaderboard(poll); - } - - ///Here we remove the toast if it's present - ///update the poll in HMSPollStore and sort the poll questions - removeToast(HMSToastsType.pollStartedToast, data: poll.pollId); - int index = pollQuestions - .indexWhere((element) => element.poll.pollId == poll.pollId); - if (index != -1) { - pollQuestions[index].updateState(poll); - sortPollQuestions(); - } - notifyListeners(); - break; - } - } - - @override - void onCues({required List subtitles}) { - // TODO: implement onCues - } } diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/app_utilities_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/app_utilities_bottom_sheet.dart index 141d1ff5f..68a727751 100644 --- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/app_utilities_bottom_sheet.dart +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/app_utilities_bottom_sheet.dart @@ -42,6 +42,24 @@ class _AppUtilitiesBottomSheetState extends State { super.deactivate(); } + Color geWhiteboardStatusColor(MeetingStore meetingStore) { + ///If whiteboard is enabled and the local peer is the owner of the whiteboard + ///we return high emphasis color since the local peer can close the whiteboard + ///else we return low emphasis color since local peer can't close the whiteboard + /// + ///In other case if whiteboard is not enabled and screen share is ON + ///we return low emphasis color since whiteboard can't be turned ON + ///In other cases we return high emphasis color + return meetingStore.isWhiteboardEnabled + ? meetingStore.whiteboardModel?.owner?.customerUserId == + meetingStore.localPeer?.customerUserId + ? HMSThemeColors.onSurfaceHighEmphasis + : HMSThemeColors.onSurfaceLowEmphasis + : meetingStore.screenShareCount > 0 || meetingStore.isScreenShareOn + ? HMSThemeColors.onSurfaceLowEmphasis + : HMSThemeColors.onSurfaceHighEmphasis; + } + @override Widget build(BuildContext context) { MeetingStore meetingStore = context.read(); @@ -381,6 +399,28 @@ class _AppUtilitiesBottomSheetState extends State { optionText: meetingStore.isNoiseCancellationEnabled ? "Noise Reduced" : "Reduce Noise"), + + if (meetingStore + .localPeer?.role.permissions.whiteboard?.admin ?? + false) + MoreOptionItem( + onTap: () async { + meetingStore.toggleWhiteboard(); + Navigator.pop(context); + }, + isActive: false, + optionIcon: SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/pencil.svg", + height: 20, + width: 20, + colorFilter: ColorFilter.mode( + geWhiteboardStatusColor(meetingStore), + BlendMode.srcIn), + ), + optionTextColor: geWhiteboardStatusColor(meetingStore), + optionText: meetingStore.isWhiteboardEnabled + ? "Close Whiteboard" + : "Open Whiteboard"), ], ), ], diff --git a/packages/hms_room_kit/lib/src/widgets/grid_layouts/screen_share_grid_layout.dart b/packages/hms_room_kit/lib/src/widgets/grid_layouts/screen_share_grid_layout.dart index a1029606e..dd68dca23 100644 --- a/packages/hms_room_kit/lib/src/widgets/grid_layouts/screen_share_grid_layout.dart +++ b/packages/hms_room_kit/lib/src/widgets/grid_layouts/screen_share_grid_layout.dart @@ -7,6 +7,8 @@ import 'package:hmssdk_flutter/hmssdk_flutter.dart'; import 'package:provider/provider.dart'; ///Project imports +import 'package:hms_room_kit/src/widgets/whiteboard_screenshare/whiteboard_screenshare_store.dart'; +import 'package:hms_room_kit/src/widgets/whiteboard_screenshare/whiteboard_tile.dart'; import 'package:hms_room_kit/src/layout_api/hms_theme_colors.dart'; import 'package:hms_room_kit/src/meeting/meeting_store.dart'; import 'package:hms_room_kit/src/model/peer_track_node.dart'; @@ -20,8 +22,12 @@ import 'package:hms_room_kit/src/widgets/grid_layouts/side_by_side_layout.dart'; class ScreenshareGridLayout extends StatefulWidget { final List peerTracks; final int screenshareCount; + final HMSWhiteboardModel? whiteboardModel; const ScreenshareGridLayout( - {super.key, required this.peerTracks, required this.screenshareCount}); + {super.key, + required this.peerTracks, + required this.screenshareCount, + this.whiteboardModel}); @override State createState() => _ScreenshareGridLayoutState(); @@ -34,133 +40,162 @@ class _ScreenshareGridLayoutState extends State { @override Widget build(BuildContext context) { ///Here we render screenshare and peer tiles in a Column - return Column( - children: [ - ///This renders the screenshare at the top half of the screen - Flexible( - flex: 2, - child: Column( - children: [ - Expanded( - child: PageView.builder( - physics: const PageScrollPhysics(), - allowImplicitScrolling: true, - itemCount: widget.screenshareCount, - onPageChanged: (newPage) { - context - .read() - .setCurrentScreenSharePage(newPage); - }, + return Selector( + selector: (_, whiteboardScreenshareStore) => + whiteboardScreenshareStore.isFullScreen, + builder: (_, isFullScreen, __) { + return Column( + children: [ + ///This renders the screenshare or whiteboard at the top 2/3 of the screen + Flexible( + flex: 2, + child: Column( + ///There will not be a case where whiteboard and screenshare are enabled at the same time + ///So we check if the whiteboard is enabled and render the whiteboard tile + ///Else we render the screenshare tile + children: [ + ///If the whiteboard is enabled we + ///render the whiteboard tile we check this with the whiteboardeModel + if (widget.whiteboardModel != null && + widget.whiteboardModel?.url != null) + Expanded(child: const WhiteboardTile()), - ///Setting the scale type for screenshare widget as fit - itemBuilder: (context, index) { - return ListenablePeerWidget( - peerTracks: widget.peerTracks, - index: index, - scaleType: ScaleType.SCALE_ASPECT_FIT, - ); - }, - ), - ), + ///This renders the screenshare tile based on the + ///screenshare count + ///Note: This doesn't account for local screenshare since + ///we don't render a tile for local screenshare + if (widget.screenshareCount > 0) + Expanded( + child: PageView.builder( + physics: const PageScrollPhysics(), + allowImplicitScrolling: true, + itemCount: widget.screenshareCount, + onPageChanged: (newPage) { + context + .read() + .setCurrentScreenSharePage(newPage); + }, - ///This renders the dots at the bottom of the grid view - ///This is only rendered if the number of pages is greater than 1 - ///The number of dots is equal to [number of screens being shared] - ///The active dot is the current page - ///The inactive dots are the pages other than the current page - if (widget.screenshareCount > 1) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Selector( - selector: (_, meetingStore) => - meetingStore.currentScreenSharePage, - builder: (_, currentScreenSharePage, __) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: DotsIndicator( - dotsCount: widget.screenshareCount, - position: currentScreenSharePage, - decorator: DotsDecorator( - activeColor: - HMSThemeColors.onSurfaceHighEmphasis, - color: HMSThemeColors.onSurfaceLowEmphasis), - ), - ); - }), - ) - ], - )), + ///Setting the scale type for screenshare widget as fit + itemBuilder: (context, index) { + return ListenablePeerWidget( + peerTracks: widget.peerTracks, + index: index, + scaleType: ScaleType.SCALE_ASPECT_FIT, + ); + }, + ), + ), - ///This renders the peer tiles at the bottom half of the screen - Flexible( - flex: 1, - child: Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Column( - children: [ - Expanded( - child: PageView.builder( - physics: const PageScrollPhysics(), - allowImplicitScrolling: true, - onPageChanged: (newPage) { - context.read().setCurrentPage(newPage); - }, - itemCount: (((widget.peerTracks.length - - widget.screenshareCount) ~/ - 2) + - (widget.peerTracks.length - widget.screenshareCount) % - 2), - itemBuilder: (context, index) { - return SideBySideLayout( - numberOfTiles: widget.peerTracks.length - - widget.screenshareCount, - index: index, - peerTracks: widget.peerTracks - .sublist(widget.screenshareCount)); - }, - ), - ), + ///This renders the dots at the bottom of the grid view + ///This is only rendered if the number of pages is greater than 1 + ///The number of dots is equal to [number of screens being shared] + ///The active dot is the current page + ///The inactive dots are the pages other than the current page + if (widget.screenshareCount > 1) + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Selector( + selector: (_, meetingStore) => + meetingStore.currentScreenSharePage, + builder: (_, currentScreenSharePage, __) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: DotsIndicator( + dotsCount: widget.screenshareCount, + position: currentScreenSharePage, + decorator: DotsDecorator( + activeColor: HMSThemeColors + .onSurfaceHighEmphasis, + color: HMSThemeColors + .onSurfaceLowEmphasis), + ), + ); + }), + ) + ], + )), - ///This renders the dots at the bottom of the grid view - ///This is only rendered if the number of pages is greater than 1 - ///The number of dots is equal to [number of peers/2 and if number of peers is not divisible by 2 then we add 1 else we add 0] - ///The active dot is the current page - ///The inactive dots are the pages other than the current page - if (((widget.peerTracks.length - widget.screenshareCount) ~/ - 2 + - (widget.peerTracks.length - widget.screenshareCount) % - 2) > - 1) - Selector( - selector: (_, meetingStore) => meetingStore.currentPage, - builder: (_, currentPage, __) { - int dotsCount = (((widget.peerTracks.length - - widget.screenshareCount) ~/ - 2) + - (widget.peerTracks.length - - widget.screenshareCount) % - 2); - return Padding( - padding: const EdgeInsets.only(top: 8.0), - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: DotsIndicator( - mainAxisSize: MainAxisSize.min, - dotsCount: dotsCount, - position: - currentPage > dotsCount ? 0 : currentPage, - decorator: DotsDecorator( - activeColor: - HMSThemeColors.onSurfaceHighEmphasis, - color: HMSThemeColors.onSurfaceLowEmphasis), - ), + ///This renders the peer tiles at the bottom half of the screen + if (!isFullScreen) + Flexible( + flex: 1, + child: Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Column( + children: [ + Expanded( + child: PageView.builder( + physics: const PageScrollPhysics(), + allowImplicitScrolling: true, + onPageChanged: (newPage) { + context + .read() + .setCurrentPage(newPage); + }, + itemCount: (((widget.peerTracks.length - + widget.screenshareCount) ~/ + 2) + + (widget.peerTracks.length - + widget.screenshareCount) % + 2), + itemBuilder: (context, index) { + return SideBySideLayout( + numberOfTiles: widget.peerTracks.length - + widget.screenshareCount, + index: index, + peerTracks: widget.peerTracks + .sublist(widget.screenshareCount)); + }, ), - ); - }) - ], - ), - )) - ], - ); + ), + + ///This renders the dots at the bottom of the grid view + ///This is only rendered if the number of pages is greater than 1 + ///The number of dots is equal to [number of peers/2 and if number of peers is not divisible by 2 then we add 1 else we add 0] + ///The active dot is the current page + ///The inactive dots are the pages other than the current page + if (((widget.peerTracks.length - + widget.screenshareCount) ~/ + 2 + + (widget.peerTracks.length - + widget.screenshareCount) % + 2) > + 1) + Selector( + selector: (_, meetingStore) => + meetingStore.currentPage, + builder: (_, currentPage, __) { + int dotsCount = (((widget.peerTracks.length - + widget.screenshareCount) ~/ + 2) + + (widget.peerTracks.length - + widget.screenshareCount) % + 2); + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: DotsIndicator( + mainAxisSize: MainAxisSize.min, + dotsCount: dotsCount, + position: currentPage > dotsCount + ? 0 + : currentPage, + decorator: DotsDecorator( + activeColor: HMSThemeColors + .onSurfaceHighEmphasis, + color: HMSThemeColors + .onSurfaceLowEmphasis), + ), + ), + ); + }) + ], + ), + )) + ], + ); + }); } } diff --git a/packages/hms_room_kit/lib/src/widgets/meeting_modes/custom_one_to_one_grid.dart b/packages/hms_room_kit/lib/src/widgets/meeting_modes/custom_one_to_one_grid.dart index 8aa633dc0..7e46cfc04 100644 --- a/packages/hms_room_kit/lib/src/widgets/meeting_modes/custom_one_to_one_grid.dart +++ b/packages/hms_room_kit/lib/src/widgets/meeting_modes/custom_one_to_one_grid.dart @@ -3,10 +3,12 @@ library; import 'package:dots_indicator/dots_indicator.dart'; import 'package:flutter/material.dart'; +import 'package:hmssdk_flutter/hmssdk_flutter.dart'; import 'package:provider/provider.dart'; import 'package:tuple/tuple.dart'; ///Project imports +import 'package:hms_room_kit/src/widgets/whiteboard_screenshare/whiteboard_screenshare_store.dart'; import 'package:hms_room_kit/hms_room_kit.dart'; import 'package:hms_room_kit/src/meeting/meeting_store.dart'; import 'package:hms_room_kit/src/model/peer_track_node.dart'; @@ -37,30 +39,39 @@ class _CustomOneToOneGridState extends State { ///The number of pages in the [PageView] is equal to [numberOfPeers/6 + (if number of peers is not divisible by 6 then we add 1 else we add 0)] ///One thing to note here is that in this view we filter out the local peer since we are rendering the local peer in the inset tile ///The inset tile is rendered at the top of the grid view - return Selector, int, PeerTrackNode, int>>( - selector: (_, meetingStore) => Tuple4( + return Selector< + MeetingStore, + Tuple5, int, PeerTrackNode, int, + HMSWhiteboardModel?>>( + selector: (_, meetingStore) => Tuple5( meetingStore.peerTracks, meetingStore.peerTracks.length, meetingStore.peerTracks[0], - meetingStore.screenShareCount), + meetingStore.screenShareCount, + meetingStore.whiteboardModel), builder: (_, data, __) { int numberOfPeers = data.item2 - (widget.isLocalInsetPresent ? 1 : 0); int pageCount = (numberOfPeers ~/ 6) + (numberOfPeers % 6 == 0 ? 0 : 1); + var screenshareStore = WhiteboardScreenshareStore(); + ///If the remote peer is sharing screen then we render the [ScreenshareGridLayout] with inset tile ///Else we render the normal layout with inset tile - return data.item4 > 0 - ? ScreenshareGridLayout( - peerTracks: widget.isLocalInsetPresent - ? data.item1 - .where((element) => - !element.peer.isLocal || - element.track?.source == "SCREEN") - .toList() - : data.item1, - screenshareCount: data.item4, + return data.item4 > 0 || data.item5 != null + ? ChangeNotifierProvider.value( + value: screenshareStore, + child: ScreenshareGridLayout( + peerTracks: widget.isLocalInsetPresent + ? data.item1 + .where((element) => + !element.peer.isLocal || + element.track?.source == "SCREEN") + .toList() + : data.item1, + screenshareCount: data.item4, + whiteboardModel: data.item5, + ), ) : @@ -68,14 +79,6 @@ class _CustomOneToOneGridState extends State { Column( children: [ Expanded( - // child: TextureViewGrid( - // peerTracks: widget.isLocalInsetPresent - // ? data.item1 - // .where((element) => - // !(element.peer.isLocal) || - // element.track?.source == "SCREEN") - // .toList() - // : data.item1), child: PageView.builder( physics: const PageScrollPhysics(), controller: controller, diff --git a/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_screenshare_store.dart b/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_screenshare_store.dart new file mode 100644 index 000000000..2e3663fd0 --- /dev/null +++ b/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_screenshare_store.dart @@ -0,0 +1,14 @@ +library; + +///Package imports +import 'package:flutter/material.dart'; + +///[WhiteboardScreenshareStore] is a store that stores the state of the whiteboard screenshare +class WhiteboardScreenshareStore extends ChangeNotifier { + bool isFullScreen = false; + + void toggleFullScreen() { + isFullScreen = !isFullScreen; + notifyListeners(); + } +} diff --git a/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_tile.dart b/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_tile.dart new file mode 100644 index 000000000..7aec79cb4 --- /dev/null +++ b/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_tile.dart @@ -0,0 +1,65 @@ +library; + +///Package imports +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:pointer_interceptor/pointer_interceptor.dart'; +import 'package:provider/provider.dart'; + +///Project imports +import 'package:hms_room_kit/src/layout_api/hms_theme_colors.dart'; +import 'package:hms_room_kit/src/widgets/whiteboard_screenshare/whiteboard_screenshare_store.dart'; +import 'package:hms_room_kit/src/widgets/whiteboard_screenshare/whiteboard_webview.dart'; + +///[WhiteboardTile] is a widget that renders the whiteboard tile +class WhiteboardTile extends StatefulWidget { + const WhiteboardTile({Key? key}) : super(key: key); + @override + State createState() => _WhiteboardTileState(); +} + +class _WhiteboardTileState extends State { + bool isFullScreen = false; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + const WhiteboardWebView(), + Positioned( + top: 5, + right: 5, + child: GestureDetector( + onTap: () { + context.read().toggleFullScreen(); + }, + child: PointerInterceptor( + child: Container( + height: 40, + width: 40, + decoration: BoxDecoration( + color: HMSThemeColors.backgroundDim.withAlpha(64), + borderRadius: BorderRadius.circular(8)), + child: Center( + child: Selector( + selector: (_, whiteboardScreenshareStore) => + whiteboardScreenshareStore.isFullScreen, + builder: (_, isFullScreen, __) { + return SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/${isFullScreen ? "minimize" : "maximize"}.svg", + height: 16, + width: 16, + semanticsLabel: "maximize_label", + colorFilter: ColorFilter.mode( + HMSThemeColors.onSurfaceHighEmphasis, + BlendMode.srcIn), + ); + }), + ), + ), + ), + )), + ], + ); + } +} diff --git a/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_webview.dart b/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_webview.dart new file mode 100644 index 000000000..094820853 --- /dev/null +++ b/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_webview.dart @@ -0,0 +1,46 @@ +library; + +///Dart imports +import 'dart:developer'; + +///Package imports +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +///Project imports +import 'package:hms_room_kit/src/meeting/meeting_store.dart'; + +///[WhiteboardWebView] is a widget that renders the whiteboard webview +class WhiteboardWebView extends StatelessWidget { + const WhiteboardWebView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Selector( + selector: (_, meetingStore) => meetingStore.whiteboardModel?.url, + builder: (_, url, __) { + ///If the url is not null we render the webview + return url != null + ? WebViewWidget( + controller: WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setBackgroundColor(const Color(0x00000000)) + ..setNavigationDelegate( + NavigationDelegate( + onNavigationRequest: (_) { + return NavigationDecision.navigate; + }, + onProgress: (int progress) {}, + onPageStarted: (String url) {}, + onPageFinished: (String url) {}, + onWebResourceError: (WebResourceError error) { + log("Error occured in whiteboard tile: ${error.description}"); + }, + ), + ) + ..loadRequest(Uri.parse(url))) + : const SizedBox(); + }); + } +} diff --git a/packages/hms_room_kit/pubspec.lock b/packages/hms_room_kit/pubspec.lock index a483faed0..d776a505b 100644 --- a/packages/hms_room_kit/pubspec.lock +++ b/packages/hms_room_kit/pubspec.lock @@ -190,7 +190,7 @@ packages: path: "../hmssdk_flutter" relative: true source: path - version: "1.10.1" + version: "1.10.2" http: dependency: transitive description: @@ -415,6 +415,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pointer_interceptor: + dependency: "direct main" + description: + name: pointer_interceptor + sha256: bd18321519718678d5fa98ad3a3359cbc7a31f018554eab80b73d08a7f0c165a + url: "https://pub.dev" + source: hosted + version: "0.10.1" + pointer_interceptor_ios: + dependency: transitive + description: + name: pointer_interceptor_ios + sha256: "2e73c39452830adc4695757130676a39412a3b7f3c34e3f752791b5384770877" + url: "https://pub.dev" + source: hosted + version: "0.10.0+2" + pointer_interceptor_platform_interface: + dependency: transitive + description: + name: pointer_interceptor_platform_interface + sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506" + url: "https://pub.dev" + source: hosted + version: "0.10.0+1" + pointer_interceptor_web: + dependency: transitive + description: + name: pointer_interceptor_web + sha256: "2a8a069206f7b234a895d30ccab8b18ea267eeb79a832e5e3d1b6464d659eb6a" + url: "https://pub.dev" + source: hosted + version: "0.10.0" pointycastle: dependency: transitive description: @@ -700,6 +732,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.4-beta" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + sha256: d81b68e88cc353e546afb93fb38958e3717282c5ac6e5d3be4a4aef9fc3c1413 + url: "https://pub.dev" + source: hosted + version: "4.5.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: dad3313c9ead95517bb1cae5e1c9d20ba83729d5a59e5e83c0a2d66203f27f91 + url: "https://pub.dev" + source: hosted + version: "3.16.1" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + url: "https://pub.dev" + source: hosted + version: "2.10.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: "4d062ad505390ecef1c4bfb6001cd857a51e00912cc9dfb66edb1886a9ebd80c" + url: "https://pub.dev" + source: hosted + version: "3.10.2" win32: dependency: transitive description: diff --git a/packages/hms_room_kit/pubspec.yaml b/packages/hms_room_kit/pubspec.yaml index b2c7b853b..af7e78f24 100644 --- a/packages/hms_room_kit/pubspec.yaml +++ b/packages/hms_room_kit/pubspec.yaml @@ -34,6 +34,8 @@ dependencies: share_plus: ^7.0.2 collection: ^1.17.0 dots_indicator: ^3.0.0 + webview_flutter: ^4.5.0 + pointer_interceptor: ^0.10.1 dev_dependencies: flutter_test: diff --git a/packages/hmssdk_flutter/android/build.gradle b/packages/hmssdk_flutter/android/build.gradle index 6accc5814..688912be5 100644 --- a/packages/hmssdk_flutter/android/build.gradle +++ b/packages/hmssdk_flutter/android/build.gradle @@ -47,10 +47,14 @@ android { } dependencies { - implementation "live.100ms:android-sdk:${sdkVersions['android']}" - implementation "live.100ms:video-view:${sdkVersions['android']}" - implementation "live.100ms:hls-player:${sdkVersions['android']}" - implementation "live.100ms:hms-noise-cancellation-android:${sdkVersions['android']}" + implementation "com.github.100mslive.android-sdk:video-view:dev-v2-SNAPSHOT" + implementation "com.github.100mslive.android-sdk:hls-player:dev-v2-SNAPSHOT" + implementation 'com.github.100mslive.android-sdk:android-sdk:dev-v2-SNAPSHOT' + implementation "com.github.100mslive.android-sdk:hms-noise-cancellation-android:dev-v2-SNAPSHOT" +// implementation "live.100ms:android-sdk:${sdkVersions['android']}" +// implementation "live.100ms:video-view:${sdkVersions['android']}" +// implementation "live.100ms:hls-player:${sdkVersions['android']}" +// implementation "live.100ms:hms-noise-cancellation-android:${sdkVersions['android']}" implementation 'com.google.code.gson:gson:2.9.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSRoleExtension.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSRoleExtension.kt index dffe96e1e..4b5e51bd3 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSRoleExtension.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSRoleExtension.kt @@ -8,16 +8,15 @@ import live.hms.video.sdk.models.role.HMSRole class HMSRoleExtension { companion object { - @SuppressLint("LongLogTag") fun toDictionary(role: HMSRole?): HashMap? { val hashMap = HashMap() if (role == null)return null - hashMap["name"] = role?.name ?: "unknown" - hashMap["publish_settings"] = PublishParamsExtension.toDictionary(role?.publishParams ?: null) - hashMap["subscribe_settings"] = SubscribeSettings.toDictionary(role?.subscribeParams ?: null) - hashMap["priority"] = role?.priority!! - hashMap["permissions"] = PermissionParamsExtension.toDictionary(role.permission ?: null) + hashMap["name"] = role.name + hashMap["publish_settings"] = PublishParamsExtension.toDictionary(role.publishParams) + hashMap["subscribe_settings"] = SubscribeSettings.toDictionary(role.subscribeParams) + hashMap["priority"] = role.priority + hashMap["permissions"] = PermissionParamsExtension.toDictionary(role.permission) return hashMap } diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt new file mode 100644 index 000000000..d11fb079b --- /dev/null +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt @@ -0,0 +1,25 @@ +package live.hms.hmssdk_flutter + +import live.hms.video.sdk.models.HMSPeer +import live.hms.video.whiteboard.HMSWhiteboard + +class HMSWhiteboardExtension { + companion object{ + + fun toDictionary(hmsWhiteboard: HMSWhiteboard?): HashMap?{ + + if(hmsWhiteboard == null){ + return null + } + + val whiteboardMap = HashMap() + + whiteboardMap["id"] = hmsWhiteboard.id + whiteboardMap["owner"] = HMSPeerExtension.toDictionary(hmsWhiteboard.owner) + whiteboardMap["title"] = hmsWhiteboard.title + whiteboardMap["url"] = hmsWhiteboard.url + + return whiteboardMap + } + } +} \ No newline at end of file diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt index 1ecd8a21c..76943fade 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt @@ -50,6 +50,8 @@ import live.hms.video.sessionstore.HmsSessionStore import live.hms.video.signal.init.* import live.hms.video.utils.HMSLogger import live.hms.video.utils.HmsUtilities +import live.hms.video.whiteboard.HMSWhiteboardUpdate +import live.hms.video.whiteboard.HMSWhiteboardUpdateListener /** HmssdkFlutterPlugin */ class HmssdkFlutterPlugin : @@ -65,6 +67,7 @@ class HmssdkFlutterPlugin : private var sessionStoreChannel: EventChannel? = null var hlsPlayerChannel: EventChannel? = null private var pollsEventChannel: EventChannel? = null + private var whiteboardEventChannel: EventChannel? = null private var eventSink: EventChannel.EventSink? = null private var previewSink: EventChannel.EventSink? = null private var logsSink: EventChannel.EventSink? = null @@ -72,6 +75,7 @@ class HmssdkFlutterPlugin : private var sessionStoreSink: EventChannel.EventSink? = null var hlsPlayerSink: EventChannel.EventSink? = null private var pollsSink: EventChannel.EventSink? = null + private var whiteboardSink: EventChannel.EventSink? = null private lateinit var activity: Activity var hmssdk: HMSSDK? = null private lateinit var hmsVideoFactory: HMSVideoViewFactory @@ -114,6 +118,9 @@ class HmssdkFlutterPlugin : this.pollsEventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "polls_event_channel") + this.whiteboardEventChannel = + EventChannel(flutterPluginBinding.binaryMessenger, "whiteboard_event_channel") + this.meetingEventChannel?.setStreamHandler(this) ?: Log.e("Channel Error", "Meeting event channel not found") this.channel?.setMethodCallHandler(this) ?: Log.e("Channel Error", "Event channel not found") this.previewChannel?.setStreamHandler(this) ?: Log.e("Channel Error", "Preview channel not found") @@ -122,6 +129,7 @@ class HmssdkFlutterPlugin : this.sessionStoreChannel?.setStreamHandler(this) ?: Log.e("Channel Error", "Session Store channel not found") this.hlsPlayerChannel?.setStreamHandler(this) ?: Log.e("Channel Error", "HLS Player channel not found") this.pollsEventChannel?.setStreamHandler(this) ?: Log.e("Channel Error", "polls events channel not found") + this.whiteboardEventChannel?.setStreamHandler(this)?:Log.e("Channel Error", "whiteboard events channel not found") this.hmsVideoFactory = HMSVideoViewFactory(this) this.hmsHLSPlayerFactory = HMSHLSPlayerFactory(this) @@ -293,6 +301,10 @@ class HmssdkFlutterPlugin : HMSNoiseCancellationControllerAction.noiseCancellationActions(call, result, hmssdk!!) } + "start_whiteboard", "stop_whiteboard", "add_whiteboard_update_listener", "remove_whiteboard_update_listener" -> { + whiteboardActions(call,result) + } + else -> { result.notImplemented() } @@ -472,6 +484,22 @@ class HmssdkFlutterPlugin : private var currentPolls = ArrayList() + private fun whiteboardActions( + call: MethodCall, + result: Result + ){ + when(call.method){ + "add_whiteboard_update_listener" -> + hmssdk?.getHmsInteractivityCenter()?.setWhiteboardUpdateListener(whiteboardListener) + "remove_whiteboard_update_listener" -> + hmssdk?.getHmsInteractivityCenter()?.removeWhiteboardUpdateListener(whiteboardListener) + else -> + hmssdk?.let { + HMSWhiteboardAction.whiteboardActions(call,result,it) + } + } + } + private fun pollActions( call: MethodCall, result: Result, @@ -502,6 +530,7 @@ class HmssdkFlutterPlugin : sessionStoreChannel?.setStreamHandler(null) ?: Log.e("Channel Error", "Session Store channel not found") hlsPlayerChannel?.setStreamHandler(null) ?: Log.e("Channel Error", "HLS Player channel not found") pollsEventChannel?.setStreamHandler(null) ?: Log.e("Channel Error", "polls event channel not found") + whiteboardEventChannel?.setStreamHandler(null) ?: Log.e("Channel Error", "whiteboard event channel not found") eventSink = null previewSink = null rtcSink = null @@ -509,6 +538,7 @@ class HmssdkFlutterPlugin : sessionStoreSink = null hlsPlayerSink = null pollsSink = null + whiteboardSink = null hmssdkFlutterPlugin = null hmsBinaryMessenger = null hmsTextureRegistry = null @@ -641,6 +671,8 @@ class HmssdkFlutterPlugin : this.hlsPlayerSink = events } else if (nameOfEventSink == "polls") { this.pollsSink = events + } else if(nameOfEventSink == "whiteboard") { + this.whiteboardSink = events } } @@ -2191,4 +2223,41 @@ class HmssdkFlutterPlugin : } } } + + private val whiteboardListener = + object: HMSWhiteboardUpdateListener{ + override fun onUpdate(hmsWhiteboardUpdate: HMSWhiteboardUpdate) { + when(hmsWhiteboardUpdate){ + is HMSWhiteboardUpdate.Start -> { + + val args = HashMap() + + args["event_name"] = "on_whiteboard_start" + + args["data"] = HMSWhiteboardExtension.toDictionary(hmsWhiteboardUpdate.hmsWhiteboard) + + if (args["data"] != null) { + CoroutineScope(Dispatchers.Main).launch { + whiteboardSink?.success(args) + } + } + } + is HMSWhiteboardUpdate.Stop -> + { + val args = HashMap() + + args["event_name"] = "on_whiteboard_stop" + + args["data"] = HMSWhiteboardExtension.toDictionary(hmsWhiteboardUpdate.hmsWhiteboard) + + if (args["data"] != null) { + CoroutineScope(Dispatchers.Main).launch { + whiteboardSink?.success(args) + } + } + } + } + } + + } } diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hms_role_components/PermissionParamsExtension.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hms_role_components/PermissionParamsExtension.kt index 0ea6541f8..3e9f26826 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hms_role_components/PermissionParamsExtension.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hms_role_components/PermissionParamsExtension.kt @@ -1,5 +1,6 @@ package live.hms.hmssdk_flutter.hms_role_components +import live.hms.video.sdk.models.role.HMSWhiteBoardPermission import live.hms.video.sdk.models.role.PermissionsParams class PermissionParamsExtension { @@ -17,7 +18,20 @@ class PermissionParamsExtension { args["un_mute"] = permissionsParams.unmute args["poll_read"] = permissionsParams.pollRead args["poll_write"] = permissionsParams.pollWrite + permissionsParams.whiteboard.let { + args["whiteboard_permission"] = getMapFromHMSWhiteboardPermission(it) + } return args } + + private fun getMapFromHMSWhiteboardPermission(hmsWhiteboardPermission: HMSWhiteBoardPermission):HashMap{ + val permission = HashMap() + + permission["admin"] = hmsWhiteboardPermission.admin + permission["write"] = hmsWhiteboardPermission.write + permission["read"] = hmsWhiteboardPermission.read + + return permission + } } } diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSWhiteboardAction.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSWhiteboardAction.kt new file mode 100644 index 000000000..53e3a3917 --- /dev/null +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSWhiteboardAction.kt @@ -0,0 +1,35 @@ +package live.hms.hmssdk_flutter.methods + +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel.Result +import live.hms.hmssdk_flutter.HMSCommonAction +import live.hms.hmssdk_flutter.HMSErrorLogger +import live.hms.video.sdk.HMSSDK + +class HMSWhiteboardAction { + + companion object{ + + fun whiteboardActions(call: MethodCall, result: Result, hmssdk: HMSSDK,){ + when(call.method){ + "start_whiteboard" -> startWhiteboard(call, result, hmssdk) + "stop_whiteboard" -> stopWhiteboard(result, hmssdk) + else -> result.notImplemented() + } + } + + private fun startWhiteboard(call: MethodCall, result: Result, hmssdk: HMSSDK){ + val title = call.argument("title") + + title?.let { + hmssdk.getHmsInteractivityCenter().startWhiteboard(it, HMSCommonAction.getActionListener(result)) + }?:run { + HMSErrorLogger.returnArgumentsError("title can't be empty") + } + } + + private fun stopWhiteboard(result: Result, hmssdk: HMSSDK){ + hmssdk.getHmsInteractivityCenter().stopWhiteboard(HMSCommonAction.getActionListener(result)) + } + } +} \ No newline at end of file diff --git a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt index 773eb7d50..119ed3b39 100644 --- a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt +++ b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt @@ -3,7 +3,13 @@ Board: https://100ms.atlassian.net/jira/software/projects/FLUT/boards/34/ - Add Quality Selector sheet in HLS Player https://100ms.atlassian.net/browse/FLUT-297 +- Whiteboard Support in flutter +https://100ms.atlassian.net/browse/FLUT-298 + +- Add `peerListUpdated` callback shows the peers in the room +https://100ms.atlassian.net/browse/FLUT-284 + Room Kit: 1.1.2 Core SDK: 1.10.2 Android SDK: 2.9.55 -iOS SDK: 1.9.0 \ No newline at end of file +iOS SDK: 1.10.0 \ No newline at end of file diff --git a/packages/hmssdk_flutter/example/android/app/build.gradle b/packages/hmssdk_flutter/example/android/app/build.gradle index 52e4f4e54..dbb0397de 100644 --- a/packages/hmssdk_flutter/example/android/app/build.gradle +++ b/packages/hmssdk_flutter/example/android/app/build.gradle @@ -36,8 +36,8 @@ android { applicationId "live.hms.flutter" minSdkVersion 21 targetSdkVersion 34 - versionCode 486 - versionName "1.5.186" + versionCode 491 + versionName "1.5.191" } signingConfigs { diff --git a/packages/hmssdk_flutter/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/packages/hmssdk_flutter/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java index add674e01..e757d644b 100644 --- a/packages/hmssdk_flutter/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java +++ b/packages/hmssdk_flutter/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -85,5 +85,10 @@ public static void registerWith(@NonNull FlutterEngine flutterEngine) { } catch (Exception e) { Log.e(TAG, "Error registering plugin url_launcher_android, io.flutter.plugins.urllauncher.UrlLauncherPlugin", e); } + try { + flutterEngine.getPlugins().add(new io.flutter.plugins.webviewflutter.WebViewFlutterPlugin()); + } catch (Exception e) { + Log.e(TAG, "Error registering plugin webview_flutter_android, io.flutter.plugins.webviewflutter.WebViewFlutterPlugin", e); + } } } diff --git a/packages/hmssdk_flutter/example/ios/Gemfile.lock b/packages/hmssdk_flutter/example/ios/Gemfile.lock index f98d835d7..8e457e1ec 100644 --- a/packages/hmssdk_flutter/example/ios/Gemfile.lock +++ b/packages/hmssdk_flutter/example/ios/Gemfile.lock @@ -15,8 +15,8 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.922.0) - aws-sdk-core (3.194.0) + aws-partitions (1.925.0) + aws-sdk-core (3.194.2) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) @@ -24,7 +24,7 @@ GEM aws-sdk-kms (1.80.0) aws-sdk-core (~> 3, >= 3.193.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.149.0) + aws-sdk-s3 (1.149.1) aws-sdk-core (~> 3, >= 3.194.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) @@ -164,7 +164,7 @@ GEM http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) - i18n (1.14.4) + i18n (1.14.5) concurrent-ruby (~> 1.0) jmespath (1.6.2) json (2.7.2) @@ -174,7 +174,7 @@ GEM mini_mime (1.1.5) minitest (5.22.3) multi_json (1.15.0) - multipart-post (2.4.0) + multipart-post (2.4.1) nanaimo (0.3.0) naturally (2.2.1) nkf (0.2.0) diff --git a/packages/hmssdk_flutter/example/ios/Podfile.lock b/packages/hmssdk_flutter/example/ios/Podfile.lock index b71a3d963..5ade372bc 100644 --- a/packages/hmssdk_flutter/example/ios/Podfile.lock +++ b/packages/hmssdk_flutter/example/ios/Podfile.lock @@ -27,15 +27,15 @@ PODS: - Firebase/Performance (= 10.18.0) - firebase_core - Flutter - - FirebaseABTesting (10.24.0): + - FirebaseABTesting (10.25.0): - FirebaseCore (~> 10.0) - FirebaseCore (10.18.0): - FirebaseCoreInternal (~> 10.0) - GoogleUtilities/Environment (~> 7.12) - GoogleUtilities/Logger (~> 7.12) - - FirebaseCoreExtension (10.24.0): + - FirebaseCoreExtension (10.25.0): - FirebaseCore (~> 10.0) - - FirebaseCoreInternal (10.24.0): + - FirebaseCoreInternal (10.25.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" - FirebaseCrashlytics (10.18.0): - FirebaseCore (~> 10.5) @@ -47,7 +47,7 @@ PODS: - PromisesObjC (~> 2.1) - FirebaseDynamicLinks (10.18.0): - FirebaseCore (~> 10.0) - - FirebaseInstallations (10.24.0): + - FirebaseInstallations (10.25.0): - FirebaseCore (~> 10.0) - GoogleUtilities/Environment (~> 7.8) - GoogleUtilities/UserDefaults (~> 7.8) @@ -62,7 +62,7 @@ PODS: - GoogleUtilities/ISASwizzler (~> 7.8) - GoogleUtilities/MethodSwizzler (~> 7.8) - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseRemoteConfig (10.24.0): + - FirebaseRemoteConfig (10.25.0): - FirebaseABTesting (~> 10.0) - FirebaseCore (~> 10.0) - FirebaseInstallations (~> 10.0) @@ -70,16 +70,17 @@ PODS: - FirebaseSharedSwift (~> 10.0) - GoogleUtilities/Environment (~> 7.8) - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseRemoteConfigInterop (10.24.0) - - FirebaseSessions (10.24.0): + - FirebaseRemoteConfigInterop (10.25.0) + - FirebaseSessions (10.25.0): - FirebaseCore (~> 10.5) - FirebaseCoreExtension (~> 10.0) - FirebaseInstallations (~> 10.0) - GoogleDataTransport (~> 9.2) - - GoogleUtilities/Environment (~> 7.10) + - GoogleUtilities/Environment (~> 7.13) + - GoogleUtilities/UserDefaults (~> 7.13) - nanopb (< 2.30911.0, >= 2.30908.0) - PromisesSwift (~> 2.1) - - FirebaseSharedSwift (10.24.0) + - FirebaseSharedSwift (10.25.0) - Flutter (1.0.0) - flutter_foreground_task (0.0.1): - Flutter @@ -104,21 +105,21 @@ PODS: - GoogleToolboxForMac/Defines (= 2.3.2) - "GoogleToolboxForMac/NSString+URLArguments (= 2.3.2)" - "GoogleToolboxForMac/NSString+URLArguments (2.3.2)" - - GoogleUtilities/Environment (7.13.0): + - GoogleUtilities/Environment (7.13.2): - GoogleUtilities/Privacy - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/ISASwizzler (7.13.0): + - GoogleUtilities/ISASwizzler (7.13.2): - GoogleUtilities/Privacy - - GoogleUtilities/Logger (7.13.0): + - GoogleUtilities/Logger (7.13.2): - GoogleUtilities/Environment - GoogleUtilities/Privacy - - GoogleUtilities/MethodSwizzler (7.13.0): + - GoogleUtilities/MethodSwizzler (7.13.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - - "GoogleUtilities/NSData+zlib (7.13.0)": + - "GoogleUtilities/NSData+zlib (7.13.2)": - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (7.13.0) - - GoogleUtilities/UserDefaults (7.13.0): + - GoogleUtilities/Privacy (7.13.2) + - GoogleUtilities/UserDefaults (7.13.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - GoogleUtilitiesComponents (1.1.0): @@ -129,16 +130,16 @@ PODS: - HMSHLSPlayerSDK (0.0.2): - HMSAnalyticsSDK (= 0.0.2) - HMSNoiseCancellationModels (1.0.0) - - HMSSDK (1.9.0): + - HMSSDK (1.10.0): - HMSAnalyticsSDK (= 0.0.2) - - HMSWebRTC (= 1.0.6168) + - HMSWebRTC (= 1.0.6169) - hmssdk_flutter (1.10.1): - Flutter - HMSBroadcastExtensionSDK (= 0.0.9) - HMSHLSPlayerSDK (= 0.0.2) - HMSNoiseCancellationModels (= 1.0.0) - - HMSSDK (= 1.9.0) - - HMSWebRTC (1.0.6168) + - HMSSDK (= 1.10.0) + - HMSWebRTC (1.0.6169) - MLImage (1.0.0-beta4) - MLKitBarcodeScanning (3.0.0): - MLKitCommon (~> 9.0) @@ -172,6 +173,8 @@ PODS: - FlutterMacOS - permission_handler_apple (9.1.1): - Flutter + - pointer_interceptor_ios (0.0.1): + - Flutter - PromisesObjC (2.4.0) - PromisesSwift (2.4.0): - PromisesObjC (= 2.4.0) @@ -182,6 +185,8 @@ PODS: - FlutterMacOS - url_launcher_ios (0.0.1): - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter DEPENDENCIES: - app_links (from `.symlinks/plugins/app_links/ios`) @@ -197,9 +202,11 @@ DEPENDENCIES: - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + - pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) SPEC REPOS: trunk: @@ -261,12 +268,16 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" + pointer_interceptor_ios: + :path: ".symlinks/plugins/pointer_interceptor_ios/ios" share_plus: :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" SPEC CHECKSUMS: app_links: e70ca16b4b0f88253b3b3660200d4a10b4ea9795 @@ -275,33 +286,33 @@ SPEC CHECKSUMS: firebase_crashlytics: 4b91b8ad60ee7c168fe88979f84c9573a729de7a firebase_dynamic_links: b626a11f5eb02033981ae377377c3f297eb4c1b0 firebase_performance: 2183122a3c7a650c80d8c164e9e28f13c4c62fc7 - FirebaseABTesting: 4431c2c56ac6e56f463b9cab05cc111078639f99 + FirebaseABTesting: e6e3c3e0e35813874f571d1b7bdae2aab319dd38 FirebaseCore: 2322423314d92f946219c8791674d2f3345b598f - FirebaseCoreExtension: af5fd85e817ea9d19f9a2659a376cf9cf99f03c0 - FirebaseCoreInternal: bcb5acffd4ea05e12a783ecf835f2210ce3dc6af + FirebaseCoreExtension: 8a47811d0b155501559ef05d089518152a0a1677 + FirebaseCoreInternal: 910a81992c33715fec9263ca7381d59ab3a750b7 FirebaseCrashlytics: 86d5bce01f42fa1db265f87ff1d591f04db610ec FirebaseDynamicLinks: c37307441c53838d66a9650dabca9e0459502527 - FirebaseInstallations: 8f581fca6478a50705d2bd2abd66d306e0f5736e + FirebaseInstallations: 91950fe859846fff0fbd296180909dd273103b09 FirebasePerformance: c406a9198d8aabfbac281b42855f5122fc1bcf69 - FirebaseRemoteConfig: 95dddc50496b37eef199dadce850d5652b534b43 - FirebaseRemoteConfigInterop: 6c349a466490aeace3ce9c091c86be1730711634 - FirebaseSessions: 2651b464e241c93fd44112f995d5ab663c970487 - FirebaseSharedSwift: 76e1529c32101d80e4f1ca2fba7c39d59f0a390a + FirebaseRemoteConfig: 9f3935cefecd85d5b312192117f444957de24a75 + FirebaseRemoteConfigInterop: b25018791b204c0d78a90e394d6c62d9b1f22da8 + FirebaseSessions: c0939656253a1fa0e94ecc266ccf770cc8b33732 + FirebaseSharedSwift: 0274086954b1b2d5fd7e829eccc587044d72a4ba Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_foreground_task: 21ef182ab0a29a3005cc72cd70e5f45cb7f7f817 GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a GoogleMLKit: 2bd0dc6253c4d4f227aad460f69215a504b2980e GoogleToolboxForMac: 8bef7c7c5cf7291c687cf5354f39f9db6399ad34 - GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152 + GoogleUtilities: c56430aef51a1aa57b25da78c3f8397e522c67b7 GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2 HMSAnalyticsSDK: 4d2a88a729b1eb42f3d25f217c28937ec318a5b7 HMSBroadcastExtensionSDK: d80fe325f6c928bd8e5176290b5a4b7ae15d6fbb HMSHLSPlayerSDK: 6a54ad4d12f3dc2270d1ecd24019d71282a4f6a3 HMSNoiseCancellationModels: a3bda1405a16015632f4bcabd46ce48f35103b02 - HMSSDK: 96bdafc1c610aabfecd1155ad7e3c1bc45b3a6cb - hmssdk_flutter: c2ad70779ed9355577afbbe1047fb20f862820ac - HMSWebRTC: a302f0d6c94f7bee94f3265adb7bb1c6569e7ee5 + HMSSDK: fbbdebf673baba7f98f3fa13241b4249929ad681 + hmssdk_flutter: 65856808a5f153c52f17be3d86ee946922d3ec70 + HMSWebRTC: 8f51ba33a0e505e17ebf3d7b37bcdca266751a13 MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505 MLKitCommon: c1b791c3e667091918d91bda4bba69a91011e390 @@ -311,11 +322,13 @@ SPEC CHECKSUMS: package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 + pointer_interceptor_ios: 9280618c0b2eeb80081a343924aa8ad756c21375 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 + webview_flutter_wkwebview: 4f3e50f7273d31e5500066ed267e3ae4309c5ae4 PODFILE CHECKSUM: 9fb9f6e431a2c6c79942252e94b241ac7972ac90 diff --git a/packages/hmssdk_flutter/example/ios/Runner/Info.plist b/packages/hmssdk_flutter/example/ios/Runner/Info.plist index 8f23eaedb..87cdb28c4 100644 --- a/packages/hmssdk_flutter/example/ios/Runner/Info.plist +++ b/packages/hmssdk_flutter/example/ios/Runner/Info.plist @@ -21,7 +21,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.5.186 + 1.5.190 CFBundleSignature ???? CFBundleURLTypes @@ -48,7 +48,7 @@ CFBundleVersion - 486 + 490 ITSAppUsesNonExemptEncryption LSApplicationCategoryType diff --git a/packages/hmssdk_flutter/example/pubspec.lock b/packages/hmssdk_flutter/example/pubspec.lock index 085e6fe80..2369d95c5 100644 --- a/packages/hmssdk_flutter/example/pubspec.lock +++ b/packages/hmssdk_flutter/example/pubspec.lock @@ -255,7 +255,7 @@ packages: source: hosted version: "6.0.0" flutter_svg: - dependency: transitive + dependency: "direct main" description: name: flutter_svg sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" @@ -574,6 +574,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pointer_interceptor: + dependency: transitive + description: + name: pointer_interceptor + sha256: bd18321519718678d5fa98ad3a3359cbc7a31f018554eab80b73d08a7f0c165a + url: "https://pub.dev" + source: hosted + version: "0.10.1" + pointer_interceptor_ios: + dependency: transitive + description: + name: pointer_interceptor_ios + sha256: "2e73c39452830adc4695757130676a39412a3b7f3c34e3f752791b5384770877" + url: "https://pub.dev" + source: hosted + version: "0.10.0+2" + pointer_interceptor_platform_interface: + dependency: transitive + description: + name: pointer_interceptor_platform_interface + sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506" + url: "https://pub.dev" + source: hosted + version: "0.10.0+1" + pointer_interceptor_web: + dependency: transitive + description: + name: pointer_interceptor_web + sha256: "2a8a069206f7b234a895d30ccab8b18ea267eeb79a832e5e3d1b6464d659eb6a" + url: "https://pub.dev" + source: hosted + version: "0.10.0" pointycastle: dependency: transitive description: @@ -583,7 +615,7 @@ packages: source: hosted version: "3.8.0" provider: - dependency: transitive + dependency: "direct main" description: name: provider sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c @@ -859,6 +891,38 @@ packages: url: "https://pub.dev" source: hosted version: "13.0.0" + webview_flutter: + dependency: transitive + description: + name: webview_flutter + sha256: d81b68e88cc353e546afb93fb38958e3717282c5ac6e5d3be4a4aef9fc3c1413 + url: "https://pub.dev" + source: hosted + version: "4.5.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: dad3313c9ead95517bb1cae5e1c9d20ba83729d5a59e5e83c0a2d66203f27f91 + url: "https://pub.dev" + source: hosted + version: "3.16.1" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + url: "https://pub.dev" + source: hosted + version: "2.10.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: "4d062ad505390ecef1c4bfb6001cd857a51e00912cc9dfb66edb1886a9ebd80c" + url: "https://pub.dev" + source: hosted + version: "3.10.2" win32: dependency: transitive description: diff --git a/packages/hmssdk_flutter/example/pubspec.yaml b/packages/hmssdk_flutter/example/pubspec.yaml index 328138a8f..a52eb5b42 100644 --- a/packages/hmssdk_flutter/example/pubspec.yaml +++ b/packages/hmssdk_flutter/example/pubspec.yaml @@ -28,6 +28,8 @@ dependencies: uuid: flutter_foreground_task: ^6.1.3 + flutter_svg: any + provider: any dev_dependencies: flutter_test: sdk: flutter diff --git a/packages/hmssdk_flutter/ios/Classes/Actions/HMSWhiteboardAction.swift b/packages/hmssdk_flutter/ios/Classes/Actions/HMSWhiteboardAction.swift new file mode 100644 index 000000000..a82130d2b --- /dev/null +++ b/packages/hmssdk_flutter/ios/Classes/Actions/HMSWhiteboardAction.swift @@ -0,0 +1,69 @@ +// +// HMSWhiteboardAction.swift +// hmssdk_flutter +// +// Created by Pushpam on 30/04/24. +// + +import Foundation +import HMSSDK + +class HMSWhiteboardAction{ + + static func whiteboardActions(_ call: FlutterMethodCall, _ result: @escaping FlutterResult, _ hmsSDK: HMSSDK?){ + switch call.method{ + case "start_whiteboard": + startWhiteboard(call, result, hmsSDK) + + case "stop_whiteboard": + stopWhiteboard(result, hmsSDK) + + default: + result(FlutterMethodNotImplemented) + } + } + + private static func startWhiteboard(_ call: FlutterMethodCall, _ result: @escaping FlutterResult, _ hmsSDK: HMSSDK?){ + let arguments = call.arguments as![AnyHashable: Any] + + /* + title is not used as of now + */ + guard let title = arguments["title"] as? String else{ + HMSErrorLogger.returnArgumentsError("title can't be empty") + return + } + hmsSDK?.interactivityCenter.startWhiteboard{ + _,error in + if let error = error { + result(HMSErrorExtension.toDictionary(error)) + }else{ + result(nil) + } + } + + } + + private static func stopWhiteboard(_ result: @escaping FlutterResult, _ hmsSDK: HMSSDK?){ + + hmsSDK?.interactivityCenter.stopWhiteboard{ + _, error in + if let error = error{ + result(HMSErrorExtension.toDictionary(error)) + }else{ + result(nil) + } + } + } + + static func getWhiteboardUpdateType(updateType: HMSWhiteboardUpdateType) -> String?{ + switch updateType{ + case .started: + return "on_whiteboard_start" + case .stopped: + return "on_whiteboard_stop" + default: + return nil + } + } +} diff --git a/packages/hmssdk_flutter/ios/Classes/Models/HMSPermissionExtension.swift b/packages/hmssdk_flutter/ios/Classes/Models/HMSPermissionExtension.swift index a70e374b3..8a064e6b2 100644 --- a/packages/hmssdk_flutter/ios/Classes/Models/HMSPermissionExtension.swift +++ b/packages/hmssdk_flutter/ios/Classes/Models/HMSPermissionExtension.swift @@ -9,8 +9,8 @@ import Foundation import HMSSDK class HMSPermissionExtension { - - static func toDictionary(_ permission: HMSPermissions) -> [String: Bool] { + + static func toDictionary(_ permission: HMSPermissions) -> [String: Any?] { [ "browser_recording": permission.browserRecording ?? false, "change_role": permission.changeRole ?? false, @@ -21,8 +21,25 @@ class HMSPermissionExtension { "rtmp_streaming": permission.rtmpStreaming ?? false, "un_mute": permission.unmute ?? false, "poll_read": permission.pollRead ?? false, - "poll_write": permission.pollWrite ?? false - + "poll_write": permission.pollWrite ?? false, + "whiteboard_permission": getMapFromHMSWhiteboardPermission(hmsWhiteboardPermission: permission.whiteboard) ] } + + static func getMapFromHMSWhiteboardPermission(hmsWhiteboardPermission: HMSWhiteboardPermission?) -> [String:Any?]?{ + + guard let hmsWhiteboardPermission = hmsWhiteboardPermission + else{ + return nil + } + + var permission = [String:Any?]() + + permission["admin"] = hmsWhiteboardPermission.admin + permission["write"] = hmsWhiteboardPermission.write + permission["read"] = hmsWhiteboardPermission.read + + return permission + } + } diff --git a/packages/hmssdk_flutter/ios/Classes/Models/HMSWhiteboardExtension.swift b/packages/hmssdk_flutter/ios/Classes/Models/HMSWhiteboardExtension.swift new file mode 100644 index 000000000..57b08c2d7 --- /dev/null +++ b/packages/hmssdk_flutter/ios/Classes/Models/HMSWhiteboardExtension.swift @@ -0,0 +1,31 @@ +// +// HMSWhiteboardExtension.swift +// hmssdk_flutter +// +// Created by Pushpam on 30/04/24. +// + +import Foundation +import HMSSDK + +class HMSWhiteboardExtension{ + + static func toDictionary(hmsWhiteboard: HMSWhiteboard?) -> [String: Any?]?{ + + guard let whiteboard = hmsWhiteboard else{ + return nil + } + + var args = [String: Any?]() + + args["id"] = hmsWhiteboard?.id + + if let owner = hmsWhiteboard?.owner{ + args["owner"] = HMSPeerExtension.toDictionary(owner) + } + args["title"] = hmsWhiteboard?.title + args["url"] = hmsWhiteboard?.url?.absoluteString + + return args + } +} diff --git a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift index 3fff710f8..215c38a62 100644 --- a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift +++ b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift @@ -17,7 +17,8 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene var sessionEventChannel: FlutterEventChannel? var hlsPlayerChannel: FlutterEventChannel? var pollsEventChannel: FlutterEventChannel? - + var whiteboardEventChannel: FlutterEventChannel? + var eventSink: FlutterEventSink? var previewSink: FlutterEventSink? var logsSink: FlutterEventSink? @@ -25,6 +26,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene var sessionSink: FlutterEventSink? var hlsPlayerSink: FlutterEventSink? var pollsEventSink: FlutterEventSink? + var whiteboardEventSink: FlutterEventSink? var roleChangeRequest: HMSRoleChangeRequest? @@ -57,7 +59,8 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene let sessionChannel = FlutterEventChannel(name: "session_event_channel", binaryMessenger: registrar.messenger()) let hlsChannel = FlutterEventChannel(name: "hls_player_channel", binaryMessenger: registrar.messenger()) let pollsChannel = FlutterEventChannel(name: "polls_event_channel", binaryMessenger: registrar.messenger()) - + let whiteboardChannel = FlutterEventChannel(name: "whiteboard_event_channel", binaryMessenger: registrar.messenger()) + let instance = SwiftHmssdkFlutterPlugin(channel: channel, meetingEventChannel: eventChannel, previewEventChannel: previewChannel, @@ -65,7 +68,8 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene rtcStatsEventChannel: rtcChannel, sessionEventChannel: sessionChannel, hlsPlayerChannel: hlsChannel, - pollsEventChannel: pollsChannel) + pollsEventChannel: pollsChannel, + whiteboardEventChannel: whiteboardChannel) let videoViewFactory = HMSFlutterPlatformViewFactory(plugin: instance) registrar.register(videoViewFactory, withId: "HMSFlutterPlatformView") @@ -80,6 +84,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene sessionChannel.setStreamHandler(instance) hlsChannel.setStreamHandler(instance) pollsChannel.setStreamHandler(instance) + whiteboardChannel.setStreamHandler(instance) registrar.addMethodCallDelegate(instance, channel: channel) } @@ -91,7 +96,8 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene rtcStatsEventChannel: FlutterEventChannel, sessionEventChannel: FlutterEventChannel, hlsPlayerChannel: FlutterEventChannel, - pollsEventChannel: FlutterEventChannel) { + pollsEventChannel: FlutterEventChannel, + whiteboardEventChannel: FlutterEventChannel) { self.channel = channel self.meetingEventChannel = meetingEventChannel @@ -101,6 +107,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene self.sessionEventChannel = sessionEventChannel self.hlsPlayerChannel = hlsPlayerChannel self.pollsEventChannel = pollsEventChannel + self.whiteboardEventChannel = whiteboardEventChannel } public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { @@ -125,6 +132,8 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene hlsPlayerSink = events case "polls": pollsEventSink = events + case "whiteboard": + whiteboardEventSink = events default: return FlutterError(code: #function, message: "invalid event sink name", details: arguments) } @@ -179,6 +188,12 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene } else { print(#function, "pollsEventChannel not found") } + if whiteboardEventChannel != nil { + whiteboardEventChannel!.setStreamHandler(nil) + whiteboardEventSink = nil + } else { + print(#function, "whiteboardEventChannel not found") + } } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -323,6 +338,9 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene case "enable_noise_cancellation", "disable_noise_cancellation", "is_noise_cancellation_enabled", "is_noise_cancellation_available": HMSNoiseCancellationController.noiseCancellationActions(call, result) + case "start_whiteboard", "stop_whiteboard", "add_whiteboard_update_listener", "remove_whiteboard_update_listener": + whiteboardActions(call,result) + default: result(FlutterMethodNotImplemented) } @@ -464,6 +482,42 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene } } + private func whiteboardActions(_ call: FlutterMethodCall, _ result: @escaping FlutterResult){ + switch call.method{ + case "add_whiteboard_update_listener": + + let whiteboardListener: HMSInteractivityCenter.HMSWhiteboardUpdateListener = { [weak self] hmsWhiteboard, hmsWhiteBoardUpdateType in + + guard let self = self else {return} + + switch hmsWhiteBoardUpdateType{ + + case .started: + let args = [ + "event_name": "on_whiteboard_start", + "data": HMSWhiteboardExtension.toDictionary(hmsWhiteboard: hmsWhiteboard) + ] + self.whiteboardEventSink?(args) + break + case .stopped: + let args = [ + "event_name": "on_whiteboard_stop", + "data": HMSWhiteboardExtension.toDictionary(hmsWhiteboard: hmsWhiteboard) + ] + self.whiteboardEventSink?(args) + break + default: + break + } + } + hmsSDK?.interactivityCenter.addWhiteboardUpdateListener(whiteboardListener) + case "remove_whiteboard_update_listener": + break + default: + HMSWhiteboardAction.whiteboardActions(call, result, hmsSDK) + } + } + // MARK: - Track Setting var audioMixerSourceMap = [String: HMSAudioNode]() private func trackSettingsAction(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { diff --git a/packages/hmssdk_flutter/lib/assets/sdk-versions.json b/packages/hmssdk_flutter/lib/assets/sdk-versions.json index bebc1b31e..dac2d7a3d 100644 --- a/packages/hmssdk_flutter/lib/assets/sdk-versions.json +++ b/packages/hmssdk_flutter/lib/assets/sdk-versions.json @@ -1,6 +1,6 @@ { "flutter": "1.10.1", - "ios": "1.9.0", + "ios": "1.10.0", "iOSBroadcastExtension": "0.0.9", "iOSHLSPlayerSDK": "0.0.2", "iOSNoiseCancellationModels": "1.0.0", diff --git a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart index 4fd3f1956..f53c2bbcf 100644 --- a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart +++ b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart @@ -25,6 +25,7 @@ export 'src/enum/hms_hls_playback_state.dart'; export 'src/enum/hms_poll_enum.dart'; export 'src/enum/hms_peer_type.dart'; export 'src/enum/hms_hls_playlist_type.dart'; +export 'src/enum/hms_whiteboard_listener_method.dart'; //EXCEPTIONS export 'src/exceptions/hms_exception.dart'; @@ -59,7 +60,6 @@ export 'src/model/hms_video_resolution.dart'; export 'src/model/hms_video_setting.dart'; export 'src/model/hms_video_track.dart'; export 'src/model/hms_video_track_setting.dart'; -export 'src/model/platform_method_response.dart'; export 'src/model/hms_track_change_request.dart'; export 'src/model/hms_peer_removed_from_room.dart'; export 'src/model/hms_message_recipient.dart'; @@ -116,6 +116,10 @@ export 'src/model/polls/hms_poll_leaderboard_summary.dart'; export 'src/model/polls/hms_poll_peer_info_response.dart'; export 'src/model/hms_noise_cancellation_controller.dart'; export 'src/model/hls_stream_properties.dart'; +export 'src/model/whiteboard/hms_whiteboard_controller.dart'; +export 'src/model/whiteboard/hms_whiteboard_model.dart'; +export 'src/model/whiteboard/hms_whiteboard_permission.dart'; +export 'src/model/whiteboard/hms_whiteboard_update_listener.dart'; export 'src/model/hls_player/hms_hls_layer.dart'; //Views diff --git a/packages/hmssdk_flutter/lib/src/common/platform_methods.dart b/packages/hmssdk_flutter/lib/src/common/platform_methods.dart index 74d11b5ea..178f82cee 100644 --- a/packages/hmssdk_flutter/lib/src/common/platform_methods.dart +++ b/packages/hmssdk_flutter/lib/src/common/platform_methods.dart @@ -232,7 +232,13 @@ enum PlatformMethod { enableNoiseCancellation, disableNoiseCancellation, isNoiseCancellationEnabled, - isNoiseCancellationAvailable + isNoiseCancellationAvailable, + + ///Whiteboard methods + startWhiteboard, + stopWhiteboard, + addWhiteboardUpdateListener, + removeWhiteboardUpdateListener, } extension PlatformMethodValues on PlatformMethod { @@ -587,6 +593,17 @@ extension PlatformMethodValues on PlatformMethod { return "is_noise_cancellation_enabled"; case PlatformMethod.isNoiseCancellationAvailable: return "is_noise_cancellation_available"; + + ///Whiteboard Methods + case PlatformMethod.startWhiteboard: + return "start_whiteboard"; + case PlatformMethod.stopWhiteboard: + return "stop_whiteboard"; + case PlatformMethod.addWhiteboardUpdateListener: + return "add_whiteboard_update_listener"; + case PlatformMethod.removeWhiteboardUpdateListener: + return "remove_whiteboard_update_listener"; + default: return 'unknown'; } @@ -942,6 +959,16 @@ extension PlatformMethodValues on PlatformMethod { case "is_noise_cancellation_available": return PlatformMethod.isNoiseCancellationAvailable; + ///Whiteboard Methods + case "start_whiteboard": + return PlatformMethod.startWhiteboard; + case "stop_whiteboard": + return PlatformMethod.stopWhiteboard; + case "add_whiteboard_update_listener": + return PlatformMethod.addWhiteboardUpdateListener; + case "remove_whiteboard_update_listener": + return PlatformMethod.removeWhiteboardUpdateListener; + default: return PlatformMethod.unknown; } diff --git a/packages/hmssdk_flutter/lib/src/enum/hms_whiteboard_listener_method.dart b/packages/hmssdk_flutter/lib/src/enum/hms_whiteboard_listener_method.dart new file mode 100644 index 000000000..5066736c3 --- /dev/null +++ b/packages/hmssdk_flutter/lib/src/enum/hms_whiteboard_listener_method.dart @@ -0,0 +1,19 @@ +enum HMSWhiteboardListenerMethod { + onWhiteboardStart, + onWhiteboardStop, + unknown +} + +extension HMSWhiteboardListenerMethodValues on HMSWhiteboardListenerMethod { + static HMSWhiteboardListenerMethod getHMSWhiteboardListenerMethodFromString( + String whiteboardMethod) { + switch (whiteboardMethod) { + case 'on_whiteboard_start': + return HMSWhiteboardListenerMethod.onWhiteboardStart; + case 'on_whiteboard_stop': + return HMSWhiteboardListenerMethod.onWhiteboardStop; + default: + return HMSWhiteboardListenerMethod.unknown; + } + } +} diff --git a/packages/hmssdk_flutter/lib/src/model/hms_permissions.dart b/packages/hmssdk_flutter/lib/src/model/hms_permissions.dart index bc1792034..312e2a019 100644 --- a/packages/hmssdk_flutter/lib/src/model/hms_permissions.dart +++ b/packages/hmssdk_flutter/lib/src/model/hms_permissions.dart @@ -1,3 +1,5 @@ +import 'package:hmssdk_flutter/src/model/whiteboard/hms_whiteboard_permission.dart'; + ///100ms HMSPermissions /// ///[HMSPermissions] contains permissions for local peer like end room, remove others, mute and unmute other peers, role change and other permissions. @@ -12,6 +14,7 @@ class HMSPermissions { final bool? unMute; final bool? pollRead; final bool? pollWrite; + final HMSWhiteboardPermission? whiteboard; HMSPermissions( {this.endRoom, @@ -23,7 +26,8 @@ class HMSPermissions { this.unMute, this.changeRole, this.pollRead, - this.pollWrite}); + this.pollWrite, + this.whiteboard}); factory HMSPermissions.fromMap(Map map) { return HMSPermissions( @@ -36,21 +40,9 @@ class HMSPermissions { rtmpStreaming: map['rtmp_streaming'], unMute: map['un_mute'], pollRead: map['poll_read'], - pollWrite: map['poll_write']); - } - - Map toJson() { - return { - 'end_room': endRoom, - 'browser_recording': browserRecording, - 'remove_others': removeOthers, - 'mute': mute, - 'un_mute': unMute, - 'hls_streaming': hlsStreaming, - 'rtmp_streaming': rtmpStreaming, - 'change_role': changeRole, - 'poll_read': pollRead, - 'poll_write': pollWrite - }; + pollWrite: map['poll_write'], + whiteboard: map['whiteboard_permission'] != null + ? HMSWhiteboardPermission.fromMap(map['whiteboard_permission']) + : null); } } diff --git a/packages/hmssdk_flutter/lib/src/model/platform_method_response.dart b/packages/hmssdk_flutter/lib/src/model/platform_method_response.dart index 223fe02f6..3d2cc531b 100644 --- a/packages/hmssdk_flutter/lib/src/model/platform_method_response.dart +++ b/packages/hmssdk_flutter/lib/src/model/platform_method_response.dart @@ -92,3 +92,14 @@ class HMSPollListenerMethodResponse { HMSPollListenerMethodResponse({required this.method, required this.data}); } + +///HMSWhiteboardListenerMethodResponse contains all the responses sent from the whiteboard channel +/// +/// Checkout different responses in [HMSWhiteboardListenerMethod] enum +class HMSWhiteboardListenerMethodResponse { + final HMSWhiteboardListenerMethod method; + final Map data; + + HMSWhiteboardListenerMethodResponse( + {required this.method, required this.data}); +} diff --git a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart new file mode 100644 index 000000000..95d253cde --- /dev/null +++ b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart @@ -0,0 +1,36 @@ +import 'package:hmssdk_flutter/hmssdk_flutter.dart'; +import 'package:hmssdk_flutter/src/service/platform_service.dart'; + +class HMSWhiteboardController { + static Future start({required String title}) async { + var result = await PlatformService.invokeMethod( + PlatformMethod.startWhiteboard, + arguments: {"title": title}); + + if (result != null) { + return HMSException.fromMap(result["error"]); + } else { + return null; + } + } + + static Future stop() async { + var result = + await PlatformService.invokeMethod(PlatformMethod.stopWhiteboard); + + if (result != null) { + return HMSException.fromMap(result["error"]); + } else { + return null; + } + } + + static void addHMSWhiteboardUpdateListener( + {required HMSWhiteboardUpdateListener listener}) { + PlatformService.addWhiteboardUpdateListener(listener); + } + + static void removeHMSWhiteboardUpdateListener() { + PlatformService.removeWhiteboardUpdateListener(); + } +} diff --git a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_model.dart b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_model.dart new file mode 100644 index 000000000..da32f984a --- /dev/null +++ b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_model.dart @@ -0,0 +1,27 @@ +//Project imports +import 'package:hmssdk_flutter/src/model/hms_peer.dart'; + +///[HMSWhiteboardModel] is a class which includes the properties of a whiteboard +class HMSWhiteboardModel { + ///[id] is the unique identifier of the whiteboard + final String id; + + ///[owner] is the owner of the whiteboard + final HMSPeer? owner; + + ///[title] is the title of the whiteboard + final String? title; + + ///[url] is the url of the whiteboard which can be used to display whiteboard + final String? url; + + HMSWhiteboardModel({required this.id, this.owner, this.title, this.url}); + + factory HMSWhiteboardModel.fromMap(Map map) { + return HMSWhiteboardModel( + id: map['id'], + owner: map['owner'] != null ? HMSPeer.fromMap(map['owner']) : null, + title: map['title'], + url: map['url']); + } +} diff --git a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_permission.dart b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_permission.dart new file mode 100644 index 000000000..7fde01ac8 --- /dev/null +++ b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_permission.dart @@ -0,0 +1,15 @@ +class HMSWhiteboardPermission { + final bool admin; + final bool write; + final bool read; + + const HMSWhiteboardPermission( + {required this.admin, required this.write, required this.read}); + + factory HMSWhiteboardPermission.fromMap(Map map) { + return HMSWhiteboardPermission( + admin: map['admin'] ?? false, + write: map['write'] ?? false, + read: map['read'] ?? false); + } +} diff --git a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_update_listener.dart b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_update_listener.dart new file mode 100644 index 000000000..00884ee68 --- /dev/null +++ b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_update_listener.dart @@ -0,0 +1,7 @@ +// Project imports +import 'package:hmssdk_flutter/src/model/whiteboard/hms_whiteboard_model.dart'; + +abstract class HMSWhiteboardUpdateListener { + void onWhiteboardStart({required HMSWhiteboardModel hmsWhiteboardModel}); + void onWhiteboardStop({required HMSWhiteboardModel hmsWhiteboardModel}); +} diff --git a/packages/hmssdk_flutter/lib/src/service/platform_service.dart b/packages/hmssdk_flutter/lib/src/service/platform_service.dart index a9b01ea4a..29e51d085 100644 --- a/packages/hmssdk_flutter/lib/src/service/platform_service.dart +++ b/packages/hmssdk_flutter/lib/src/service/platform_service.dart @@ -18,6 +18,7 @@ import 'package:hmssdk_flutter/src/enum/hms_hls_playback_event_method.dart'; import 'package:hmssdk_flutter/src/enum/hms_key_change_listener_method.dart'; import 'package:hmssdk_flutter/src/enum/hms_logs_update_listener.dart'; import 'package:hmssdk_flutter/src/model/hms_key_change_observer.dart'; +import 'package:hmssdk_flutter/src/model/platform_method_response.dart'; abstract class PlatformService { ///used to pass data to platform using methods @@ -46,9 +47,14 @@ abstract class PlatformService { static const EventChannel _hlsPlayerChannel = const EventChannel("hls_player_channel"); + ///used to get poll event updates static const EventChannel _pollsEventChannel = const EventChannel("polls_event_channel"); + ///used to get whiteboard events + static const EventChannel _whiteboardEventChannel = + const EventChannel("whiteboard_event_channel"); + ///add meeting listeners. static List updateListeners = []; @@ -63,6 +69,8 @@ abstract class PlatformService { static HMSPollListener? _pollListener; + static HMSWhiteboardUpdateListener? _whiteboardListener; + ///List for event Listener static List statsListeners = []; static bool isStartedListening = false; @@ -108,6 +116,17 @@ abstract class PlatformService { PlatformService.invokeMethod(PlatformMethod.addPollUpdateListener); } + static void addWhiteboardUpdateListener( + HMSWhiteboardUpdateListener listener) { + _whiteboardListener = listener; + PlatformService.invokeMethod(PlatformMethod.addWhiteboardUpdateListener); + } + + static void removeWhiteboardUpdateListener() { + _whiteboardListener = null; + PlatformService.invokeMethod(PlatformMethod.removeWhiteboardUpdateListener); + } + static void removePollUpdateListener() { _pollListener = null; PlatformService.invokeMethod(PlatformMethod.removePollUpdateListener); @@ -585,6 +604,28 @@ abstract class PlatformService { break; } }); + + _whiteboardEventChannel + .receiveBroadcastStream({'name': 'whiteboard'}).map((event) { + HMSWhiteboardListenerMethod method = HMSWhiteboardListenerMethodValues + .getHMSWhiteboardListenerMethodFromString(event['event_name']); + Map data = event['data']; + return HMSWhiteboardListenerMethodResponse(method: method, data: data); + }).listen((event) { + HMSWhiteboardListenerMethod method = event.method; + switch (method) { + case HMSWhiteboardListenerMethod.onWhiteboardStart: + _whiteboardListener?.onWhiteboardStart( + hmsWhiteboardModel: HMSWhiteboardModel.fromMap(event.data)); + break; + case HMSWhiteboardListenerMethod.onWhiteboardStop: + _whiteboardListener?.onWhiteboardStop( + hmsWhiteboardModel: HMSWhiteboardModel.fromMap(event.data)); + break; + case HMSWhiteboardListenerMethod.unknown: + break; + } + }); } static void notifyLogsUpdateListeners( From c4de74098475e5f0f7591ea5ed5fade461c97f82 Mon Sep 17 00:00:00 2001 From: Pushpam <93931528+Decoder07@users.noreply.github.com> Date: Fri, 10 May 2024 14:38:41 +0530 Subject: [PATCH 07/15] Fixed audio track settings (#1765) --- .../Classes/Models/HMSTrackSettingsExtension.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/hmssdk_flutter/ios/Classes/Models/HMSTrackSettingsExtension.swift b/packages/hmssdk_flutter/ios/Classes/Models/HMSTrackSettingsExtension.swift index 4063cc75a..74165d6d3 100644 --- a/packages/hmssdk_flutter/ios/Classes/Models/HMSTrackSettingsExtension.swift +++ b/packages/hmssdk_flutter/ios/Classes/Models/HMSTrackSettingsExtension.swift @@ -83,6 +83,19 @@ class HMSTrackSettingsExtension { if let mode = getAudioMode(from: audioSettingsDict["audio_mode"] as? String) { builder.audioMode = mode } + + /* + Here we set the noise cancellation controller based on the parameter passed in audio track + settings + */ + if let enableNoiseCancellation = audioSettingsDict["enable_noise_cancellation"] as? Bool { + if enableNoiseCancellation { + + /// We create the noise cancellation plugin + HMSNoiseCancellationController.createPlugin() + builder.noiseCancellationPlugin = HMSNoiseCancellationController.noiseCancellationController + } + } }) } catch { From f9342d9f87f50f281c3e8d86105a746b4369d6b1 Mon Sep 17 00:00:00 2001 From: Pushpam <93931528+Decoder07@users.noreply.github.com> Date: Fri, 10 May 2024 15:10:29 +0530 Subject: [PATCH 08/15] Added HLS Stats (#1766) --- .../lib/src/hls_viewer/hls_player.dart | 3 + .../lib/src/hls_viewer/hls_stats_view.dart | 174 ++++++++++-------- .../hmssdk_flutter/example/ios/Podfile.lock | 2 +- packages/hmssdk_flutter/example/pubspec.lock | 66 +++---- 4 files changed, 120 insertions(+), 125 deletions(-) diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_player.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_player.dart index 0632aad64..68b0b50f4 100644 --- a/packages/hms_room_kit/lib/src/hls_viewer/hls_player.dart +++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_player.dart @@ -6,6 +6,7 @@ import 'package:hmssdk_flutter/hmssdk_flutter.dart'; import 'package:provider/provider.dart'; ///Project imports +import 'package:hms_room_kit/src/hls_viewer/hls_stats_view.dart'; import 'package:hms_room_kit/src/hls_viewer/hls_player_store.dart'; import 'package:hms_room_kit/src/meeting/meeting_store.dart'; import 'package:hms_room_kit/src/hls_viewer/hls_player_overlay_options.dart'; @@ -68,6 +69,8 @@ class HLSPlayer extends StatelessWidget { }) : Center(child: const HLSWaitingUI()), + const HLSStatsView(), + ///This renders the overlay controls for HLS Player Align( alignment: Alignment.center, diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_stats_view.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_stats_view.dart index 1b411e895..39b996df2 100644 --- a/packages/hms_room_kit/lib/src/hls_viewer/hls_stats_view.dart +++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_stats_view.dart @@ -1,91 +1,107 @@ +library; + +///Package imports import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +///Project imports import 'package:hms_room_kit/src/common/app_color.dart'; import 'package:hms_room_kit/src/hls_viewer/hls_player_store.dart'; -import 'package:provider/provider.dart'; +import 'package:hms_room_kit/src/meeting/meeting_store.dart'; import 'package:hms_room_kit/src/widgets/common_widgets/hms_text_style.dart'; +///[HLSStatsView] is a component that is used to show the HLS Player Stats class HLSStatsView extends StatelessWidget { const HLSStatsView({super.key}); @override Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(5), - margin: const EdgeInsets.all(2), - decoration: BoxDecoration( - color: Colors.black38.withOpacity(0.3), - borderRadius: const BorderRadius.all(Radius.circular(10))), - child: ListView( - shrinkWrap: true, - children: [ - Selector( - builder: (_, bitrate, __) { - return Text( - "Bitrate : ${bitrate == null ? "-" : (bitrate / 8000)} KBps", - style: HMSTextStyle.setTextStyle( - color: iconColor, fontSize: 12)); - }, - selector: (_, hlsPlayerStore) => - hlsPlayerStore.hlsPlayerStats?.averageBitrate), - const SizedBox( - height: 10, - ), - Selector( - builder: (_, bufferedDuration, __) { - return Text( - "Buffered Duration : ${bufferedDuration == null ? "-" : bufferedDuration / 1000}", - style: HMSTextStyle.setTextStyle( - color: iconColor, fontSize: 12)); - }, - selector: (_, hlsPlayerStore) => - hlsPlayerStore.hlsPlayerStats?.bufferedDuration), - const SizedBox( - height: 10, - ), - Selector( - builder: (_, videoWidth, __) { - return Text("Video Width : ${videoWidth ?? "-"} px", - style: HMSTextStyle.setTextStyle( - color: iconColor, fontSize: 12)); - }, - selector: (_, hlsPlayerStore) => - hlsPlayerStore.hlsPlayerStats?.videoWidth), - const SizedBox( - height: 10, - ), - Selector( - builder: (_, videoHeight, __) { - return Text("Video Height : ${videoHeight ?? "-"} px", - style: HMSTextStyle.setTextStyle( - color: iconColor, fontSize: 12)); - }, - selector: (_, hlsPlayerStore) => - hlsPlayerStore.hlsPlayerStats?.videoHeight), - const SizedBox( - height: 10, - ), - Selector( - builder: (_, droppedFrameCount, __) { - return Text("Dropped Frames : ${droppedFrameCount ?? "-"} ", - style: HMSTextStyle.setTextStyle( - color: iconColor, fontSize: 12)); - }, - selector: (_, hlsPlayerStore) => - hlsPlayerStore.hlsPlayerStats?.droppedFrameCount), - const SizedBox( - height: 10, - ), - Selector( - builder: (_, distanceFromLive, __) { - return Text( - "Distance from live edge : ${distanceFromLive == null ? "-" : distanceFromLive / 1000}s", - style: HMSTextStyle.setTextStyle( - color: iconColor, fontSize: 12)); - }, - selector: (_, hlsPlayerStore) => - hlsPlayerStore.hlsPlayerStats?.distanceFromLive), - ], - ), - ); + return Selector( + selector: (_, meetingStore) => meetingStore.isStatsVisible, + builder: (_, statsVisible, __) { + return statsVisible + ? Container( + padding: const EdgeInsets.all(5), + margin: const EdgeInsets.all(2), + decoration: BoxDecoration( + color: Colors.black38.withOpacity(0.3), + borderRadius: + const BorderRadius.all(Radius.circular(10))), + child: ListView( + shrinkWrap: true, + children: [ + Selector( + builder: (_, bitrate, __) { + return Text( + "Bitrate : ${bitrate == null ? "-" : (bitrate / 1000)} Kbps", + style: HMSTextStyle.setTextStyle( + color: iconColor, fontSize: 12)); + }, + selector: (_, hlsPlayerStore) => + hlsPlayerStore.hlsPlayerStats?.averageBitrate), + const SizedBox( + height: 10, + ), + Selector( + builder: (_, bufferedDuration, __) { + return Text( + "Buffered Duration : ${bufferedDuration == null ? "-" : bufferedDuration / 1000}", + style: HMSTextStyle.setTextStyle( + color: iconColor, fontSize: 12)); + }, + selector: (_, hlsPlayerStore) => + hlsPlayerStore.hlsPlayerStats?.bufferedDuration), + const SizedBox( + height: 10, + ), + Selector( + builder: (_, videoWidth, __) { + return Text("Video Width : ${videoWidth ?? "-"} px", + style: HMSTextStyle.setTextStyle( + color: iconColor, fontSize: 12)); + }, + selector: (_, hlsPlayerStore) => + hlsPlayerStore.hlsPlayerStats?.videoWidth), + const SizedBox( + height: 10, + ), + Selector( + builder: (_, videoHeight, __) { + return Text( + "Video Height : ${videoHeight ?? "-"} px", + style: HMSTextStyle.setTextStyle( + color: iconColor, fontSize: 12)); + }, + selector: (_, hlsPlayerStore) => + hlsPlayerStore.hlsPlayerStats?.videoHeight), + const SizedBox( + height: 10, + ), + Selector( + builder: (_, droppedFrameCount, __) { + return Text( + "Dropped Frames : ${droppedFrameCount ?? "-"} ", + style: HMSTextStyle.setTextStyle( + color: iconColor, fontSize: 12)); + }, + selector: (_, hlsPlayerStore) => + hlsPlayerStore.hlsPlayerStats?.droppedFrameCount), + const SizedBox( + height: 10, + ), + Selector( + builder: (_, distanceFromLive, __) { + return Text( + "Distance from live edge : ${distanceFromLive == null ? "-" : distanceFromLive / 1000}s", + style: HMSTextStyle.setTextStyle( + color: iconColor, fontSize: 12)); + }, + selector: (_, hlsPlayerStore) => + hlsPlayerStore.hlsPlayerStats?.distanceFromLive), + ], + ), + ) + : const SizedBox(); + }); } } diff --git a/packages/hmssdk_flutter/example/ios/Podfile.lock b/packages/hmssdk_flutter/example/ios/Podfile.lock index 5ade372bc..0485c7125 100644 --- a/packages/hmssdk_flutter/example/ios/Podfile.lock +++ b/packages/hmssdk_flutter/example/ios/Podfile.lock @@ -332,4 +332,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 9fb9f6e431a2c6c79942252e94b241ac7972ac90 -COCOAPODS: 1.15.2 +COCOAPODS: 1.14.3 diff --git a/packages/hmssdk_flutter/example/pubspec.lock b/packages/hmssdk_flutter/example/pubspec.lock index 2369d95c5..ac8f356f1 100644 --- a/packages/hmssdk_flutter/example/pubspec.lock +++ b/packages/hmssdk_flutter/example/pubspec.lock @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" convert: dependency: transitive description: @@ -342,30 +342,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" linkify: dependency: transitive description: @@ -386,26 +362,26 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.9.1" mime: dependency: transitive description: @@ -450,10 +426,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" path_parsing: dependency: transitive description: @@ -719,18 +695,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -751,10 +727,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" tuple: dependency: transitive description: @@ -883,14 +859,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.0+2" - vm_service: + web: dependency: transitive description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "0.1.4-beta" webview_flutter: dependency: transitive description: @@ -948,5 +924,5 @@ packages: source: hosted version: "6.3.0" sdks: - dart: ">=3.2.0-0 <4.0.0" + dart: ">=3.1.0 <4.0.0" flutter: ">=3.13.0" From ed09cbc580002bc25e809e7a112948a3d7803e30 Mon Sep 17 00:00:00 2001 From: Pushpam <93931528+Decoder07@users.noreply.github.com> Date: Wed, 15 May 2024 13:39:02 +0530 Subject: [PATCH 09/15] Added whiteboard sdk changes (#1767) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added whiteboard sdk changes * 🤖 Automated Format and Fix * Fixed android whiteboard issue * Updated version numbers * 🤖 Automated Format and Fix * released sample app version 1.5.193 (493) 🍀 * 🤖 Automated Format and Fix * Removed unused await * Updated methods * Fixed widget errors * 🤖 Automated Format and Fix * fixed flutter version in yaml * Removed 3.22 code updates * 🤖 Automated Format and Fix * Updated date --------- Co-authored-by: Decoder07 Co-authored-by: Yogesh Singh --- .github/workflows/build.yml | 1 + packages/hms_room_kit/CHANGELOG.md | 19 ++++++ .../lib/src/hls_viewer/hls_player_store.dart | 2 +- .../lib/src/meeting/meeting_store.dart | 2 +- .../app_utilities_bottom_sheet.dart | 3 +- .../whiteboard_webview.dart | 54 ++++++++++----- packages/hmssdk_flutter/CHANGELOG.md | 25 +++++++ packages/hmssdk_flutter/android/build.gradle | 12 ++-- .../hmssdk_flutter/HMSWhiteboardExtension.kt | 12 +++- .../example/ExampleAppChangelog.txt | 2 +- .../example/android/app/build.gradle | 4 +- .../example/ios/Runner/Info.plist | 4 +- .../Models/HMSWhiteboardExtension.swift | 15 ++++- .../Classes/SwiftHmssdkFlutterPlugin.swift | 4 +- .../lib/assets/sdk-versions.json | 4 +- .../hmssdk_flutter/lib/hmssdk_flutter.dart | 1 + .../lib/src/enum/hms_whiteboard_state.dart | 15 +++++ .../whiteboard/hms_whiteboard_controller.dart | 21 ++++++ .../whiteboard/hms_whiteboard_model.dart | 20 +++++- .../whiteboard/hms_whiteboard_permission.dart | 6 ++ .../hms_whiteboard_update_listener.dart | 6 ++ packages/hmssdk_flutter/pubspec.lock | 66 ++++++------------- 22 files changed, 210 insertions(+), 88 deletions(-) create mode 100644 packages/hmssdk_flutter/lib/src/enum/hms_whiteboard_state.dart diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8268c242e..b56e33204 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,6 +41,7 @@ jobs: - uses: subosito/flutter-action@v2 with: channel: stable + flutter-version: 3.13.9 cache: true - name: Get Flutter dependencies in Core SDK run: flutter pub get diff --git a/packages/hms_room_kit/CHANGELOG.md b/packages/hms_room_kit/CHANGELOG.md index 2dabfff25..1547ec2e0 100644 --- a/packages/hms_room_kit/CHANGELOG.md +++ b/packages/hms_room_kit/CHANGELOG.md @@ -5,6 +5,25 @@ | hms_room_kit | [![Pub Version](https://img.shields.io/pub/v/hms_room_kit)](https://pub.dev/packages/hms_room_kit) | | hmssdk_flutter | [![Pub Version](https://img.shields.io/pub/v/hmssdk_flutter)](https://pub.dev/packages/hmssdk_flutter) | +## 1.1.2 - 2024-05-15 + +| Package | Version | +| -------------- | ------------------------------------------------------------------------------------------------------ | +| hms_room_kit | 1.1.2 | +| hmssdk_flutter | 1.10.2 | + +### 🚀 Added + +- Whiteboard support in Prebuilt + + Prebuilt now supports whiteboard for better collaboration. Users can create, manage, and stop whiteboards directly from the prebuilt interface. + +- Introducing option to select layers in HLS Player + + HLS Player now supports layer selection from HLS Player Settings. + +Uses `hmssdk_flutter` package version 1.10.2 + ## 1.1.1 - 2024-04-26 | Package | Version | diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart index 3b025de0b..911fbbfcc 100644 --- a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart +++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart @@ -266,7 +266,7 @@ class HLSPlayerStore extends ChangeNotifier ///[setHLSLayer] sets the HLS Layer void setHLSLayer(HMSHLSLayer hmsHLSLayer) async { selectedLayer = hmsHLSLayer; - await HMSHLSPlayerController.setHLSLayer(hmsHLSLayer: hmsHLSLayer); + HMSHLSPlayerController.setHLSLayer(hmsHLSLayer: hmsHLSLayer); notifyListeners(); } diff --git a/packages/hms_room_kit/lib/src/meeting/meeting_store.dart b/packages/hms_room_kit/lib/src/meeting/meeting_store.dart index cf43e2ce9..e3ed2aa0a 100644 --- a/packages/hms_room_kit/lib/src/meeting/meeting_store.dart +++ b/packages/hms_room_kit/lib/src/meeting/meeting_store.dart @@ -2417,7 +2417,7 @@ class MeetingStore extends ChangeNotifier void toggleWhiteboard() async { if (isWhiteboardEnabled) { - if (localPeer?.peerId == whiteboardModel?.owner?.peerId) { + if (whiteboardModel?.isOwner ?? false) { HMSException? error = await HMSWhiteboardController.stop(); if (error != null) { log("HMSWhiteboardController.stop error: ${error.description}"); diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/app_utilities_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/app_utilities_bottom_sheet.dart index 68a727751..bb33d6760 100644 --- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/app_utilities_bottom_sheet.dart +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/app_utilities_bottom_sheet.dart @@ -51,8 +51,7 @@ class _AppUtilitiesBottomSheetState extends State { ///we return low emphasis color since whiteboard can't be turned ON ///In other cases we return high emphasis color return meetingStore.isWhiteboardEnabled - ? meetingStore.whiteboardModel?.owner?.customerUserId == - meetingStore.localPeer?.customerUserId + ? meetingStore.whiteboardModel?.isOwner ?? false ? HMSThemeColors.onSurfaceHighEmphasis : HMSThemeColors.onSurfaceLowEmphasis : meetingStore.screenShareCount > 0 || meetingStore.isScreenShareOn diff --git a/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_webview.dart b/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_webview.dart index 094820853..39cc9329d 100644 --- a/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_webview.dart +++ b/packages/hms_room_kit/lib/src/widgets/whiteboard_screenshare/whiteboard_webview.dart @@ -12,9 +12,43 @@ import 'package:webview_flutter/webview_flutter.dart'; import 'package:hms_room_kit/src/meeting/meeting_store.dart'; ///[WhiteboardWebView] is a widget that renders the whiteboard webview -class WhiteboardWebView extends StatelessWidget { +class WhiteboardWebView extends StatefulWidget { const WhiteboardWebView({Key? key}) : super(key: key); + @override + State createState() => _WhiteboardWebViewState(); +} + +class _WhiteboardWebViewState extends State { + late WebViewController _controller; + + @override + void initState() { + super.initState(); + _controller = WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setBackgroundColor(const Color(0x00000000)) + ..setNavigationDelegate( + NavigationDelegate( + onNavigationRequest: (_) { + return NavigationDecision.navigate; + }, + onProgress: (int progress) {}, + onPageStarted: (String url) {}, + onPageFinished: (String url) {}, + onWebResourceError: (WebResourceError error) { + log("Error occured in whiteboard tile: ${error.description}"); + }, + ), + ); + } + + @override + void dispose() { + _controller.loadHtmlString("https://www.100ms.live/"); + super.dispose(); + } + @override Widget build(BuildContext context) { return Selector( @@ -23,23 +57,7 @@ class WhiteboardWebView extends StatelessWidget { ///If the url is not null we render the webview return url != null ? WebViewWidget( - controller: WebViewController() - ..setJavaScriptMode(JavaScriptMode.unrestricted) - ..setBackgroundColor(const Color(0x00000000)) - ..setNavigationDelegate( - NavigationDelegate( - onNavigationRequest: (_) { - return NavigationDecision.navigate; - }, - onProgress: (int progress) {}, - onPageStarted: (String url) {}, - onPageFinished: (String url) {}, - onWebResourceError: (WebResourceError error) { - log("Error occured in whiteboard tile: ${error.description}"); - }, - ), - ) - ..loadRequest(Uri.parse(url))) + controller: _controller..loadRequest(Uri.parse(url))) : const SizedBox(); }); } diff --git a/packages/hmssdk_flutter/CHANGELOG.md b/packages/hmssdk_flutter/CHANGELOG.md index eefddafd3..34000b377 100644 --- a/packages/hmssdk_flutter/CHANGELOG.md +++ b/packages/hmssdk_flutter/CHANGELOG.md @@ -5,6 +5,31 @@ | hms_room_kit | [![Pub Version](https://img.shields.io/pub/v/hms_room_kit)](https://pub.dev/packages/hms_room_kit) | | hmssdk_flutter | [![Pub Version](https://img.shields.io/pub/v/hmssdk_flutter)](https://pub.dev/packages/hmssdk_flutter) | +# 1.10.2 - 2024-05-15 + +| Package | Version | +| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| hms_room_kit | 1.1.2 | +| hmssdk_flutter | 1.10.2 | + +### ✨ Added + +- Introducing Whiteboard support in HMSSDK + + HMSSDK now provides support for Whiteboard. You can now start/stop a whiteboard using `HMSWhiteboardController` methods. HMSSDK provides also provides callbacks for whiteboard start/stop events. Learn more about it [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard) + +- HLS Layer methods + + HLS Stream Layers can be controlled using the HMSHLSPlayerController's `getHLSLayers` and `setHLSLayer` methods. Learn more about the methods [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/record-and-live-stream/hls-player) + +- `onPeerListUpdate` event on `HMSPreviewListener` + + The `onPeerListUpdate` event is now available on `HMSPreviewListener` to get updates on the peer list. Learn more about it [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/preview#supplementary-bytes) + +Uses Android SDK 2.9.56 & iOS SDK 1.10.0 + +**Full Changelog**: [1.10.1...1.10.2](https://github.com/100mslive/100ms-flutter/compare/1.10.1...1.10.2) + # 1.10.1 - 2024-04-26 | Package | Version | diff --git a/packages/hmssdk_flutter/android/build.gradle b/packages/hmssdk_flutter/android/build.gradle index 688912be5..6accc5814 100644 --- a/packages/hmssdk_flutter/android/build.gradle +++ b/packages/hmssdk_flutter/android/build.gradle @@ -47,14 +47,10 @@ android { } dependencies { - implementation "com.github.100mslive.android-sdk:video-view:dev-v2-SNAPSHOT" - implementation "com.github.100mslive.android-sdk:hls-player:dev-v2-SNAPSHOT" - implementation 'com.github.100mslive.android-sdk:android-sdk:dev-v2-SNAPSHOT' - implementation "com.github.100mslive.android-sdk:hms-noise-cancellation-android:dev-v2-SNAPSHOT" -// implementation "live.100ms:android-sdk:${sdkVersions['android']}" -// implementation "live.100ms:video-view:${sdkVersions['android']}" -// implementation "live.100ms:hls-player:${sdkVersions['android']}" -// implementation "live.100ms:hms-noise-cancellation-android:${sdkVersions['android']}" + implementation "live.100ms:android-sdk:${sdkVersions['android']}" + implementation "live.100ms:video-view:${sdkVersions['android']}" + implementation "live.100ms:hls-player:${sdkVersions['android']}" + implementation "live.100ms:hms-noise-cancellation-android:${sdkVersions['android']}" implementation 'com.google.code.gson:gson:2.9.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt index d11fb079b..1632f8b61 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt @@ -2,6 +2,7 @@ package live.hms.hmssdk_flutter import live.hms.video.sdk.models.HMSPeer import live.hms.video.whiteboard.HMSWhiteboard +import live.hms.video.whiteboard.State class HMSWhiteboardExtension { companion object{ @@ -18,8 +19,17 @@ class HMSWhiteboardExtension { whiteboardMap["owner"] = HMSPeerExtension.toDictionary(hmsWhiteboard.owner) whiteboardMap["title"] = hmsWhiteboard.title whiteboardMap["url"] = hmsWhiteboard.url - + whiteboardMap["state"] = getStateFromString(hmsWhiteboard.state) + whiteboardMap["is_owner"] = hmsWhiteboard.isOwner return whiteboardMap } + + private fun getStateFromString(state: State): String{ + return when(state){ + State.Started -> "started" + State.Stopped -> "stopped" + else -> "stopped" + } + } } } \ No newline at end of file diff --git a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt index 119ed3b39..53badfa06 100644 --- a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt +++ b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt @@ -11,5 +11,5 @@ https://100ms.atlassian.net/browse/FLUT-284 Room Kit: 1.1.2 Core SDK: 1.10.2 -Android SDK: 2.9.55 +Android SDK: 2.9.56 iOS SDK: 1.10.0 \ No newline at end of file diff --git a/packages/hmssdk_flutter/example/android/app/build.gradle b/packages/hmssdk_flutter/example/android/app/build.gradle index dbb0397de..d9b49e55c 100644 --- a/packages/hmssdk_flutter/example/android/app/build.gradle +++ b/packages/hmssdk_flutter/example/android/app/build.gradle @@ -36,8 +36,8 @@ android { applicationId "live.hms.flutter" minSdkVersion 21 targetSdkVersion 34 - versionCode 491 - versionName "1.5.191" + versionCode 493 + versionName "1.5.193" } signingConfigs { diff --git a/packages/hmssdk_flutter/example/ios/Runner/Info.plist b/packages/hmssdk_flutter/example/ios/Runner/Info.plist index 87cdb28c4..061bf3fc8 100644 --- a/packages/hmssdk_flutter/example/ios/Runner/Info.plist +++ b/packages/hmssdk_flutter/example/ios/Runner/Info.plist @@ -21,7 +21,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.5.190 + 1.5.193 CFBundleSignature ???? CFBundleURLTypes @@ -48,7 +48,7 @@ CFBundleVersion - 490 + 493 ITSAppUsesNonExemptEncryption LSApplicationCategoryType diff --git a/packages/hmssdk_flutter/ios/Classes/Models/HMSWhiteboardExtension.swift b/packages/hmssdk_flutter/ios/Classes/Models/HMSWhiteboardExtension.swift index 57b08c2d7..692235a21 100644 --- a/packages/hmssdk_flutter/ios/Classes/Models/HMSWhiteboardExtension.swift +++ b/packages/hmssdk_flutter/ios/Classes/Models/HMSWhiteboardExtension.swift @@ -10,7 +10,7 @@ import HMSSDK class HMSWhiteboardExtension{ - static func toDictionary(hmsWhiteboard: HMSWhiteboard?) -> [String: Any?]?{ + static func toDictionary(hmsWhiteboard: HMSWhiteboard?,hmsSDK: HMSSDK?) -> [String: Any?]?{ guard let whiteboard = hmsWhiteboard else{ return nil @@ -25,7 +25,20 @@ class HMSWhiteboardExtension{ } args["title"] = hmsWhiteboard?.title args["url"] = hmsWhiteboard?.url?.absoluteString + args["is_owner"] = hmsWhiteboard?.owner?.customerUserID == hmsSDK?.localPeer?.customerUserID + args["state"] = getStateFromString(state: hmsWhiteboard?.state) return args } + + private static func getStateFromString(state: HMSWhiteboard.WhiteboardState?) -> String{ + switch(state){ + case .started: + return "started" + case .stopped: + return "stopped" + default: + return "stopped" + } + } } diff --git a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift index 215c38a62..c889af512 100644 --- a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift +++ b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift @@ -495,14 +495,14 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene case .started: let args = [ "event_name": "on_whiteboard_start", - "data": HMSWhiteboardExtension.toDictionary(hmsWhiteboard: hmsWhiteboard) + "data": HMSWhiteboardExtension.toDictionary(hmsWhiteboard: hmsWhiteboard, hmsSDK: hmsSDK) ] self.whiteboardEventSink?(args) break case .stopped: let args = [ "event_name": "on_whiteboard_stop", - "data": HMSWhiteboardExtension.toDictionary(hmsWhiteboard: hmsWhiteboard) + "data": HMSWhiteboardExtension.toDictionary(hmsWhiteboard: hmsWhiteboard, hmsSDK: hmsSDK) ] self.whiteboardEventSink?(args) break diff --git a/packages/hmssdk_flutter/lib/assets/sdk-versions.json b/packages/hmssdk_flutter/lib/assets/sdk-versions.json index dac2d7a3d..b84919fd8 100644 --- a/packages/hmssdk_flutter/lib/assets/sdk-versions.json +++ b/packages/hmssdk_flutter/lib/assets/sdk-versions.json @@ -1,8 +1,8 @@ { - "flutter": "1.10.1", + "flutter": "1.10.2", "ios": "1.10.0", "iOSBroadcastExtension": "0.0.9", "iOSHLSPlayerSDK": "0.0.2", "iOSNoiseCancellationModels": "1.0.0", - "android": "2.9.55" + "android": "2.9.56" } diff --git a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart index f53c2bbcf..11fac1b6f 100644 --- a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart +++ b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart @@ -26,6 +26,7 @@ export 'src/enum/hms_poll_enum.dart'; export 'src/enum/hms_peer_type.dart'; export 'src/enum/hms_hls_playlist_type.dart'; export 'src/enum/hms_whiteboard_listener_method.dart'; +export 'src/enum/hms_whiteboard_state.dart'; //EXCEPTIONS export 'src/exceptions/hms_exception.dart'; diff --git a/packages/hmssdk_flutter/lib/src/enum/hms_whiteboard_state.dart b/packages/hmssdk_flutter/lib/src/enum/hms_whiteboard_state.dart new file mode 100644 index 000000000..fa12ad21e --- /dev/null +++ b/packages/hmssdk_flutter/lib/src/enum/hms_whiteboard_state.dart @@ -0,0 +1,15 @@ +///[HMSWhiteboardState] enum is used to define the state of the whiteboard +enum HMSWhiteboardState { started, stopped } + +extension HMSWhiteboardStateValues on HMSWhiteboardState { + static HMSWhiteboardState getWhiteboardStateFromName(String name) { + switch (name) { + case "started": + return HMSWhiteboardState.started; + case "stopped": + return HMSWhiteboardState.stopped; + default: + return HMSWhiteboardState.stopped; + } + } +} diff --git a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart index 95d253cde..6c6cf6fb4 100644 --- a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart +++ b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart @@ -1,7 +1,15 @@ +// Project imports import 'package:hmssdk_flutter/hmssdk_flutter.dart'; import 'package:hmssdk_flutter/src/service/platform_service.dart'; +///[HMSWhiteboardController] class contains methods to control the Whiteboard class HMSWhiteboardController { + /// Starts the Whiteboard with the specified [title]. + /// **parameters**: + /// + /// **title** - title of the whiteboard + /// + /// Refer [Start Whiteboard](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard#start-whiteboard) static Future start({required String title}) async { var result = await PlatformService.invokeMethod( PlatformMethod.startWhiteboard, @@ -14,6 +22,9 @@ class HMSWhiteboardController { } } + /// Stops the Whiteboard. + /// + /// Refer [Stop Whiteboard](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard#stop-whiteboard) static Future stop() async { var result = await PlatformService.invokeMethod(PlatformMethod.stopWhiteboard); @@ -25,11 +36,21 @@ class HMSWhiteboardController { } } + /// Adds an [HMSWhiteboardUpdateListener] to listen for Whiteboard updates. + /// + /// **parameters**: + /// + /// **listener** - whiteboard update listener to be attached + /// + /// Refer [Whiteboard Update Listener](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard#how-to-display-whiteboard) static void addHMSWhiteboardUpdateListener( {required HMSWhiteboardUpdateListener listener}) { PlatformService.addWhiteboardUpdateListener(listener); } + /// Removes an [HMSWhiteboardUpdateListener] that was previously added. + /// + /// Refer [Whiteboard Update Listener](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard#how-to-display-whiteboard) static void removeHMSWhiteboardUpdateListener() { PlatformService.removeWhiteboardUpdateListener(); } diff --git a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_model.dart b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_model.dart index da32f984a..94cdc6269 100644 --- a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_model.dart +++ b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_model.dart @@ -1,4 +1,5 @@ //Project imports +import 'package:hmssdk_flutter/src/enum/hms_whiteboard_state.dart'; import 'package:hmssdk_flutter/src/model/hms_peer.dart'; ///[HMSWhiteboardModel] is a class which includes the properties of a whiteboard @@ -15,13 +16,28 @@ class HMSWhiteboardModel { ///[url] is the url of the whiteboard which can be used to display whiteboard final String? url; - HMSWhiteboardModel({required this.id, this.owner, this.title, this.url}); + ///[isOwner] is a boolean which tells if the current user is the owner of the whiteboard + final bool? isOwner; + + ///[state] is an enum of type [WhiteboardState] which tells the state of the whiteboard + final HMSWhiteboardState state; + + HMSWhiteboardModel( + {required this.id, + this.owner, + this.title, + this.url, + this.isOwner, + required this.state}); factory HMSWhiteboardModel.fromMap(Map map) { return HMSWhiteboardModel( id: map['id'], owner: map['owner'] != null ? HMSPeer.fromMap(map['owner']) : null, title: map['title'], - url: map['url']); + url: map['url'], + isOwner: map['is_owner'], + state: + HMSWhiteboardStateValues.getWhiteboardStateFromName(map['state'])); } } diff --git a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_permission.dart b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_permission.dart index 7fde01ac8..757b488c0 100644 --- a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_permission.dart +++ b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_permission.dart @@ -1,6 +1,12 @@ +///[HMSWhiteboardPermission] is a class that implements the permissions of a user in a whiteboard session. class HMSWhiteboardPermission { + ///[admin] is a boolean which tells if the user has admin permissions final bool admin; + + ///[write] is a boolean which tells if the user has permission to write/edit the whiteboard final bool write; + + ///[read] is a boolean which tells if the user has permission to read the whiteboard final bool read; const HMSWhiteboardPermission( diff --git a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_update_listener.dart b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_update_listener.dart index 00884ee68..764f3e45f 100644 --- a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_update_listener.dart +++ b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_update_listener.dart @@ -1,7 +1,13 @@ // Project imports import 'package:hmssdk_flutter/src/model/whiteboard/hms_whiteboard_model.dart'; +///[HMSWhiteboardUpdateListener] is a listener interface which listens to the updates of the whiteboard +/// +///Implement this listener in your class to listen to the updates of the whiteboard abstract class HMSWhiteboardUpdateListener { + ///[onWhiteboardStart] is called when the whiteboard is started void onWhiteboardStart({required HMSWhiteboardModel hmsWhiteboardModel}); + + ///[onWhiteboardStop] is called when the whiteboard is stopped void onWhiteboardStop({required HMSWhiteboardModel hmsWhiteboardModel}); } diff --git a/packages/hmssdk_flutter/pubspec.lock b/packages/hmssdk_flutter/pubspec.lock index bfac3fa40..2932c9c3b 100644 --- a/packages/hmssdk_flutter/pubspec.lock +++ b/packages/hmssdk_flutter/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" fake_async: dependency: transitive description: @@ -59,30 +59,6 @@ packages: description: flutter source: sdk version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" lints: dependency: "direct dev" description: @@ -95,34 +71,34 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.9.1" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" sky_engine: dependency: transitive description: flutter @@ -140,18 +116,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -172,10 +148,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" vector_math: dependency: transitive description: @@ -184,14 +160,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - vm_service: + web: dependency: transitive description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "0.1.4-beta" sdks: - dart: ">=3.2.0-0 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=2.10.0" From 25672ce326c3bebbfc9801b780c78b001da74fdd Mon Sep 17 00:00:00 2001 From: Decoder07 Date: Wed, 15 May 2024 14:03:27 +0530 Subject: [PATCH 10/15] Added missing line --- .../kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt | 2 +- .../live/hms/hmssdk_flutter/methods/HMSWhiteboardAction.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt index 1632f8b61..61e448834 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSWhiteboardExtension.kt @@ -32,4 +32,4 @@ class HMSWhiteboardExtension { } } } -} \ No newline at end of file +} diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSWhiteboardAction.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSWhiteboardAction.kt index 53e3a3917..9ba309dd9 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSWhiteboardAction.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSWhiteboardAction.kt @@ -32,4 +32,4 @@ class HMSWhiteboardAction { hmssdk.getHmsInteractivityCenter().stopWhiteboard(HMSCommonAction.getActionListener(result)) } } -} \ No newline at end of file +} From 8ac9948174127be991c416c13c19e8dbbdd09e5d Mon Sep 17 00:00:00 2001 From: Decoder07 Date: Wed, 15 May 2024 14:16:07 +0530 Subject: [PATCH 11/15] Added EOFL --- .../main/kotlin/live/hms/hmssdk_flutter/HMSHLSLayerExtension.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSLayerExtension.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSLayerExtension.kt index 0385bf5dd..16fbaefbe 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSLayerExtension.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSLayerExtension.kt @@ -21,4 +21,4 @@ class HMSHLSLayerExtension { return map } } -} \ No newline at end of file +} From ef4f8173779e66258f3172986f8ae364d5118ac0 Mon Sep 17 00:00:00 2001 From: Decoder07 Date: Wed, 15 May 2024 17:00:47 +0530 Subject: [PATCH 12/15] Updated docs link --- packages/hmssdk_flutter/CHANGELOG.md | 2 +- .../src/model/whiteboard/hms_whiteboard_controller.dart | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/hmssdk_flutter/CHANGELOG.md b/packages/hmssdk_flutter/CHANGELOG.md index 34000b377..37aba890b 100644 --- a/packages/hmssdk_flutter/CHANGELOG.md +++ b/packages/hmssdk_flutter/CHANGELOG.md @@ -16,7 +16,7 @@ - Introducing Whiteboard support in HMSSDK - HMSSDK now provides support for Whiteboard. You can now start/stop a whiteboard using `HMSWhiteboardController` methods. HMSSDK provides also provides callbacks for whiteboard start/stop events. Learn more about it [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard) + HMSSDK now provides support for Whiteboard. You can now start/stop a whiteboard using `HMSWhiteboardController` methods. HMSSDK provides also provides callbacks for whiteboard start/stop events. Learn more about it [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/extend-capabilities/whiteboard) - HLS Layer methods diff --git a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart index 6c6cf6fb4..416bed19b 100644 --- a/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart +++ b/packages/hmssdk_flutter/lib/src/model/whiteboard/hms_whiteboard_controller.dart @@ -9,7 +9,7 @@ class HMSWhiteboardController { /// /// **title** - title of the whiteboard /// - /// Refer [Start Whiteboard](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard#start-whiteboard) + /// Refer [Start Whiteboard](https://www.100ms.live/docs/flutter/v2/how-to-guides/extend-capabilities/whiteboard#start-whiteboard) static Future start({required String title}) async { var result = await PlatformService.invokeMethod( PlatformMethod.startWhiteboard, @@ -24,7 +24,7 @@ class HMSWhiteboardController { /// Stops the Whiteboard. /// - /// Refer [Stop Whiteboard](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard#stop-whiteboard) + /// Refer [Stop Whiteboard](https://www.100ms.live/docs/flutter/v2/how-to-guides/extend-capabilities/whiteboard#stop-whiteboard) static Future stop() async { var result = await PlatformService.invokeMethod(PlatformMethod.stopWhiteboard); @@ -42,7 +42,7 @@ class HMSWhiteboardController { /// /// **listener** - whiteboard update listener to be attached /// - /// Refer [Whiteboard Update Listener](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard#how-to-display-whiteboard) + /// Refer [Whiteboard Update Listener](https://www.100ms.live/docs/flutter/v2/how-to-guides/extend-capabilities/whiteboard#how-to-display-whiteboard) static void addHMSWhiteboardUpdateListener( {required HMSWhiteboardUpdateListener listener}) { PlatformService.addWhiteboardUpdateListener(listener); @@ -50,7 +50,7 @@ class HMSWhiteboardController { /// Removes an [HMSWhiteboardUpdateListener] that was previously added. /// - /// Refer [Whiteboard Update Listener](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/whiteboard#how-to-display-whiteboard) + /// Refer [Whiteboard Update Listener](https://www.100ms.live/docs/flutter/v2/how-to-guides/extend-capabilities/whiteboard#how-to-display-whiteboard) static void removeHMSWhiteboardUpdateListener() { PlatformService.removeWhiteboardUpdateListener(); } From fe64168c849f009ef9bf7a0ca678cbba03d05165 Mon Sep 17 00:00:00 2001 From: Decoder07 Date: Wed, 15 May 2024 17:04:10 +0530 Subject: [PATCH 13/15] Updated hmssdk_flutter to 1.10.2 --- packages/hms_room_kit/example/pubspec.lock | 7 ++++--- packages/hms_room_kit/pubspec.lock | 7 ++++--- packages/hms_room_kit/pubspec.yaml | 3 +-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/hms_room_kit/example/pubspec.lock b/packages/hms_room_kit/example/pubspec.lock index 9570935fd..64c74229c 100644 --- a/packages/hms_room_kit/example/pubspec.lock +++ b/packages/hms_room_kit/example/pubspec.lock @@ -210,9 +210,10 @@ packages: hmssdk_flutter: dependency: transitive description: - path: "../../hmssdk_flutter" - relative: true - source: path + name: hmssdk_flutter + sha256: b3f1438c5146afe0399935d78820357bf548b0e3ea36f9355878670ccc2aca6e + url: "https://pub.dev" + source: hosted version: "1.10.2" http: dependency: transitive diff --git a/packages/hms_room_kit/pubspec.lock b/packages/hms_room_kit/pubspec.lock index d776a505b..c2a23c807 100644 --- a/packages/hms_room_kit/pubspec.lock +++ b/packages/hms_room_kit/pubspec.lock @@ -187,9 +187,10 @@ packages: hmssdk_flutter: dependency: "direct main" description: - path: "../hmssdk_flutter" - relative: true - source: path + name: hmssdk_flutter + sha256: b3f1438c5146afe0399935d78820357bf548b0e3ea36f9355878670ccc2aca6e + url: "https://pub.dev" + source: hosted version: "1.10.2" http: dependency: transitive diff --git a/packages/hms_room_kit/pubspec.yaml b/packages/hms_room_kit/pubspec.yaml index af7e78f24..35b4d7c9d 100644 --- a/packages/hms_room_kit/pubspec.yaml +++ b/packages/hms_room_kit/pubspec.yaml @@ -14,8 +14,7 @@ dependencies: flutter: sdk: flutter - hmssdk_flutter: - path: ../hmssdk_flutter + hmssdk_flutter: 1.10.2 intl: ^0.18.0 permission_handler: ^11.0.0 provider: ^6.0.5 From 8ec769c16ed0e492776de11e3f87cce0d2fe5477 Mon Sep 17 00:00:00 2001 From: Decoder07 Date: Wed, 15 May 2024 11:35:46 +0000 Subject: [PATCH 14/15] =?UTF-8?q?=F0=9F=A4=96=20Automated=20Format=20and?= =?UTF-8?q?=20Fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/hmssdk_flutter/example/pubspec.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/hmssdk_flutter/example/pubspec.lock b/packages/hmssdk_flutter/example/pubspec.lock index ac8f356f1..3cb0fe0c9 100644 --- a/packages/hmssdk_flutter/example/pubspec.lock +++ b/packages/hmssdk_flutter/example/pubspec.lock @@ -306,9 +306,10 @@ packages: hmssdk_flutter: dependency: transitive description: - path: ".." - relative: true - source: path + name: hmssdk_flutter + sha256: b3f1438c5146afe0399935d78820357bf548b0e3ea36f9355878670ccc2aca6e + url: "https://pub.dev" + source: hosted version: "1.10.2" http: dependency: transitive From d8d3093b5bc7f52143e4f388d1cf4f842ec71579 Mon Sep 17 00:00:00 2001 From: Decoder07 Date: Wed, 15 May 2024 17:16:30 +0530 Subject: [PATCH 15/15] Fixed lint errors --- .../hms_room_kit/lib/src/preview/preview_page.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/hms_room_kit/lib/src/preview/preview_page.dart b/packages/hms_room_kit/lib/src/preview/preview_page.dart index 08531289b..f67e815b3 100644 --- a/packages/hms_room_kit/lib/src/preview/preview_page.dart +++ b/packages/hms_room_kit/lib/src/preview/preview_page.dart @@ -275,12 +275,12 @@ class _PreviewPageState extends State { nameController, width: width * 0.38, onPressed: () { - nameController.text - .trim() - .isEmpty - ? null - : _navigateToMeeting( - previewStore); + if (nameController.text + .trim() + .isNotEmpty) { + _navigateToMeeting( + previewStore); + } }, childWidget: PreviewJoinButton(