From 927f7ec80db12ab6a3f037670f8fc37d86f4cb3a Mon Sep 17 00:00:00 2001 From: Pushpam <93931528+Decoder07@users.noreply.github.com> Date: Thu, 29 Aug 2024 13:15:55 +0530 Subject: [PATCH 1/2] feat: added android methods for zoom support (#1811) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: added android methods for zoom support * 🤖 Automated Format and Fix * Resolved conflicts * 🤖 Automated Format and Fix * fixed isZoomSupported method on android * increased app version * Updated changelog * released sample app version 1.5.223 (523) 🍀 * 🤖 Automated Format and Fix * added debug mode flag in zoom controls * 🤖 Automated Format and Fix --------- Co-authored-by: Decoder07 --- .../local_peer_bottom_sheet.dart | 53 +++++++++- .../hms/hmssdk_flutter/HmssdkFlutterPlugin.kt | 2 +- .../methods/HMSCameraControlsAction.kt | 98 ++++++++++++++++++- .../example/ExampleAppChangelog.txt | 7 +- .../example/android/app/build.gradle | 4 +- .../hmssdk_flutter/example/ios/Podfile.lock | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../example/ios/Runner/Info.plist | 4 +- .../Actions/HMSCameraControlsAction.swift | 55 ++++++++++- .../Classes/SwiftHmssdkFlutterPlugin.swift | 2 +- .../lib/src/common/platform_methods.dart | 28 ++++++ .../lib/src/model/hms_camera_controls.dart | 66 +++++++++++++ 13 files changed, 308 insertions(+), 17 deletions(-) diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/local_peer_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/local_peer_bottom_sheet.dart index 3095335f3..e946f184f 100644 --- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/local_peer_bottom_sheet.dart +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/local_peer_bottom_sheet.dart @@ -4,6 +4,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:hms_room_kit/src/widgets/common_widgets/hms_cross_button.dart'; +import 'package:hmssdk_flutter/hmssdk_flutter.dart'; import 'package:provider/provider.dart'; ///Project imports @@ -51,7 +52,10 @@ class _LocalPeerBottomSheetState extends State { @override Widget build(BuildContext context) { return FractionallySizedBox( - heightFactor: widget.isInsetTile ? 0.26 : 0.2, + heightFactor: + (AppDebugConfig.isDebugMode && widget.meetingStore.isVideoOn) + ? (widget.isInsetTile ? 0.46 : 0.4) + : (widget.isInsetTile ? 0.26 : 0.2), child: Padding( padding: const EdgeInsets.only(top: 16.0, left: 24, right: 24), child: Column( @@ -228,6 +232,53 @@ class _LocalPeerBottomSheetState extends State { widget.meetingStore.peerTracks.length > 1 ? HMSThemeColors.onSurfaceHighEmphasis : HMSThemeColors.onSurfaceLowEmphasis)), + if (AppDebugConfig.isDebugMode && + widget.meetingStore.isVideoOn) + ListTile( + horizontalTitleGap: 2, + onTap: () async { + Navigator.pop(context); + bool isZoomSupported = + await HMSCameraControls.isZoomSupported(); + if (isZoomSupported) { + HMSCameraControls.setZoom(zoomValue: 2); + } + }, + contentPadding: EdgeInsets.zero, + leading: SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/maximize.svg", + semanticsLabel: "fl_local_pin_tile", + height: 20, + width: 20, + colorFilter: ColorFilter.mode( + HMSThemeColors.onSurfaceHighEmphasis, + BlendMode.srcIn), + ), + title: HMSSubheadingText( + text: "Zoom In (2x)", + textColor: HMSThemeColors.onSurfaceHighEmphasis)), + + if (AppDebugConfig.isDebugMode && + widget.meetingStore.isVideoOn) + ListTile( + horizontalTitleGap: 2, + onTap: () async { + Navigator.pop(context); + HMSCameraControls.resetZoom(); + }, + contentPadding: EdgeInsets.zero, + leading: SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/minimize.svg", + semanticsLabel: "fl_local_pin_tile", + height: 20, + width: 20, + colorFilter: ColorFilter.mode( + HMSThemeColors.onSurfaceHighEmphasis, + BlendMode.srcIn), + ), + title: HMSSubheadingText( + text: "Reset zoom", + textColor: HMSThemeColors.onSurfaceHighEmphasis)), ], ), ), 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 3d7cb5cdd..51c2dc636 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 @@ -255,7 +255,7 @@ class HmssdkFlutterPlugin : "capture_snapshot" -> { captureSnapshot(call, result) } - "is_tap_to_focus_supported", "capture_image_at_max_supported_resolution", "is_zoom_supported", "is_flash_supported", "toggle_flash" -> { + "is_tap_to_focus_supported", "capture_image_at_max_supported_resolution", "is_zoom_supported", "is_flash_supported", "toggle_flash", "set_zoom", "reset_zoom", "get_max_zoom", "get_min_zoom" -> { HMSCameraControlsAction.cameraControlsAction(call, result, hmssdk!!, activity.applicationContext) } "get_session_metadata_for_key", "set_session_metadata_for_key" -> { diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSCameraControlsAction.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSCameraControlsAction.kt index 7a1040118..d31f130ff 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSCameraControlsAction.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/methods/HMSCameraControlsAction.kt @@ -24,6 +24,10 @@ class HMSCameraControlsAction { "capture_image_at_max_supported_resolution" -> captureImageAtMaxSupportedResolution(call, result, hmssdk, context) "is_flash_supported" -> isFlashSupported(result, hmssdk) "toggle_flash" -> toggleFlash(result, hmssdk) + "set_zoom" -> setZoom(call, result, hmssdk) + "reset_zoom" -> resetZoom(result, hmssdk) + "get_max_zoom" -> getMaxZoom(result, hmssdk) + "get_min_zoom" -> getMinZoom(result, hmssdk) else -> { result.notImplemented() } @@ -54,7 +58,7 @@ class HMSCameraControlsAction { hmssdk.getLocalPeer()?.let { localPeer -> localPeer.videoTrack?.let { localVideoTrack -> localVideoTrack.getCameraControl()?.let { cameraControl -> - HMSResultExtension.toDictionary(true, cameraControl.isZoomSupported()) + result.success(HMSResultExtension.toDictionary(true, cameraControl.isZoomSupported())) return } } @@ -206,5 +210,97 @@ class HMSCameraControlsAction { return } } + + private fun setZoom( + call: MethodCall, + result: Result, + hmssdk: HMSSDK + ){ + val zoomValue = call.argument("zoom_value") + zoomValue?.let { _zoomValue -> + hmssdk.getLocalPeer()?.let { localPeer -> + localPeer.videoTrack?.let { localVideoTrack -> + localVideoTrack.getCameraControl()?.setZoom( + _zoomValue.toFloat() + ) + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("local video track is null"))) + return + } + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("local peer is null"))) + return + } + }?:run{ + HMSErrorLogger.returnArgumentsError("zoom value parameter is null in setZoom method") + return + } + } + + private fun resetZoom( + result: Result, + hmssdk: HMSSDK, + ){ + hmssdk.getLocalPeer()?.let { localPeer -> + localPeer.videoTrack?.let { localVideoTrack -> + localVideoTrack.getCameraControl()?.resetZoom() ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("cameraControl is null"))) + return + } + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("local video track is null"))) + return + } + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("local peer is null"))) + return + } + } + + private fun getMinZoom( + result: Result, + hmssdk: HMSSDK, + ){ + hmssdk.getLocalPeer()?.let { localPeer -> + localPeer.videoTrack?.let { localVideoTrack -> + localVideoTrack.getCameraControl()?.let { cameraControl -> + result.success(HMSResultExtension.toDictionary(true, cameraControl.getMinZoom())) + return + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("cameraControl is null"))) + return + } + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("local video track is null"))) + return + } + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("local peer is null"))) + return + } + } + + private fun getMaxZoom( + result: Result, + hmssdk: HMSSDK, + ){ + hmssdk.getLocalPeer()?.let { localPeer -> + localPeer.videoTrack?.let { localVideoTrack -> + localVideoTrack.getCameraControl()?.let { cameraControl -> + result.success(HMSResultExtension.toDictionary(true, cameraControl.getMaxZoom())) + return + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("cameraControl is null"))) + return + } + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("local video track is null"))) + return + } + } ?: run { + result.success(HMSResultExtension.toDictionary(false, HMSExceptionExtension.getError("local peer is null"))) + return + } + } } } diff --git a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt index 697559da5..f1a7ecf49 100644 --- a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt +++ b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt @@ -1,10 +1,7 @@ Board: https://app.devrev.ai/100ms/vistas/vista-250 -- Change Role on Prebuilt -https://app.devrev.ai/100ms/works/ISS-22877 - -- Update DateTime parsing with `convertDateFromEpoch` in SDK -https://app.devrev.ai/100ms/works/ISS-22778 +- Add support for zoom in camera controls +https://app.devrev.ai/100ms/works/ISS-23282 Room Kit: 1.1.6 Core SDK: 1.10.6 diff --git a/packages/hmssdk_flutter/example/android/app/build.gradle b/packages/hmssdk_flutter/example/android/app/build.gradle index cb01c87b0..17dd04245 100644 --- a/packages/hmssdk_flutter/example/android/app/build.gradle +++ b/packages/hmssdk_flutter/example/android/app/build.gradle @@ -40,8 +40,8 @@ android { applicationId "live.hms.flutter" minSdkVersion 21 targetSdkVersion 34 - versionCode 520 - versionName "1.5.220" + versionCode 523 + versionName "1.5.223" } signingConfigs { diff --git a/packages/hmssdk_flutter/example/ios/Podfile.lock b/packages/hmssdk_flutter/example/ios/Podfile.lock index 56ece5a0b..c7f975b7c 100644 --- a/packages/hmssdk_flutter/example/ios/Podfile.lock +++ b/packages/hmssdk_flutter/example/ios/Podfile.lock @@ -303,7 +303,7 @@ SPEC CHECKSUMS: FirebaseRemoteConfigInterop: 6efda51fb5e2f15b16585197e26eaa09574e8a4d FirebaseSessions: dbd14adac65ce996228652c1fc3a3f576bdf3ecc FirebaseSharedSwift: 20530f495084b8d840f78a100d8c5ee613375f6e - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_foreground_task: 21ef182ab0a29a3005cc72cd70e5f45cb7f7f817 GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a GoogleMLKit: 2bd0dc6253c4d4f227aad460f69215a504b2980e diff --git a/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/project.pbxproj index fc0c44fb7..37fb2667c 100644 --- a/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -248,7 +248,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1340; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = 100ms; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db2..5e31d3d34 100644 --- a/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.5.220 + 1.5.223 CFBundleSignature ???? CFBundleURLTypes @@ -48,7 +48,7 @@ CFBundleVersion - 520 + 523 ITSAppUsesNonExemptEncryption LSApplicationCategoryType diff --git a/packages/hmssdk_flutter/ios/Classes/Actions/HMSCameraControlsAction.swift b/packages/hmssdk_flutter/ios/Classes/Actions/HMSCameraControlsAction.swift index 3d8c2b185..e519c3e23 100644 --- a/packages/hmssdk_flutter/ios/Classes/Actions/HMSCameraControlsAction.swift +++ b/packages/hmssdk_flutter/ios/Classes/Actions/HMSCameraControlsAction.swift @@ -32,9 +32,15 @@ class HMSCameraControlsAction { case "toggle_flash": toggleFlash(result, hmsSDK) + + case "set_zoom": + setZoom(call, result, hmsSDK) + + case "reset_zoom": + resetZoom(result, hmsSDK) // these method calls return FlutterMethodNotImplemented to indicate that the requested functionality is not yet implemented. - case "is_tap_to_focus_supported", "is_zoom_supported": + case "is_tap_to_focus_supported", "is_zoom_supported", "get_max_zoom", "get_min_zoom": result(FlutterMethodNotImplemented) // If the method call does not match any of the above cases, also return FlutterMethodNotImplemented. @@ -170,4 +176,51 @@ class HMSCameraControlsAction { formatter.timeStyle = .medium return formatter.string(from: Date()) } + + static private func setZoom(_ call: FlutterMethodCall, _ result: @escaping FlutterResult, _ hmsSDK: HMSSDK?){ + guard let localPeer = hmsSDK?.localPeer else { + result(HMSResultExtension.toDictionary(false, HMSErrorExtension.getError("\(#function) An instance of Local Peer could not be found. Please check if a Room is joined."))) + return + } + + guard let localVideoTrack = localPeer.localVideoTrack() + else { + result(HMSResultExtension.toDictionary(false, HMSErrorExtension.getError("\(#function) Video Track of Local Peer could not be found. Please check if the Local Peer has permission to publish video & video is unmuted currently."))) + return + } + + let arguments = call.arguments as? [AnyHashable: Any] + + guard let zoomValue = arguments?["zoom_value"] as? CGFloat + else{ + HMSErrorLogger.returnArgumentsError("zoom value can't be empty") + return + } + + localVideoTrack.modifyCaptureDevice { device in + + guard let device = device else { return } + + device.videoZoomFactor = zoomValue + } + } + + static private func resetZoom(_ result: @escaping FlutterResult, _ hmsSDK: HMSSDK?){ + guard let localPeer = hmsSDK?.localPeer else { + result(HMSResultExtension.toDictionary(false, HMSErrorExtension.getError("\(#function) An instance of Local Peer could not be found. Please check if a Room is joined."))) + return + } + + guard let localVideoTrack = localPeer.localVideoTrack() + else { + result(HMSResultExtension.toDictionary(false, HMSErrorExtension.getError("\(#function) Video Track of Local Peer could not be found. Please check if the Local Peer has permission to publish video & video is unmuted currently."))) + return + } + + localVideoTrack.modifyCaptureDevice { device in + + guard let device = device else { return } + device.videoZoomFactor = 1.0 + } + } } diff --git a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift index 9d56521d1..9db792145 100644 --- a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift +++ b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift @@ -315,7 +315,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene // MARK: - Advanced Camera Controls - case "capture_image_at_max_supported_resolution", "is_tap_to_focus_supported", "is_zoom_supported", "is_flash_supported", "toggle_flash": + case "capture_image_at_max_supported_resolution", "is_tap_to_focus_supported", "is_zoom_supported", "is_flash_supported", "toggle_flash", "set_zoom", "reset_zoom", "get_max_zoom", "get_min_zoom": HMSCameraControlsAction.cameraControlsAction(call, result, hmsSDK) // MARK: - Session Store diff --git a/packages/hmssdk_flutter/lib/src/common/platform_methods.dart b/packages/hmssdk_flutter/lib/src/common/platform_methods.dart index 7cb9c51bf..d47cb6551 100644 --- a/packages/hmssdk_flutter/lib/src/common/platform_methods.dart +++ b/packages/hmssdk_flutter/lib/src/common/platform_methods.dart @@ -165,9 +165,17 @@ enum PlatformMethod { captureSnapshot, getAllLogs, getAuthTokenByRoomCode, + + ///Camera Controls captureImageAtMaxSupportedResolution, isFlashSupported, toggleFlash, + isZoomSupported, + setZoom, + resetZoom, + getMaxZoom, + getMinZoom, + getSessionMetadataForKey, setSessionMetadataForKey, addKeyChangeListener, @@ -494,6 +502,16 @@ extension PlatformMethodValues on PlatformMethod { return "is_flash_supported"; case PlatformMethod.toggleFlash: return "toggle_flash"; + case PlatformMethod.isZoomSupported: + return "is_zoom_supported"; + case PlatformMethod.setZoom: + return "set_zoom"; + case PlatformMethod.resetZoom: + return "reset_zoom"; + case PlatformMethod.getMaxZoom: + return "get_max_zoom"; + case PlatformMethod.getMinZoom: + return "get_min_zoom"; case PlatformMethod.getSessionMetadataForKey: return "get_session_metadata_for_key"; case PlatformMethod.setSessionMetadataForKey: @@ -881,6 +899,16 @@ extension PlatformMethodValues on PlatformMethod { return PlatformMethod.isFlashSupported; case "toggle_flash": return PlatformMethod.toggleFlash; + case "is_zoom_supported": + return PlatformMethod.isZoomSupported; + case "set_zoom": + return PlatformMethod.setZoom; + case "reset_zoom": + return PlatformMethod.resetZoom; + case "get_max_zoom": + return PlatformMethod.getMaxZoom; + case "get_min_zoom": + return PlatformMethod.getMinZoom; case "get_session_metadata_for_key": return PlatformMethod.getSessionMetadataForKey; case "set_session_metadata_for_key": diff --git a/packages/hmssdk_flutter/lib/src/model/hms_camera_controls.dart b/packages/hmssdk_flutter/lib/src/model/hms_camera_controls.dart index ed08cf467..c1c439ef7 100644 --- a/packages/hmssdk_flutter/lib/src/model/hms_camera_controls.dart +++ b/packages/hmssdk_flutter/lib/src/model/hms_camera_controls.dart @@ -1,3 +1,6 @@ +import 'dart:developer'; +import 'dart:io'; + import 'package:hmssdk_flutter/src/common/platform_methods.dart'; import 'package:hmssdk_flutter/src/exceptions/hms_exception.dart'; import 'package:hmssdk_flutter/src/service/platform_service.dart'; @@ -61,4 +64,67 @@ class HMSCameraControls { return HMSException.fromMap(result["data"]["error"]); } } + + static Future isZoomSupported() async { + if (Platform.isAndroid) { + var result = + await PlatformService.invokeMethod(PlatformMethod.isZoomSupported); + if (result["success"]) { + return result["data"]; + } else { + return false; + } + } else { + return true; + } + } + + static Future setZoom({required double zoomValue}) async { + var result = + await PlatformService.invokeMethod(PlatformMethod.setZoom, arguments: { + "zoom_value": zoomValue, + }); + if (result["success"]) { + return result["data"]; + } else { + return HMSException.fromMap(result["data"]["error"]); + } + } + + static Future resetZoom() async { + var result = await PlatformService.invokeMethod(PlatformMethod.resetZoom); + if (result["success"]) { + return result["data"]; + } else { + return HMSException.fromMap(result["data"]["error"]); + } + } + + static Future getMinZoom() async { + if (Platform.isAndroid) { + var result = + await PlatformService.invokeMethod(PlatformMethod.getMinZoom); + if (result["success"]) { + return result["data"]; + } else { + return HMSException.fromMap(result["data"]["error"]); + } + } else { + log("getMinZoom is only available on android"); + } + } + + static Future getMaxZoom() async { + if (Platform.isAndroid) { + var result = + await PlatformService.invokeMethod(PlatformMethod.getMaxZoom); + if (result["success"]) { + return result["data"]; + } else { + return HMSException.fromMap(result["data"]["error"]); + } + } else { + log("getMaxZoom is only available on android"); + } + } } From e08c00aa0160f732b1a2a3d925d4d3b7f7b1e3e8 Mon Sep 17 00:00:00 2001 From: Pushpam <93931528+Decoder07@users.noreply.github.com> Date: Thu, 29 Aug 2024 13:18:38 +0530 Subject: [PATCH 2/2] feat: Hand Raise sorting based on Time (#1812) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Hand Raise sorting based on Time * 🤖 Automated Format and Fix --------- Co-authored-by: Decoder07 --- .../lib/src/meeting/meeting_store.dart | 33 ++++++++++++ .../participants_bottom_sheet.dart | 50 +++++++++++-------- 2 files changed, 63 insertions(+), 20 deletions(-) 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 a3730dd64..bebe8531d 100644 --- a/packages/hms_room_kit/lib/src/meeting/meeting_store.dart +++ b/packages/hms_room_kit/lib/src/meeting/meeting_store.dart @@ -666,16 +666,45 @@ class MeetingStore extends ChangeNotifier void toggleLocalPeerHandRaise() { if (isRaisedHand) { _hmsSDKInteractor.lowerLocalPeerHand(hmsActionResultListener: this); + resetTimestampWhenHandDown(); } else { _hmsSDKInteractor.raiseLocalPeerHand(hmsActionResultListener: this); + setTimestampWhenHandRaise(); } } + void setTimestampWhenHandRaise() { + int currentTime = DateTime.now().millisecondsSinceEpoch; + log("Vkohli Setting timestamp for hand raise $currentTime"); + _hmsSDKInteractor.changeMetadata( + metadata: + "{\"isBRBOn\":false,\"prevRole\":\"$previousRole\",\"handRaisedAt\":${currentTime}}", + hmsActionResultListener: this); + } + + void resetTimestampWhenHandDown() { + _hmsSDKInteractor.changeMetadata( + metadata: "{\"isBRBOn\":false,\"prevRole\":\"$previousRole\"}", + hmsActionResultListener: this); + } + void lowerRemotePeerHand(HMSPeer forPeer) { _hmsSDKInteractor.lowerRemotePeerHand( forPeer: forPeer, hmsActionResultListener: this); } + int _getTimestampFromPeerMetadata(String? metadata) { + if (metadata == null) { + return 0; + } + try { + Map metadataMap = jsonDecode(metadata); + return metadataMap["handRaisedAt"]; + } catch (e) { + return 0; + } + } + bool isBRB = false; void changeMetadataBRB() { @@ -1604,6 +1633,10 @@ class MeetingStore extends ChangeNotifier (handDownPeer) => handDownPeer.peer.peerId == peer.peerId); participantsInMeetingMap[peer.role.name]?[index].updatePeer(peer); } + participantsInMeetingMap["Hand Raised"]?.sort((a, b) { + return _getTimestampFromPeerMetadata(a.peer.metadata) + .compareTo(_getTimestampFromPeerMetadata(b.peer.metadata)); + }); notifyListeners(); } else if (peerUpdate == HMSPeerUpdate.metadataChanged) { participantsInMeetingMap[peer.role.name]?[index].updatePeer(peer); diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/participants_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/participants_bottom_sheet.dart index 34cbf292d..a1ac8375a 100644 --- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/participants_bottom_sheet.dart +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/participants_bottom_sheet.dart @@ -69,6 +69,10 @@ class _ParticipantsBottomSheetState extends State { ); } + bool isHandRaisedRow(String role) { + return role == "Hand Raised"; + } + Widget _kebabMenu(HMSPeer peer) { final meetingStore = context.read(); PeerTrackNode? peerTrackNode; @@ -410,12 +414,13 @@ class _ParticipantsBottomSheetState extends State { .keys .elementAt(index); return Selector?>>( - selector: (_, meetingStore) => Tuple2( + Tuple3?, String>>( + selector: (_, meetingStore) => Tuple3( meetingStore .participantsInMeetingMap[role]?.length ?? 0, - meetingStore.participantsInMeetingMap[role]), + meetingStore.participantsInMeetingMap[role], + role), builder: (_, participantsPerRole, __) { return (participantsPerRole.item2?.isNotEmpty ?? false) @@ -458,7 +463,9 @@ class _ParticipantsBottomSheetState extends State { null ? 0 : (participantsPerRole.item1) * - 54, + (isHandRaisedRow(role) + ? 60 + : 54), child: Center( child: ListView.builder( physics: @@ -538,15 +545,18 @@ class _ParticipantsBottomSheetState extends State { isSIPPeer, __) { return isSIPPeer - ? CircleAvatar( - radius: 16, - backgroundColor: HMSThemeColors.surfaceBright, - child: SvgPicture.asset( - "packages/hms_room_kit/lib/src/assets/icons/sip_call.svg", - height: 12, - width: 12, - colorFilter: ColorFilter.mode(HMSThemeColors.onSurfaceHighEmphasis, BlendMode.srcIn), - )) + ? Padding( + padding: const EdgeInsets.only(right: 4.0), + child: CircleAvatar( + radius: 12, + backgroundColor: HMSThemeColors.surfaceDefault, + child: SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/sip_call.svg", + height: 12, + width: 12, + colorFilter: ColorFilter.mode(HMSThemeColors.onSurfaceHighEmphasis, BlendMode.srcIn), + )), + ) : const SizedBox(); }, selector: (_, participantsStore) => @@ -562,14 +572,14 @@ class _ParticipantsBottomSheetState extends State { builder: (_, participantData, __) { return participantData.item1 != -1 && participantData.item1 < 3 && participantData.item2 ? Padding( - padding: const EdgeInsets.only(right: 16.0), + padding: const EdgeInsets.only(right: 4.0), child: CircleAvatar( - radius: 16, + radius: 12, backgroundColor: HMSThemeColors.surfaceDefault, child: SvgPicture.asset( "packages/hms_room_kit/lib/src/assets/icons/network_${participantData.item1}.svg", - height: 16, - width: 16, + height: 12, + width: 12, ), ), ) @@ -588,12 +598,12 @@ class _ParticipantsBottomSheetState extends State { ? Padding( padding: const EdgeInsets.only(right: 16.0), child: CircleAvatar( - radius: 16, + radius: 12, backgroundColor: HMSThemeColors.surfaceDefault, child: SvgPicture.asset( "packages/hms_room_kit/lib/src/assets/icons/hand_outline.svg", - height: 16, - width: 16, + height: 12, + width: 12, colorFilter: ColorFilter.mode(HMSThemeColors.onSurfaceHighEmphasis, BlendMode.srcIn), ), ),