diff --git a/.java-version b/.java-version index 392ea27c7..8808b7e39 100644 --- a/.java-version +++ b/.java-version @@ -1 +1 @@ -openjdk64-17.0.11 +17.0.12 diff --git a/README.md b/README.md index b2e79d9e1..9087d386a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ [![Discord](https://img.shields.io/discord/843749923060711464?label=Join%20on%20Discord)](https://100ms.live/discord) [![Firebase](https://img.shields.io/badge/Download%20Android-Firebase-green)](https://appdistribution.firebase.dev/i/b623e5310929ab70) [![TestFlight](https://img.shields.io/badge/Download%20iOS-TestFlight-blue)](https://testflight.apple.com/join/Uhzebmut) -[![Activity](https://img.shields.io/github/commit-activity/m/100mslive/100ms-flutter.svg)](https://github.com/100mslive/100ms-flutter/projects?type=classic) [![Register](https://img.shields.io/badge/Contact-Know%20More-blue)](https://dashboard.100ms.live/register) # 100ms Flutter SDK 🎉 diff --git a/packages/hms_room_kit/CHANGELOG.md b/packages/hms_room_kit/CHANGELOG.md index d6bd02d05..743bd270e 100644 --- a/packages/hms_room_kit/CHANGELOG.md +++ b/packages/hms_room_kit/CHANGELOG.md @@ -6,6 +6,52 @@ | hmssdk_flutter | [![Pub Version](https://img.shields.io/pub/v/hmssdk_flutter)](https://pub.dev/packages/hmssdk_flutter) | | hms_video_plugin | [![Pub Version](https://img.shields.io/pub/v/hms_video_plugin)](https://pub.dev/packages/hms_video_plugin) | +# 1.10.6 - 2024-09-17 + +| Package | Version | +| ----------------------------| ------ | +| hms_room_kit | 1.1.6 | +| hmssdk_flutter | 1.10.6 | + +### Breaking Changes in hms_room_kit + +- Removed Noise Cancellation dependency from Prebuilt on Android + + Noise Cancellation dependency is removed from Prebuilt on Android. + Users will have to add the dependency manually in their Android project to use Noise Cancellation. + This change is made to reduce the size of the Prebuilt package. + Refer to the [Noise Cancellation](https://www.100ms.live/docs/flutter/v2/how-to-guides/extend-capabilities/noise-cancellation) documentation for more details. + + +### hmssdk_flutter + +- Added Camera Zoom Controls in `HMSCameraControls` + + Users can now control the camera zoom using the `HMSCameraControls` class. The `setZoom` method can be used to set the zoom level of the camera. + + Learn more about Camera Zoom Controls [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/configure-your-device/camera/camera-controls). + +### hms_room_kit + +- Added support to control Automatic Gain Control and Noise Suppresion in Prebuilt + + Prebuilt now supports toggling Automatic Gain Control (AGC) and Noise Suppresion for better audio quality. Users can enable or disable AGC and Noise Suppresion from the prebuilt interface. + +- Resolved an issue where the Prebuilt UI was not updating on performing End Session + +- Hand Raise sorting based on Time + + Hand Raise list is now sorted based on the time of raising the hand. Refer to the [Hand Raise](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/peer/large-room) documentation for more details. + +- Added support to perform Switch Role of any user on Prebuilt + + Users can now switch the role of any user, if they have necessary permissions, from the Prebuilt interface. Refer to the [Change Role](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/peer/change-role) documentation for more details. + +Uses Android SDK 2.9.67 & iOS SDK 1.16.1 + +**Full Changelog**: [1.10.5...1.10.6](https://github.com/100mslive/100ms-flutter/compare/1.10.5...1.10.6) + + ## 1.1.5 - 2024-07-25 | Package | Version | diff --git a/packages/hms_room_kit/README.md b/packages/hms_room_kit/README.md index 374ef29b2..329318aad 100644 --- a/packages/hms_room_kit/README.md +++ b/packages/hms_room_kit/README.md @@ -7,7 +7,6 @@ [![Discord](https://img.shields.io/discord/843749923060711464?label=Join%20on%20Discord)](https://100ms.live/discord) [![Firebase](https://img.shields.io/badge/Download%20Android-Firebase-green)](https://appdistribution.firebase.dev/i/b623e5310929ab70) [![TestFlight](https://img.shields.io/badge/Download%20iOS-TestFlight-blue)](https://testflight.apple.com/join/Uhzebmut) -[![Activity](https://img.shields.io/github/commit-activity/m/100mslive/100ms-flutter.svg)](https://github.com/100mslive/100ms-flutter/projects/1) [![Register](https://img.shields.io/badge/Contact-Know%20More-blue)](https://dashboard.100ms.live/register)

diff --git a/packages/hms_room_kit/example/ios/Podfile.lock b/packages/hms_room_kit/example/ios/Podfile.lock index 2e9a26455..0549a3594 100644 --- a/packages/hms_room_kit/example/ios/Podfile.lock +++ b/packages/hms_room_kit/example/ios/Podfile.lock @@ -5,21 +5,25 @@ PODS: - HMSHLSPlayerSDK (0.0.2): - HMSAnalyticsSDK (= 0.0.2) - HMSNoiseCancellationModels (1.0.0) - - HMSSDK (1.9.0): + - HMSSDK (1.16.1): - HMSAnalyticsSDK (= 0.0.2) - - HMSWebRTC (= 1.0.6168) - - hmssdk_flutter (1.10.1): + - HMSWebRTC (= 1.0.6171) + - hmssdk_flutter (1.10.6): - Flutter - HMSBroadcastExtensionSDK (= 0.0.9) - HMSHLSPlayerSDK (= 0.0.2) - HMSNoiseCancellationModels (= 1.0.0) - - HMSSDK (= 1.9.0) - - HMSWebRTC (1.0.6168) + - HMSSDK (= 1.16.1) + - HMSWebRTC (1.0.6171) + - image_picker_ios (0.0.1): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - permission_handler_apple (9.1.1): - Flutter + - pointer_interceptor_ios (0.0.1): + - Flutter - share_plus (0.0.1): - Flutter - shared_preferences_foundation (0.0.1): @@ -27,15 +31,20 @@ PODS: - FlutterMacOS - url_launcher_ios (0.0.1): - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter DEPENDENCIES: - Flutter (from `Flutter`) - hmssdk_flutter (from `.symlinks/plugins/hmssdk_flutter/ios`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/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: @@ -51,31 +60,40 @@ EXTERNAL SOURCES: :path: Flutter hmssdk_flutter: :path: ".symlinks/plugins/hmssdk_flutter/ios" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" path_provider_foundation: :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: - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 HMSAnalyticsSDK: 4d2a88a729b1eb42f3d25f217c28937ec318a5b7 HMSBroadcastExtensionSDK: d80fe325f6c928bd8e5176290b5a4b7ae15d6fbb HMSHLSPlayerSDK: 6a54ad4d12f3dc2270d1ecd24019d71282a4f6a3 HMSNoiseCancellationModels: a3bda1405a16015632f4bcabd46ce48f35103b02 - HMSSDK: 96bdafc1c610aabfecd1155ad7e3c1bc45b3a6cb - hmssdk_flutter: c2ad70779ed9355577afbbe1047fb20f862820ac - HMSWebRTC: a302f0d6c94f7bee94f3265adb7bb1c6569e7ee5 + HMSSDK: 31e779fbf9c95335d88475a7f9f42fb077692e30 + hmssdk_flutter: da118bf9558b0556b609cdc14540dca5514291ac + HMSWebRTC: f6f4f02a665fda6d9d8a5b223272045c3d9486fb + image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425 path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 + pointer_interceptor_ios: 9280618c0b2eeb80081a343924aa8ad756c21375 share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 + webview_flutter_wkwebview: 4f3e50f7273d31e5500066ed267e3ae4309c5ae4 PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b diff --git a/packages/hms_room_kit/example/pubspec.lock b/packages/hms_room_kit/example/pubspec.lock index c62245892..ab3e10d6e 100644 --- a/packages/hms_room_kit/example/pubspec.lock +++ b/packages/hms_room_kit/example/pubspec.lock @@ -238,15 +238,15 @@ packages: path: ".." relative: true source: path - version: "1.1.5" + version: "1.1.6" hmssdk_flutter: dependency: transitive description: name: hmssdk_flutter - sha256: "2da8500708d8a8ebfa3d3ffb2f1deafd0ff23828dfaff6fdd1b4367da6337cf0" + sha256: "0097739f0005593738021d8c3d56179aee3ae46fa704a0d0be419b4ece4c350d" url: "https://pub.dev" source: hosted - version: "1.10.5" + version: "1.10.6" http: dependency: transitive description: diff --git a/packages/hms_room_kit/example/pubspec.yaml b/packages/hms_room_kit/example/pubspec.yaml index 0752a727f..b765a8078 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.5 +version: 1.1.6 environment: sdk: ">=3.0.0 <4.0.0" diff --git a/packages/hms_room_kit/lib/src/assets/icons/peer_settings.svg b/packages/hms_room_kit/lib/src/assets/icons/peer_settings.svg new file mode 100644 index 000000000..a0215f427 --- /dev/null +++ b/packages/hms_room_kit/lib/src/assets/icons/peer_settings.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/hms_room_kit/lib/src/common/utility_functions.dart b/packages/hms_room_kit/lib/src/common/utility_functions.dart index 5fe8a4657..88f8699c0 100644 --- a/packages/hms_room_kit/lib/src/common/utility_functions.dart +++ b/packages/hms_room_kit/lib/src/common/utility_functions.dart @@ -396,6 +396,8 @@ class Utilities { required bool joinWithMutedAudio, required bool isSoftwareDecoderDisabled, required bool isNoiseCancellationEnabled, + required bool isAutomaticGainControlEnabled, + required bool isNoiseSuppressionEnabled, HMSAudioMode? audioMode, }) { return HMSTrackSetting( @@ -414,7 +416,9 @@ class Utilities { ? HMSTrackInitState.MUTED : HMSTrackInitState.UNMUTED, audioMode: audioMode, - enableNoiseCancellation: isNoiseCancellationEnabled), + enableNoiseCancellation: isNoiseCancellationEnabled, + enableAutomaticGainControl: isAutomaticGainControlEnabled, + enableNoiseSupression: isNoiseSuppressionEnabled), videoTrackSetting: HMSVideoTrackSetting( trackInitialState: joinWithMutedVideo ? HMSTrackInitState.MUTED diff --git a/packages/hms_room_kit/lib/src/hms_prebuilt_options.dart b/packages/hms_room_kit/lib/src/hms_prebuilt_options.dart index 25399aa1a..fb582c750 100644 --- a/packages/hms_room_kit/lib/src/hms_prebuilt_options.dart +++ b/packages/hms_room_kit/lib/src/hms_prebuilt_options.dart @@ -30,9 +30,17 @@ class HMSPrebuiltOptions { final HMSIOSScreenshareConfig? iOSScreenshareConfig; ///To enable noise cancellation in prebuilt. - ///Default value is true + ///Default value is false final bool enableNoiseCancellation; + ///To enable automatic gain control in prebuilt. + ///Default value is false + final bool isAutomaticGainControlEnabled; + + ///To enable noise suppression in prebuilt. + ///Default value is false + final bool isNoiseSuppressionEnabled; + ///[HMSPrebuiltOptions] is a class that is used to pass the options to the prebuilt HMSPrebuiltOptions( {this.userName, @@ -40,5 +48,7 @@ class HMSPrebuiltOptions { this.endPoints, this.debugInfo = false, this.iOSScreenshareConfig, - this.enableNoiseCancellation = false}); + this.enableNoiseCancellation = false, + this.isAutomaticGainControlEnabled = false, + this.isNoiseSuppressionEnabled = false}); } diff --git a/packages/hms_room_kit/lib/src/hmssdk_interactor.dart b/packages/hms_room_kit/lib/src/hmssdk_interactor.dart index 785557e4b..5cae98cf9 100644 --- a/packages/hms_room_kit/lib/src/hmssdk_interactor.dart +++ b/packages/hms_room_kit/lib/src/hmssdk_interactor.dart @@ -38,7 +38,9 @@ class HMSSDKInteractor { bool isAudioMixerDisabled = true, HMSAudioMode audioMode = HMSAudioMode.VOICE, bool isPrebuilt = false, - bool isNoiseCancellationEnabled = false}) { + bool isNoiseCancellationEnabled = false, + bool isAutomaticGainControlEnabled = false, + bool isNoiseSuppressionEnabled = false}) { HMSLogSettings hmsLogSettings = HMSLogSettings( maxDirSizeInBytes: 1000000, isLogStorageEnabled: true, @@ -50,7 +52,9 @@ class HMSSDKInteractor { joinWithMutedAudio: joinWithMutedAudio, isSoftwareDecoderDisabled: isSoftwareDecoderDisabled, audioMode: audioMode, - isNoiseCancellationEnabled: isNoiseCancellationEnabled); + isNoiseCancellationEnabled: isNoiseCancellationEnabled, + isAutomaticGainControlEnabled: isAutomaticGainControlEnabled, + isNoiseSuppressionEnabled: isNoiseSuppressionEnabled); hmsSDK = HMSSDK( iOSScreenshareConfig: iOSScreenshareConfig, 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..010fe6ac1 100644 --- a/packages/hms_room_kit/lib/src/meeting/meeting_store.dart +++ b/packages/hms_room_kit/lib/src/meeting/meeting_store.dart @@ -380,7 +380,6 @@ class MeetingStore extends ChangeNotifier void endRoom(bool lock, String? reason) { isEndRoomCalled = true; _hmsSDKInteractor.endRoom(lock, reason ?? "", this); - _hmsSDKInteractor.destroy(); } void removePeerFromRoom(HMSPeer peer) { @@ -666,16 +665,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; + + _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 +1632,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/meeting_screen_controller.dart b/packages/hms_room_kit/lib/src/meeting_screen_controller.dart index 5dc70ce02..3118b518c 100644 --- a/packages/hms_room_kit/lib/src/meeting_screen_controller.dart +++ b/packages/hms_room_kit/lib/src/meeting_screen_controller.dart @@ -92,12 +92,7 @@ class _MeetingScreenControllerState extends State { _meetingStore = MeetingStore(hmsSDKInteractor: widget.hmsSDKInteractor); _setInitValues(); _joinMeeting(); - - ///If the role is hlsStreaming we set the HLS Player store - if (HMSRoomLayout.roleLayoutData?.screens?.conferencing?.hlsLiveStreaming != - null) { - _setHLSPlayerStore(); - } + _setHLSPlayerStore(); } ///This function joins the room only if the name is not empty diff --git a/packages/hms_room_kit/lib/src/preview_meeting_flow.dart b/packages/hms_room_kit/lib/src/preview_meeting_flow.dart index 9391cc15e..86ccbcc9b 100644 --- a/packages/hms_room_kit/lib/src/preview_meeting_flow.dart +++ b/packages/hms_room_kit/lib/src/preview_meeting_flow.dart @@ -42,7 +42,9 @@ class _PreviewMeetingFlowState extends State { Widget build(BuildContext context) { return HMSRoomLayout.skipPreview ? MeetingScreenController( - user: widget.prebuiltOptions?.userId ?? "", + user: widget.prebuiltOptions?.userName ?? + widget.prebuiltOptions?.userId ?? + "", localPeerNetworkQuality: null, options: widget.prebuiltOptions, tokenData: widget.tokenData, diff --git a/packages/hms_room_kit/lib/src/screen_controller.dart b/packages/hms_room_kit/lib/src/screen_controller.dart index b073d8f54..f957bbe2e 100644 --- a/packages/hms_room_kit/lib/src/screen_controller.dart +++ b/packages/hms_room_kit/lib/src/screen_controller.dart @@ -147,6 +147,10 @@ class _ScreenControllerState extends State { isAudioMixerDisabled: AppDebugConfig.isAudioMixerDisabled, isNoiseCancellationEnabled: widget.options?.enableNoiseCancellation ?? false, + isAutomaticGainControlEnabled: + widget.options?.isAutomaticGainControlEnabled ?? false, + isNoiseSuppressionEnabled: + widget.options?.isNoiseSuppressionEnabled ?? false, isPrebuilt: true); await _hmsSDKInteractor.build(); diff --git a/packages/hms_room_kit/lib/src/service/app_debug_config.dart b/packages/hms_room_kit/lib/src/service/app_debug_config.dart index efcb776a5..3239a169c 100644 --- a/packages/hms_room_kit/lib/src/service/app_debug_config.dart +++ b/packages/hms_room_kit/lib/src/service/app_debug_config.dart @@ -6,7 +6,6 @@ class AppDebugConfig { Setting these values to defaults and can be toggled from the application This will not be shipped with the ui_kit package and only used for internal testing */ - static bool skipPreview = false; static bool mirrorCamera = true; static bool showStats = false; static bool isSoftwareDecoderDisabled = true; @@ -25,7 +24,6 @@ class AppDebugConfig { /// Resets the debug configuration to default values static void resetToDefault() { - skipPreview = false; mirrorCamera = true; showStats = false; isSoftwareDecoderDisabled = true; diff --git a/packages/hms_room_kit/lib/src/widgets/app_dialogs/change_role_option_dialog.dart b/packages/hms_room_kit/lib/src/widgets/app_dialogs/change_role_option_dialog.dart deleted file mode 100644 index 5fe15ce12..000000000 --- a/packages/hms_room_kit/lib/src/widgets/app_dialogs/change_role_option_dialog.dart +++ /dev/null @@ -1,211 +0,0 @@ -//Package imports -import 'package:dropdown_button2/dropdown_button2.dart'; -import 'package:flutter/material.dart'; -import 'package:collection/collection.dart'; - -//Project imports -import 'package:hmssdk_flutter/hmssdk_flutter.dart'; - -import 'package:hms_room_kit/src/common/app_color.dart'; -import 'package:hms_room_kit/src/common/utility_functions.dart'; -import 'package:hms_room_kit/src/widgets/common_widgets/hms_dropdown.dart'; -import 'package:hms_room_kit/src/widgets/common_widgets/hms_subtitle_text.dart'; -import 'package:hms_room_kit/src/widgets/common_widgets/hms_text_style.dart'; -import 'package:hms_room_kit/src/widgets/common_widgets/hms_title_text.dart'; - -class ChangeRoleOptionDialog extends StatefulWidget { - final String peerName; - final List roles; - final Function(HMSRole, bool) changeRole; - final bool force; - final HMSPeer peer; - const ChangeRoleOptionDialog({ - super.key, - required this.peerName, - required this.roles, - required this.changeRole, - required this.peer, - this.force = true, - }); - - @override - ChangeRoleOptionDialogState createState() => ChangeRoleOptionDialogState(); -} - -class ChangeRoleOptionDialogState extends State { - late bool askPermission; - HMSRole? valueChoose; - - void _updateDropDownValue(dynamic newValue) { - valueChoose = newValue; - } - - @override - void initState() { - super.initState(); - askPermission = !widget.force; - valueChoose = widget.roles[0]; - } - - @override - Widget build(BuildContext context) { - String message = "Change the role of ‘${widget.peerName}’ to"; - double width = MediaQuery.of(context).size.width; - return AlertDialog( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - actionsPadding: const EdgeInsets.only(left: 20, right: 20, bottom: 10), - backgroundColor: themeBottomSheetColor, - insetPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), - contentPadding: - const EdgeInsets.only(top: 20, bottom: 15, left: 24, right: 24), - title: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - HMSTitleText( - text: "Change Role", - fontSize: 20, - letterSpacing: 0.15, - textColor: themeDefaultColor, - ), - const SizedBox( - height: 8, - ), - HMSSubtitleText(text: message, textColor: themeSubHeadingColor), - ], - ), - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.only(left: 10, right: 5), - decoration: BoxDecoration( - color: themeSurfaceColor, - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: borderColor, style: BorderStyle.solid, width: 0.80), - ), - child: DropdownButtonHideUnderline( - child: HMSDropDown( - dropDownItems: [ - ...widget.roles - .sortedBy((element) => element.priority.toString()) - .map((role) => DropdownMenuItem( - value: role, - child: HMSTitleText( - text: role.name, - textColor: themeDefaultColor, - fontWeight: FontWeight.w400, - ), - )) - .toList(), - ], - iconStyleData: IconStyleData( - icon: const Icon(Icons.keyboard_arrow_down), - iconEnabledColor: themeDefaultColor, - ), - selectedValue: valueChoose, - updateSelectedValue: _updateDropDownValue)), - ), - const SizedBox( - height: 15, - ), - if (!widget.peer.isLocal) - Row( - children: [ - SizedBox( - width: 25, - height: 25, - child: Checkbox( - value: askPermission, - activeColor: Colors.blue, - onChanged: (bool? value) { - if (value != null) { - askPermission = value; - setState(() {}); - } - }), - ), - const SizedBox( - width: 10.5, - ), - SizedBox( - width: width * 0.5, - child: Text( - "Request permission from the user", - style: HMSTextStyle.setTextStyle( - color: themeDefaultColor, - fontSize: 14, - height: 20 / 14, - letterSpacing: 0.25, - ), - )), - ], - ), - ], - ), - actions: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ElevatedButton( - style: ButtonStyle( - shadowColor: MaterialStateProperty.all(themeSurfaceColor), - backgroundColor: - MaterialStateProperty.all(themeBottomSheetColor), - shape: MaterialStateProperty.all( - RoundedRectangleBorder( - side: const BorderSide( - width: 1, color: Color.fromRGBO(107, 125, 153, 1)), - borderRadius: BorderRadius.circular(8.0), - ))), - onPressed: () => Navigator.pop(context, false), - child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 12, horizontal: 10), - child: Text('Cancel', - style: HMSTextStyle.setTextStyle( - color: themeDefaultColor, - fontSize: 16, - fontWeight: FontWeight.w600, - letterSpacing: 0.50)), - )), - ElevatedButton( - style: ButtonStyle( - shadowColor: MaterialStateProperty.all(themeSurfaceColor), - backgroundColor: MaterialStateProperty.all(hmsdefaultColor), - shape: MaterialStateProperty.all( - RoundedRectangleBorder( - side: BorderSide(width: 1, color: hmsdefaultColor), - borderRadius: BorderRadius.circular(8.0), - ))), - onPressed: () => { - if (valueChoose == null) - { - Utilities.showToast("Please select a role"), - } - else - { - Navigator.pop(context), - widget.changeRole(valueChoose!, !askPermission) - } - }, - child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 12, horizontal: 10), - child: Text( - 'Change', - style: HMSTextStyle.setTextStyle( - color: themeDefaultColor, - fontSize: 16, - fontWeight: FontWeight.w600, - letterSpacing: 0.50), - ), - ), - ), - ], - ) - ], - ); - } -} diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/change_role_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/change_role_bottom_sheet.dart new file mode 100644 index 000000000..06b0df5f4 --- /dev/null +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/change_role_bottom_sheet.dart @@ -0,0 +1,144 @@ +library; + +///Dart imports +import 'dart:math' as Math; + +///Package imports +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; +import 'package:hmssdk_flutter/hmssdk_flutter.dart'; + +///Project imports +import 'package:hms_room_kit/src/widgets/common_widgets/hms_dropdown.dart'; +import 'package:hms_room_kit/hms_room_kit.dart'; +import 'package:hms_room_kit/src/widgets/common_widgets/hms_cross_button.dart'; + +///[ChangeRoleBottomSheet] is a bottom sheet that allows the user to change the role of a peer it contains a dropdown to select the new role for the peer +class ChangeRoleBottomSheet extends StatefulWidget { + final String peerName; + final List roles; + final Function(HMSRole, bool) changeRole; + final bool force; + final HMSPeer peer; + const ChangeRoleBottomSheet({ + super.key, + required this.peerName, + required this.roles, + required this.changeRole, + required this.peer, + this.force = true, + }); + + @override + ChangeRoleBottomSheetState createState() => ChangeRoleBottomSheetState(); +} + +class ChangeRoleBottomSheetState extends State { + HMSRole? roleSelected; + + void _updateDropDownValue(dynamic newValue) { + roleSelected = newValue; + setState(() {}); + } + + @override + void initState() { + super.initState(); + roleSelected = widget.roles[0]; + } + + @override + Widget build(BuildContext context) { + String message = + "Switch the role of '${widget.peerName.substring(0, Math.min(30, widget.peerName.length))}' from '${widget.peer.role.name.substring(0, Math.min(20, widget.peer.role.name.length))}' to "; + return FractionallySizedBox( + heightFactor: 0.3, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + HMSTitleText( + text: "Switch Role", + fontSize: 20, + letterSpacing: 0.15, + textColor: HMSThemeColors.onSecondaryHighEmphasis, + ), + HMSCrossButton() + ], + ), + HMSSubtitleText( + text: message, + textColor: HMSThemeColors.onSurfaceMediumEmphasis, + maxLines: 2, + ), + const SizedBox( + height: 24, + ), + DropdownButtonHideUnderline( + child: HMSDropDown( + dropDownItems: [ + ...widget.roles + .where((role) => ((role.name != widget.peer.role.name) && + (role.name != '__internal_recorder'))) + .sortedBy((element) => element.priority.toString()) + .map((role) => DropdownMenuItem( + value: role, + child: HMSTitleText( + text: role.name, + textColor: HMSThemeColors.onSurfaceHighEmphasis, + fontWeight: FontWeight.w400, + letterSpacing: 0.5, + ), + )) + .toList(), + ], + iconStyleData: IconStyleData( + icon: const Icon(Icons.keyboard_arrow_down), + iconEnabledColor: HMSThemeColors.onSurfaceHighEmphasis, + ), + selectedValue: roleSelected, + updateSelectedValue: _updateDropDownValue)), + const SizedBox( + height: 24, + ), + ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + roleSelected == null + ? HMSThemeColors.primaryDisabled + : HMSThemeColors.primaryDefault), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ))), + onPressed: () => { + Navigator.pop(context), + if (roleSelected != null) + {widget.changeRole(roleSelected!, true)} + }, + child: Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: Center( + child: HMSTitleText( + text: "Switch Role", + textColor: HMSThemeColors.onPrimaryHighEmphasis), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_utilities_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_utilities_bottom_sheet.dart index 2cec15a3e..e588f36a4 100644 --- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_utilities_bottom_sheet.dart +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_utilities_bottom_sheet.dart @@ -30,6 +30,7 @@ class ChatUtilitiesBottomSheet extends StatefulWidget { class _ChatUtilitiesBottomSheetState extends State { bool isPinned = false; bool isBlocked = false; + bool isLocalBlocked = false; @override initState() { @@ -39,14 +40,32 @@ class _ChatUtilitiesBottomSheetState extends State { (element) => element["id"] == widget.message.messageId) != -1; - isBlocked = context.read().blackListedUserIds.indexWhere( - (userId) => userId == widget.message.sender?.customerUserId) != - -1; + // Initial check for isBlocked + updateIsBlocked(); + + // Add listener to update isBlocked when blackListedUserIds changes + context.read().addListener(updateIsBlocked); + } + + void updateIsBlocked() { + setState(() { + isBlocked = context.read().blackListedUserIds.indexWhere( + (userId) => userId == widget.message.sender?.customerUserId) != + -1; + isLocalBlocked = context + .read() + .blackListedUserIds + .indexWhere((userId) => + userId == + context.read().localPeer?.customerUserId) != + -1; + }); } @override void deactivate() { context.read().removeBottomSheet(context); + context.read().removeListener(updateIsBlocked); super.deactivate(); } @@ -156,7 +175,8 @@ class _ChatUtilitiesBottomSheetState extends State { if ((HMSRoomLayout.chatData?.realTimeControls?.canBlockUser ?? false) && - !(widget.message.sender?.isLocal ?? true)) + !(widget.message.sender?.isLocal ?? true) && + !isLocalBlocked) ListTile( horizontalTitleGap: 2, onTap: () async { 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/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 df5b53833..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 @@ -14,6 +14,7 @@ import 'package:hmssdk_flutter/hmssdk_flutter.dart'; ///Project imports import 'package:hms_room_kit/hms_room_kit.dart'; +import 'package:hms_room_kit/src/widgets/bottom_sheets/change_role_bottom_sheet.dart'; import 'package:hms_room_kit/src/widgets/toasts/hms_toasts_type.dart'; import 'package:hms_room_kit/src/layout_api/hms_room_layout.dart'; import 'package:hms_room_kit/src/model/participant_store.dart'; @@ -68,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; @@ -177,6 +182,34 @@ class _ParticipantsBottomSheetState extends State { break; case 5: + ///This is called when someone clicks on switch Role + Navigator.pop(context); + showModalBottomSheet( + isScrollControlled: true, + backgroundColor: HMSThemeColors.surfaceDim, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16)), + ), + context: context, + builder: (ctx) => ChangeNotifierProvider.value( + value: meetingStore, + child: Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(ctx).viewInsets.bottom), + child: ChangeRoleBottomSheet( + peerName: peer.name, + roles: meetingStore.roles, + peer: peer, + changeRole: (newRole, isForceChange) => + meetingStore.changeRoleOfPeer( + peer: peer, + roleName: newRole, + forceChange: true)))), + ); + case 6: + ///This is called when someone clicks on remove Participant meetingStore.removePeerFromRoom(peer); break; @@ -299,9 +332,30 @@ class _ParticipantsBottomSheetState extends State { ), ]), ), - if (removePeerPermission) + if (changeRolePermission && meetingStore.roles.length > 1) PopupMenuItem( value: 5, + child: Row(children: [ + SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/peer_settings.svg", + colorFilter: ColorFilter.mode( + HMSThemeColors.onSurfaceHighEmphasis, + BlendMode.srcIn)), + const SizedBox( + width: 8, + ), + HMSTitleText( + text: "Switch Role", + textColor: HMSThemeColors.onSurfaceHighEmphasis, + fontSize: 14, + lineHeight: 20, + letterSpacing: 0.1, + ), + ]), + ), + if (removePeerPermission) + PopupMenuItem( + value: 6, child: Row(children: [ SvgPicture.asset( "packages/hms_room_kit/lib/src/assets/icons/peer_remove.svg", @@ -360,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) @@ -408,7 +463,9 @@ class _ParticipantsBottomSheetState extends State { null ? 0 : (participantsPerRole.item1) * - 54, + (isHandRaisedRow(role) + ? 60 + : 54), child: Center( child: ListView.builder( physics: @@ -488,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) => @@ -512,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, ), ), ) @@ -538,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), ), ), diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/remote_peer_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/remote_peer_bottom_sheet.dart index 30e5525cb..a2259d32e 100644 --- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/remote_peer_bottom_sheet.dart +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/remote_peer_bottom_sheet.dart @@ -8,6 +8,7 @@ import 'package:flutter_svg/flutter_svg.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'; +import 'package:hms_room_kit/src/widgets/bottom_sheets/change_role_bottom_sheet.dart'; import 'package:hms_room_kit/src/widgets/common_widgets/hms_cross_button.dart'; import 'package:hms_room_kit/src/widgets/common_widgets/hms_subheading_text.dart'; import 'package:hmssdk_flutter/hmssdk_flutter.dart'; @@ -220,6 +221,56 @@ class _RemotePeerBottomSheetState extends State { textColor: widget.peerTrackNode.track == null ? HMSThemeColors.onSurfaceLowEmphasis : HMSThemeColors.onSurfaceHighEmphasis)), + if ((widget.meetingStore.localPeer?.role.permissions + .changeRole ?? + false) && + (widget.meetingStore.roles.length > 1)) + ListTile( + horizontalTitleGap: 2, + onTap: () async { + Navigator.pop(context); + showModalBottomSheet( + isScrollControlled: true, + backgroundColor: HMSThemeColors.surfaceDim, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16)), + ), + context: context, + builder: (ctx) => ChangeNotifierProvider.value( + value: widget.meetingStore, + child: Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(ctx) + .viewInsets + .bottom), + child: ChangeRoleBottomSheet( + peerName: + widget.peerTrackNode.peer.name, + roles: widget.meetingStore.roles, + peer: widget.peerTrackNode.peer, + changeRole: (newRole, isForceChange) => + widget.meetingStore + .changeRoleOfPeer( + peer: widget + .peerTrackNode.peer, + roleName: newRole, + forceChange: + isForceChange)))), + ); + }, + contentPadding: EdgeInsets.zero, + leading: SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/peer_settings.svg", + semanticsLabel: "fl_change_role", + colorFilter: ColorFilter.mode( + HMSThemeColors.onSurfaceHighEmphasis, + BlendMode.srcIn), + ), + title: HMSSubheadingText( + text: "Switch Role", + textColor: HMSThemeColors.onSurfaceHighEmphasis)), // ListTile( // horizontalTitleGap: 2, // onTap: () async { diff --git a/packages/hms_room_kit/lib/src/widgets/common_widgets/hms_dropdown.dart b/packages/hms_room_kit/lib/src/widgets/common_widgets/hms_dropdown.dart index 41380e833..dfdd2b4d6 100644 --- a/packages/hms_room_kit/lib/src/widgets/common_widgets/hms_dropdown.dart +++ b/packages/hms_room_kit/lib/src/widgets/common_widgets/hms_dropdown.dart @@ -1,7 +1,14 @@ +library; + +///Package imports import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; -import 'package:hms_room_kit/src/common/app_color.dart'; +///Project imports +import 'package:hms_room_kit/hms_room_kit.dart'; + +///[HMSDropDown] is a dropdown that allows the user to select an item from a list of items +///It is wrapper around the [DropdownButton2] widget and uses 100ms default themes class HMSDropDown extends StatefulWidget { final Key? dropdownKey; final Widget? dropdownHint; @@ -14,19 +21,22 @@ class HMSDropDown extends StatefulWidget { final dynamic selectedValue; final Function(dynamic) updateSelectedValue; final bool isExpanded; - const HMSDropDown( - {super.key, - this.dropdownKey, - this.dropdownHint, - this.dropdownButton, - this.buttonStyleData, - this.dropdownStyleData, - this.menuItemStyleData, - required this.dropDownItems, - this.iconStyleData, - required this.selectedValue, - this.isExpanded = true, - required this.updateSelectedValue}); + final double dropdownWidth; + const HMSDropDown({ + super.key, + this.dropdownKey, + this.dropdownHint, + this.dropdownButton, + this.buttonStyleData, + this.dropdownStyleData, + this.menuItemStyleData, + required this.dropDownItems, + this.iconStyleData, + required this.selectedValue, + this.isExpanded = true, + this.dropdownWidth = 48, + required this.updateSelectedValue, + }); @override State createState() => _HMSDropDownState(); } @@ -42,7 +52,7 @@ class _HMSDropDownState extends State { @override Widget build(BuildContext context) { - final width = MediaQuery.of(context).size.width; + final width = MediaQuery.of(context).size.width - widget.dropdownWidth; return DropdownButton2( key: widget.dropdownKey, hint: widget.dropdownHint, @@ -58,25 +68,26 @@ class _HMSDropDownState extends State { customButton: widget.dropdownButton, dropdownStyleData: widget.dropdownStyleData == null ? DropdownStyleData( - width: width * 0.7, + width: width, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: themeSurfaceColor, - border: Border.all(color: borderColor)), - offset: const Offset(-10, -10), + borderRadius: BorderRadius.circular(8), + color: HMSThemeColors.surfaceDefault, + ), ) : widget.dropdownStyleData!, iconStyleData: widget.iconStyleData == null ? IconStyleData( icon: const Icon(Icons.keyboard_arrow_down), - iconEnabledColor: iconColor) + iconEnabledColor: HMSThemeColors.onSurfaceHighEmphasis) : widget.iconStyleData!, buttonStyleData: widget.buttonStyleData == null ? ButtonStyleData( - width: width * 0.7, + width: width, height: 48, + padding: EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: themeSurfaceColor, + color: HMSThemeColors.surfaceDefault, + borderRadius: BorderRadius.circular(8), ), ) : widget.buttonStyleData!, diff --git a/packages/hms_room_kit/pubspec.lock b/packages/hms_room_kit/pubspec.lock index df659cc15..f79153b9d 100644 --- a/packages/hms_room_kit/pubspec.lock +++ b/packages/hms_room_kit/pubspec.lock @@ -220,10 +220,10 @@ packages: dependency: "direct main" description: name: hmssdk_flutter - sha256: "2da8500708d8a8ebfa3d3ffb2f1deafd0ff23828dfaff6fdd1b4367da6337cf0" + sha256: "0097739f0005593738021d8c3d56179aee3ae46fa704a0d0be419b4ece4c350d" url: "https://pub.dev" source: hosted - version: "1.10.5" + version: "1.10.6" http: dependency: transitive description: diff --git a/packages/hms_room_kit/pubspec.yaml b/packages/hms_room_kit/pubspec.yaml index 459cb3ea2..c8e2e53d3 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.5 +version: 1.1.6 homepage: https://www.100ms.live/ repository: https://github.com/100mslive/100ms-flutter issue_tracker: https://github.com/100mslive/100ms-flutter/issues @@ -14,7 +14,7 @@ dependencies: flutter: sdk: flutter - hmssdk_flutter: 1.10.5 + hmssdk_flutter: 1.10.6 intl: ^0.19.0 permission_handler: ^11.0.0 provider: ^6.0.5 diff --git a/packages/hmssdk_flutter/CHANGELOG.md b/packages/hmssdk_flutter/CHANGELOG.md index fee920169..928ac600b 100644 --- a/packages/hmssdk_flutter/CHANGELOG.md +++ b/packages/hmssdk_flutter/CHANGELOG.md @@ -6,6 +6,36 @@ | hmssdk_flutter | [![Pub Version](https://img.shields.io/pub/v/hmssdk_flutter)](https://pub.dev/packages/hmssdk_flutter) | | hms_video_plugin | [![Pub Version](https://img.shields.io/pub/v/hms_video_plugin)](https://pub.dev/packages/hms_video_plugin) | +# 1.10.6 - 2024-09-17 + +| Package | Version | +| ----------------------------|----------| +| hms_room_kit | 1.1.6 | +| hmssdk_flutter | 1.10.6 | + +### Breaking Changes + +- Removed Noise Cancellation dependency + + Noise Cancellation dependency is removed from Prebuilt on Android. + Users will have to add the dependency manually in their Android project to use Noise Cancellation. + This change is made to reduce the size of the package. + Refer to the [Noise Cancellation](https://www.100ms.live/docs/flutter/v2/how-to-guides/extend-capabilities/noise-cancellation) documentation for more details. + + +### hmssdk_flutter + +- Added Camera Zoom Controls in `HMSCameraControls` + + Users can now control the camera zoom using the `HMSCameraControls` class. The `setZoom` method can be used to set the zoom level of the camera. + + Learn more about Camera Zoom Controls [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/configure-your-device/camera/camera-controls). + +Uses Android SDK 2.9.67 & iOS SDK 1.16.1 + +**Full Changelog**: [1.10.5...1.10.6](https://github.com/100mslive/100ms-flutter/compare/1.10.5...1.10.6) + + # 1.10.5 - 2024-07-25 | Package | Version | diff --git a/packages/hmssdk_flutter/README.md b/packages/hmssdk_flutter/README.md index d63c281c4..cbfb7dde6 100644 --- a/packages/hmssdk_flutter/README.md +++ b/packages/hmssdk_flutter/README.md @@ -7,7 +7,6 @@ [![Discord](https://img.shields.io/discord/843749923060711464?label=Join%20on%20Discord)](https://100ms.live/discord) [![Firebase](https://img.shields.io/badge/Download%20Android-Firebase-green)](https://appdistribution.firebase.dev/i/b623e5310929ab70) [![TestFlight](https://img.shields.io/badge/Download%20iOS-TestFlight-blue)](https://testflight.apple.com/join/Uhzebmut) -[![Activity](https://img.shields.io/github/commit-activity/m/100mslive/100ms-flutter.svg)](https://github.com/100mslive/100ms-flutter/projects?type=classic) [![Register](https://img.shields.io/badge/Contact-Know%20More-blue)](https://dashboard.100ms.live/register)

diff --git a/packages/hmssdk_flutter/android/build.gradle b/packages/hmssdk_flutter/android/build.gradle index 6accc5814..8350bb55f 100644 --- a/packages/hmssdk_flutter/android/build.gradle +++ b/packages/hmssdk_flutter/android/build.gradle @@ -50,7 +50,6 @@ 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.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/HMSTrackSettingsExtension.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSTrackSettingsExtension.kt index 2a742e6a0..205423990 100644 --- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSTrackSettingsExtension.kt +++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSTrackSettingsExtension.kt @@ -58,6 +58,20 @@ class HMSTrackSettingsExtension { hmsAudioTrackSettings.enableNoiseCancellation(true) } } + + val enableAutomaticGainControl = audioHashMap["enable_automatic_gain_control"] as? Boolean + enableAutomaticGainControl?.let { + if(it){ + hmsAudioTrackSettings.enableAutomaticGainControl(true) + } + } + + val enableNoiseSupression = audioHashMap["enable_noise_supression"] as? Boolean + enableNoiseSupression?.let { + if(it){ + hmsAudioTrackSettings.enableNoiseSupression(true) + } + } } var hmsVideoTrackSettings = HMSVideoTrackSettings.Builder() 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 810325734..68d709a14 100644 --- a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt +++ b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt @@ -1,18 +1,23 @@ Board: https://app.devrev.ai/100ms/vistas/vista-250 -- Caption text is not in sync with other app -https://app.devrev.ai/100ms/works/ISS-22834 +- Add support for zoom in camera controls +https://app.devrev.ai/100ms/works/ISS-23282 -- Noise cancellation layout API -https://app.devrev.ai/100ms/works/ISS-22858 +- Add support for Music Mode +https://app.devrev.ai/100ms/works/ISS-22859 -- Sample application not able to access microphone from a background in Android 14. -https://app.devrev.ai/100ms/works/ISS-22907 +- Support for long running sessions +https://app.devrev.ai/100ms/works/ISS-23134 -- Transcription replaces older transcription from view -https://app.devrev.ai/100ms/works/ISS-22845 +- Hand Raise sorting based on Time +https://app.devrev.ai/100ms/works/ISS-23102 -Room Kit: 1.1.5 -Core SDK: 1.10.5 -Android SDK: 2.9.64 -iOS SDK: 1.15.0 +- Change Role on Prebuilt +https://app.devrev.ai/100ms/works/ISS-22877 + +- Resolved crash when performing Role Change to VNRT + +Room Kit: 1.1.6 +Core SDK: 1.10.6 +Android SDK: 2.9.67 +iOS SDK: 1.16.1 diff --git a/packages/hmssdk_flutter/example/android/Gemfile.lock b/packages/hmssdk_flutter/example/android/Gemfile.lock index fee1f0f00..9f6b0a3b2 100644 --- a/packages/hmssdk_flutter/example/android/Gemfile.lock +++ b/packages/hmssdk_flutter/example/android/Gemfile.lock @@ -10,25 +10,25 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.929.0) - aws-sdk-core (3.196.1) + aws-partitions (1.970.0) + aws-sdk-core (3.202.2) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.8) + aws-sigv4 (~> 1.9) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.81.0) - aws-sdk-core (~> 3, >= 3.193.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.151.0) - aws-sdk-core (~> 3, >= 3.194.0) + aws-sdk-kms (1.88.0) + aws-sdk-core (~> 3, >= 3.201.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.159.0) + aws-sdk-core (~> 3, >= 3.201.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.9.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) base64 (0.2.0) @@ -37,14 +37,14 @@ GEM colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.4) declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) domain_name (0.6.20240107) dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.110.0) + excon (0.111.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -66,7 +66,7 @@ GEM faraday-httpclient (1.0.1) faraday-multipart (1.0.4) multipart-post (~> 2) - faraday-net_http (1.0.1) + faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) @@ -139,7 +139,7 @@ GEM google-apis-core (>= 0.11.0, < 2.a) google-apis-storage_v1 (0.31.0) google-apis-core (>= 0.11.0, < 2.a) - google-cloud-core (1.7.0) + google-cloud-core (1.7.1) google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) @@ -160,18 +160,18 @@ GEM os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.5) + http-cookie (1.0.7) domain_name (~> 0.5) httpclient (2.8.3) i18n (1.14.5) concurrent-ruby (~> 1.0) jmespath (1.6.2) json (2.7.2) - jwt (2.8.1) + jwt (2.8.2) base64 - mini_magick (4.12.0) + mini_magick (4.13.2) mini_mime (1.1.5) - minitest (5.22.3) + minitest (5.25.1) multi_json (1.15.0) multipart-post (2.4.1) nanaimo (0.3.0) @@ -180,14 +180,15 @@ GEM optparse (0.5.0) os (1.1.4) plist (3.7.1) - public_suffix (5.0.5) + public_suffix (6.0.1) rake (13.2.1) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.6) + rexml (3.3.6) + strscan rouge (2.0.7) ruby2_keywords (0.0.5) rubyzip (2.3.2) @@ -200,6 +201,7 @@ GEM simctl (1.6.10) CFPropertyList naturally + strscan (3.1.0) terminal-notifier (2.0.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) @@ -213,13 +215,13 @@ GEM uber (0.1.0) unicode-display_width (2.5.0) word_wrap (1.0.0) - xcodeproj (1.24.0) + xcodeproj (1.25.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.2, < 4.0) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) @@ -234,4 +236,4 @@ DEPENDENCIES fastlane-plugin-firebase_app_distribution BUNDLED WITH - 2.5.9 + 2.5.18 diff --git a/packages/hmssdk_flutter/example/android/app/build.gradle b/packages/hmssdk_flutter/example/android/app/build.gradle index d0c8a5858..bbf2cc4c5 100644 --- a/packages/hmssdk_flutter/example/android/app/build.gradle +++ b/packages/hmssdk_flutter/example/android/app/build.gradle @@ -1,5 +1,9 @@ +import groovy.json.JsonSlurper + def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') +def sdkVersions = new JsonSlurper().parse file("../../../lib/assets/sdk-versions.json") + if (localPropertiesFile.exists()) { localPropertiesFile.withReader('UTF-8') { reader -> localProperties.load(reader) @@ -36,8 +40,8 @@ android { applicationId "live.hms.flutter" minSdkVersion 21 targetSdkVersion 34 - versionCode 518 - versionName "1.5.218" + versionCode 529 + versionName "1.5.229" } signingConfigs { @@ -79,6 +83,7 @@ flutter { dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'com.google.firebase:firebase-crashlytics:18.6.2' + implementation "live.100ms:hms-noise-cancellation-android:${sdkVersions['android']}" } apply plugin: 'com.google.gms.google-services' diff --git a/packages/hmssdk_flutter/example/ios/Gemfile.lock b/packages/hmssdk_flutter/example/ios/Gemfile.lock index 795ca6aea..daf867df2 100644 --- a/packages/hmssdk_flutter/example/ios/Gemfile.lock +++ b/packages/hmssdk_flutter/example/ios/Gemfile.lock @@ -15,20 +15,20 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.955.0) - aws-sdk-core (3.201.1) + aws-partitions (1.970.0) + aws-sdk-core (3.202.2) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.8) + aws-sigv4 (~> 1.9) jmespath (~> 1, >= 1.6.1) aws-sdk-kms (1.88.0) aws-sdk-core (~> 3, >= 3.201.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.156.0) + aws-sdk-s3 (1.159.0) aws-sdk-core (~> 3, >= 3.201.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) - aws-sigv4 (1.8.0) + aws-sigv4 (1.9.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) base64 (0.2.0) @@ -37,7 +37,7 @@ GEM colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.4) declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) @@ -66,7 +66,7 @@ GEM faraday-httpclient (1.0.1) faraday-multipart (1.0.4) multipart-post (~> 2) - faraday-net_http (1.0.1) + faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) @@ -118,7 +118,7 @@ GEM 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) + fastlane-plugin-versioning (0.6.0) gh_inspector (1.1.3) google-apis-androidpublisher_v3 (0.54.0) google-apis-core (>= 0.11.0, < 2.a) @@ -140,7 +140,7 @@ GEM google-apis-core (>= 0.11.0, < 2.a) google-apis-storage_v1 (0.31.0) google-apis-core (>= 0.11.0, < 2.a) - google-cloud-core (1.7.0) + google-cloud-core (1.7.1) google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) @@ -161,7 +161,7 @@ GEM os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.6) + http-cookie (1.0.7) domain_name (~> 0.5) httpclient (2.8.3) i18n (1.14.5) @@ -172,7 +172,7 @@ GEM base64 mini_magick (4.13.2) mini_mime (1.1.5) - minitest (5.22.3) + minitest (5.25.1) multi_json (1.15.0) multipart-post (2.4.1) nanaimo (0.3.0) @@ -181,14 +181,14 @@ GEM optparse (0.5.0) os (1.1.4) plist (3.7.1) - public_suffix (6.0.0) + public_suffix (6.0.1) rake (13.2.1) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.9) + rexml (3.3.6) strscan rouge (2.0.7) ruby2_keywords (0.0.5) @@ -216,13 +216,13 @@ GEM uber (0.1.0) unicode-display_width (2.5.0) word_wrap (1.0.0) - xcodeproj (1.24.0) + xcodeproj (1.25.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.2, < 4.0) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) @@ -238,4 +238,4 @@ DEPENDENCIES fastlane-plugin-versioning BUNDLED WITH - 2.5.9 + 2.5.18 diff --git a/packages/hmssdk_flutter/example/ios/Podfile.lock b/packages/hmssdk_flutter/example/ios/Podfile.lock index 135ec9926..67749b088 100644 --- a/packages/hmssdk_flutter/example/ios/Podfile.lock +++ b/packages/hmssdk_flutter/example/ios/Podfile.lock @@ -130,16 +130,16 @@ PODS: - HMSHLSPlayerSDK (0.0.2): - HMSAnalyticsSDK (= 0.0.2) - HMSNoiseCancellationModels (1.0.0) - - HMSSDK (1.15.0): + - HMSSDK (1.16.1): - HMSAnalyticsSDK (= 0.0.2) - - HMSWebRTC (= 1.0.6170) - - hmssdk_flutter (1.10.5): + - HMSWebRTC (= 1.0.6171) + - hmssdk_flutter (1.10.6): - Flutter - HMSBroadcastExtensionSDK (= 0.0.9) - HMSHLSPlayerSDK (= 0.0.2) - HMSNoiseCancellationModels (= 1.0.0) - - HMSSDK (= 1.15.0) - - HMSWebRTC (1.0.6170) + - HMSSDK (= 1.16.1) + - HMSWebRTC (1.0.6171) - image_picker_ios (0.0.1): - Flutter - MLImage (1.0.0-beta4) @@ -315,9 +315,9 @@ SPEC CHECKSUMS: HMSBroadcastExtensionSDK: d80fe325f6c928bd8e5176290b5a4b7ae15d6fbb HMSHLSPlayerSDK: 6a54ad4d12f3dc2270d1ecd24019d71282a4f6a3 HMSNoiseCancellationModels: a3bda1405a16015632f4bcabd46ce48f35103b02 - HMSSDK: fc3d2141c654e9fdca7f27c290c17b6b61b9dc92 - hmssdk_flutter: 5e98234b680a0c7f814671aa5ad649b67d6fe670 - HMSWebRTC: b5ffaf5d6133ae2a4c841beaf1e5e4fe06d0fb07 + HMSSDK: 31e779fbf9c95335d88475a7f9f42fb077692e30 + hmssdk_flutter: da118bf9558b0556b609cdc14540dca5514291ac + HMSWebRTC: f6f4f02a665fda6d9d8a5b223272045c3d9486fb image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425 MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505 @@ -338,4 +338,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 9fb9f6e431a2c6c79942252e94b241ac7972ac90 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/packages/hmssdk_flutter/example/ios/Runner/Info.plist b/packages/hmssdk_flutter/example/ios/Runner/Info.plist index 2389fb90c..0e3e4f6d3 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.218 + 1.5.229 CFBundleSignature ???? CFBundleURLTypes @@ -48,7 +48,7 @@ CFBundleVersion - 518 + 529 ITSAppUsesNonExemptEncryption LSApplicationCategoryType diff --git a/packages/hmssdk_flutter/example/lib/app_settings_bottom_sheet.dart b/packages/hmssdk_flutter/example/lib/app_settings_bottom_sheet.dart index dd0b897be..bf7467683 100644 --- a/packages/hmssdk_flutter/example/lib/app_settings_bottom_sheet.dart +++ b/packages/hmssdk_flutter/example/lib/app_settings_bottom_sheet.dart @@ -88,7 +88,6 @@ class _AppSettingsBottomSheetState extends State { AppDebugConfig.isSoftwareDecoderDisabled = isSoftwareDecoderDisabled; AppDebugConfig.mirrorCamera = mirrorCamera; AppDebugConfig.showStats = showStats; - AppDebugConfig.skipPreview = skipPreview; AppDebugConfig.isDebugMode = isDebugMode; AppDebugConfig.nameChangeOnPreview = true; AppDebugConfig.isVirtualBackgroundEnabled = isVirtualBackgroundEnabled; diff --git a/packages/hmssdk_flutter/example/lib/main.dart b/packages/hmssdk_flutter/example/lib/main.dart index a2c64b49f..037245b82 100644 --- a/packages/hmssdk_flutter/example/lib/main.dart +++ b/packages/hmssdk_flutter/example/lib/main.dart @@ -235,6 +235,7 @@ class _HomePageState extends State { TextEditingController meetingLinkController = TextEditingController(); Uuid? uuid; String uuidString = ""; + HMSAudioMode audioMode = HMSAudioMode.VOICE; PackageInfo _packageInfo = PackageInfo( appName: 'Unknown', @@ -264,6 +265,9 @@ class _HomePageState extends State { } else { meetingLinkController.text = widget.deepLinkURL ?? ""; } + + int audioModeInt = await Utilities.getIntData(key: "audio-mode"); + audioMode = HMSAudioMode.values[audioModeInt]; } Future _closeApp() { @@ -348,7 +352,11 @@ class _HomePageState extends State { appGroup: "group.flutterhms", preferredExtension: "live.100ms.flutter.FlutterBroadcastUploadExtension"), - enableNoiseCancellation: true)), + enableNoiseCancellation: true, + isNoiseSuppressionEnabled: + audioMode == HMSAudioMode.MUSIC, + isAutomaticGainControlEnabled: + audioMode == HMSAudioMode.MUSIC)), ))); } diff --git a/packages/hmssdk_flutter/example/pubspec.lock b/packages/hmssdk_flutter/example/pubspec.lock index 6c8d07012..5624f709c 100644 --- a/packages/hmssdk_flutter/example/pubspec.lock +++ b/packages/hmssdk_flutter/example/pubspec.lock @@ -335,15 +335,15 @@ packages: path: "../../hms_room_kit" relative: true source: path - version: "1.1.5" + version: "1.1.6" hmssdk_flutter: dependency: transitive description: name: hmssdk_flutter - sha256: "2da8500708d8a8ebfa3d3ffb2f1deafd0ff23828dfaff6fdd1b4367da6337cf0" + sha256: "0097739f0005593738021d8c3d56179aee3ae46fa704a0d0be419b4ece4c350d" url: "https://pub.dev" source: hosted - version: "1.10.5" + version: "1.10.6" http: dependency: transitive description: diff --git a/packages/hmssdk_flutter/example/pubspec.yaml b/packages/hmssdk_flutter/example/pubspec.yaml index d0aaf2e98..1b60c9d20 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.5 +version: 1.10.6 environment: sdk: ">=2.16.0 <4.0.0" 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/assets/sdk-versions.json b/packages/hmssdk_flutter/lib/assets/sdk-versions.json index 473ba10fb..82477eff1 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.5", - "ios": "1.15.0", + "flutter": "1.10.6", + "ios": "1.16.1", "iOSBroadcastExtension": "0.0.9", "iOSHLSPlayerSDK": "0.0.2", "iOSNoiseCancellationModels": "1.0.0", - "android": "2.9.64" + "android": "2.9.67" } 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/hmssdk.dart b/packages/hmssdk_flutter/lib/src/hmssdk.dart index 3b25e5522..0ce6dcf92 100644 --- a/packages/hmssdk_flutter/lib/src/hmssdk.dart +++ b/packages/hmssdk_flutter/lib/src/hmssdk.dart @@ -1430,7 +1430,7 @@ class HMSSDK { /// ///**hmsActionResultListener** - [hmsActionResultListener] is a callback instance on which [HMSActionResultListener.onSuccess] and [HMSActionResultListener.onException] will be called. /// - ///TODO: Add docs link + /// Refer the guide [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/peer/large-room) void lowerLocalPeerHand( {HMSActionResultListener? hmsActionResultListener}) async { final dynamic result = @@ -1453,7 +1453,7 @@ class HMSSDK { /// ///**hmsActionResultListener** - [hmsActionResultListener] is a callback instance on which [HMSActionResultListener.onSuccess] and [HMSActionResultListener.onException] will be called. /// - ///TODO: Add docs link + /// Refer the guide [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/peer/large-room) void raiseLocalPeerHand( {HMSActionResultListener? hmsActionResultListener}) async { final dynamic result = @@ -1477,7 +1477,7 @@ class HMSSDK { ///**forPeer** - [forPeer] the peer whose hand you wish to lower ///**hmsActionResultListener** - [hmsActionResultListener] is a callback instance on which [HMSActionResultListener.onSuccess] and [HMSActionResultListener.onException] will be called. /// - ///TODO: Add docs link + /// Refer the guide [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/peer/large-room) void lowerRemotePeerHand( {required HMSPeer forPeer, HMSActionResultListener? hmsActionResultListener}) async { diff --git a/packages/hmssdk_flutter/lib/src/model/hms_audio_track_setting.dart b/packages/hmssdk_flutter/lib/src/model/hms_audio_track_setting.dart index baca57ed5..54faae4f9 100644 --- a/packages/hmssdk_flutter/lib/src/model/hms_audio_track_setting.dart +++ b/packages/hmssdk_flutter/lib/src/model/hms_audio_track_setting.dart @@ -40,6 +40,16 @@ class HMSAudioTrackSetting { ///Refer: Read more about noise cancellation [here](///) final bool enableNoiseCancellation; + ///[enableAutomaticGainControl] property sets the automatic gain control status in the room whether is enabled or not. + /// + ///Refer: Read more about automatic gain control [here](///) + final bool enableAutomaticGainControl; + + ///[enableNoiseSupression] property sets the noise suppression status in the room whether is enabled or not. + /// + ///Refer: Read more about noise suppression [here](///) + final bool enableNoiseSupression; + HMSAudioTrackSetting( {this.useHardwareAcousticEchoCanceler, this.audioSource, @@ -47,7 +57,9 @@ class HMSAudioTrackSetting { this.audioMode, this.phoneCallState = HMSAndroidPhoneCallState.DISABLE_MUTE_ON_VOIP_PHONE_CALL_RING, - this.enableNoiseCancellation = false}); + this.enableNoiseCancellation = false, + this.enableAutomaticGainControl = false, + this.enableNoiseSupression = false}); factory HMSAudioTrackSetting.fromMap(Map map) { List nodeList = []; @@ -109,7 +121,9 @@ class HMSAudioTrackSetting { 'phone_call_state': HMSAndroidPhoneCallStateValue.getValuefromHMSPhoneCallState( phoneCallState), - 'enable_noise_cancellation': enableNoiseCancellation + 'enable_noise_cancellation': enableNoiseCancellation, + 'enable_automatic_gain_control': enableAutomaticGainControl, + 'enable_noise_supression': enableNoiseSupression }; } } 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"); + } + } } diff --git a/packages/hmssdk_flutter/pubspec.yaml b/packages/hmssdk_flutter/pubspec.yaml index 1e2445444..cb917e07e 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.5 +version: 1.10.6 homepage: https://www.100ms.live/ repository: https://github.com/100mslive/100ms-flutter issue_tracker: https://github.com/100mslive/100ms-flutter/issues