diff --git a/.github/ISSUE_TEMPLATE/1-bug_report.yml b/.github/ISSUE_TEMPLATE/1-bug_report.yml index a82efb567..3b1f7755b 100644 --- a/.github/ISSUE_TEMPLATE/1-bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1-bug_report.yml @@ -1,5 +1,6 @@ name: 🐛 Bug Report description: Report a reproducible bug or regression in 100ms Flutter Package +title: "🐛 " labels: ["Needs Triage 🔍"] body: - type: markdown @@ -68,7 +69,7 @@ body: ```dart ``` validations: - required: true + required: true - type: textarea attributes: label: Logs diff --git a/.github/ISSUE_TEMPLATE/2-question-support.md b/.github/ISSUE_TEMPLATE/2-question-support.md index e76649555..e2fe1d973 100644 --- a/.github/ISSUE_TEMPLATE/2-question-support.md +++ b/.github/ISSUE_TEMPLATE/2-question-support.md @@ -1,27 +1,27 @@ --- name: "❓ Question or Support Request" about: "Questions and requests for support." -title: "" +title: "❓ " labels: ["question"] -assignees: '' - +assignees: "" --- # ❓ Question or Support Request + - ## Describe your question or ask for support + -* +- ## Is your feature request related to a problem? Please describe - -* + ---- +- *** ## **Describe the solution you'd like** - -* + ---- +- *** ## **Describe alternatives you've considered** - -* + ---- +- *** ### Any Media to attach? + --- - ### **Additional context** - -* + +- ## Test Scenarios diff --git a/.github/ISSUE_TEMPLATE/4-docs-bug.md b/.github/ISSUE_TEMPLATE/4-docs-bug.md index 4ac39fca9..491af3c5d 100644 --- a/.github/ISSUE_TEMPLATE/4-docs-bug.md +++ b/.github/ISSUE_TEMPLATE/4-docs-bug.md @@ -1,21 +1,21 @@ --- name: "📚 Documentation issue report" about: "Report an issue in the documentation." -title: "" +title: "📚 " labels: ["Needs Triage 🔍"] -assignees: '' - +assignees: "" --- -# 📚 Documentation Issue Report + +# 📚 Documentation Task + ## **Describe the bug** - -* + ---- +- *** ### Steps to Reproduce @@ -36,21 +36,22 @@ assignees: '' --- ### Any Media to attach? + --- ## **Describe the solution you'd like** + -* - ---- +- *** ### **Additional context** + -* +- key: $key value: $value"); + SessionStoreKey keyType = SessionStoreKeyValues.getMethodFromName(key); + switch (keyType) { + case SessionStoreKey.PINNED_MESSAGE_SESSION_KEY: + sessionMetadata = value; + break; + case SessionStoreKey.SPOTLIGHT: + setPeerToSpotlight(value); + break; + case SessionStoreKey.unknown: + break; + } + notifyListeners(); + } + + ///This method sets the peer to spotlight + ///this also handles removing a peer from spotlight case + void setPeerToSpotlight(String? value) { + int currentSpotlightPeerIndex = + peerTracks.indexWhere((node) => node.uid == spotLightPeer?.uid); + if (currentSpotlightPeerIndex != -1) { + peerTracks[currentSpotlightPeerIndex].pinTile = false; + spotLightPeer = null; + spotlightMetadata = null; + } + if (value != null) { + int index = peerTracks.indexWhere(((node) => + node.audioTrack?.trackId == (value) || + node.track?.trackId == (value))); + if (index != -1) { + Utilities.showToast("${peerTracks[index].peer.name} is in spotlight"); + spotLightPeer = peerTracks[index]; + changePinTileStatus(peerTracks[index]); + } else { + spotlightMetadata = value; + } + } else { + spotlightMetadata = null; + spotLightPeer = null; + } + notifyListeners(); + } + void setMode(MeetingMode meetingMode) { //Turning the videos on if the previously mode was audio if (this.meetingMode == MeetingMode.Audio && @@ -1405,19 +1494,30 @@ class MeetingStore extends ChangeNotifier return false; } + void setSpotlightOnTrackUpdate(HMSTrack track) { + ///In order to avoid errors because of + ///track updates ordering for audio and video + ///adding the method call here. + if (spotlightMetadata == track.trackId) { + setPeerToSpotlight(spotlightMetadata); + } + } + HMSAudioFilePlayerNode audioFilePlayerNode = HMSAudioFilePlayerNode("audioFilePlayerNode"); HMSMicNode micNode = HMSMicNode(); - void playAudioIos(String url) { - audioFilePlayerNode.play(fileUrl: url); + void playAudioIos(String url) async { + HMSException? exception = await audioFilePlayerNode.play(fileUrl: url); + if (exception != null) { + Utilities.showToast(exception.description, time: 5); + } isPlayerRunningIos(); } Future isPlayerRunningIos() async { - bool isPlaying = await audioFilePlayerNode.isPlaying(); - isAudioShareStarted = isPlaying; - return isPlaying; + isAudioShareStarted = await audioFilePlayerNode.isPlaying(); + return isAudioShareStarted; } void stopAudioIos() { @@ -1430,13 +1530,22 @@ class MeetingStore extends ChangeNotifier audioPlayerVolume = volume; } - void setSessionMetadata(String? metadata) { - _hmsSDKInteractor.setSessionMetadata( - metadata: metadata, hmsActionResultListener: this); + void setSessionMetadata({required String key, String? metadata}) { + _hmsSessionStore?.setSessionMetadataForKey( + key: key, data: metadata, hmsActionResultListener: this); } - void getSessionMetadata() async { - sessionMetadata = await _hmsSDKInteractor.getSessionMetadata(); + void getSessionMetadata(String key) async { + dynamic result = await _hmsSessionStore?.getSessionMetadataForKey(key: key); + if (result is HMSException) { + Utilities.showToast( + "Error Occured: code: ${result.code?.errorCode}, description: ${result.description}, message: ${result.message}", + time: 5); + return; + } + if (result != null) { + sessionMetadata = result as String; + } notifyListeners(); } @@ -1733,6 +1842,8 @@ class MeetingStore extends ChangeNotifier case HMSActionResultListenerMethod.changeRoleOfPeersWithRoles: Utilities.showToast("Change Role successful"); break; + case HMSActionResultListenerMethod.setSessionMetadataForKey: + break; } } @@ -1744,7 +1855,11 @@ class MeetingStore extends ChangeNotifier required HMSException hmsException}) { this.hmsException = hmsException; log("ActionResultListener onException-> method: ${methodType.toString()} , Error code : ${hmsException.code} , Description : ${hmsException.description} , Message : ${hmsException.message}"); - FirebaseCrashlytics.instance.log(hmsException.toString()); + FirebaseAnalytics.instance + .logEvent(name: "HMSActionResultListenerLogs", parameters: { + "data": + "ActionResultListener onException-> method: ${methodType.toString()} , Error code : ${hmsException.code} , Description : ${hmsException.description} , Message : ${hmsException.message}" + }); switch (methodType) { case HMSActionResultListenerMethod.leave: break; @@ -1809,6 +1924,9 @@ class MeetingStore extends ChangeNotifier case HMSActionResultListenerMethod.changeRoleOfPeersWithRoles: Utilities.showToast("Change role failed"); break; + case HMSActionResultListenerMethod.setSessionMetadataForKey: + Utilities.showToast("Set session metadata failed"); + break; } notifyListeners(); } @@ -1900,7 +2018,6 @@ class MeetingStore extends ChangeNotifier @override void onLogMessage({required HMSLogList hmsLogList}) { - FirebaseCrashlytics.instance.log(hmsLogList.toString()); FirebaseAnalytics.instance.logEvent( name: "SDK_Logs", parameters: {"data": hmsLogList.toString()}); applicationLogs.hmsLog.addAll(hmsLogList.hmsLog); diff --git a/example/lib/meeting_modes/audio_mode.dart b/example/lib/meeting_modes/audio_mode.dart index d22f02ac5..680dd83da 100644 --- a/example/lib/meeting_modes/audio_mode.dart +++ b/example/lib/meeting_modes/audio_mode.dart @@ -47,8 +47,7 @@ List portraitPattern( tiles.add(StairedGridTile(1, ratio)); pinTileCount++; } - int gridView = (peerTrack.length - pinTileCount) ~/ 6; - int tileLeft = (peerTrack.length - pinTileCount) - (gridView * 6); + int tileLeft = (peerTrack.length - pinTileCount) % 6; for (int i = 0; i < (peerTrack.length - pinTileCount - tileLeft); i++) { tiles.add(StairedGridTile(1 / 3, ratio / 1.5)); } diff --git a/example/lib/meeting_modes/basic_grid_view.dart b/example/lib/meeting_modes/basic_grid_view.dart index 96fe3ee0d..dbc738d3b 100644 --- a/example/lib/meeting_modes/basic_grid_view.dart +++ b/example/lib/meeting_modes/basic_grid_view.dart @@ -123,8 +123,7 @@ List portraitPattern(List peerTrack, pinTileCount++; } int normalTile = peerTrack.length - screenShareCount - pinTileCount; - int gridView = normalTile ~/ 4; - int tileLeft = normalTile - (gridView * 4); + int tileLeft = normalTile % 4; for (int i = 0; i < (normalTile - tileLeft); i++) { tiles.add(StairedGridTile(0.5, ratio)); } diff --git a/example/lib/meeting_modes/hero_mode.dart b/example/lib/meeting_modes/hero_mode.dart index a0ae072ed..0f9fed4fa 100644 --- a/example/lib/meeting_modes/hero_mode.dart +++ b/example/lib/meeting_modes/hero_mode.dart @@ -127,7 +127,7 @@ List portraitPattern( tiles.add(StairedGridTile(0.33, ratio / 0.6)); } int gridView = normalTile ~/ 4; - int tileLeft = normalTile - (gridView * 4); + int tileLeft = normalTile % 4; for (int i = 0; i < (normalTile - tileLeft - 4); i++) { tiles.add(StairedGridTile(0.5, ratio)); } diff --git a/example/lib/preview/preview_store.dart b/example/lib/preview/preview_store.dart index f9080a99b..65c359e06 100644 --- a/example/lib/preview/preview_store.dart +++ b/example/lib/preview/preview_store.dart @@ -143,8 +143,6 @@ class PreviewStore extends ChangeNotifier meetingUrl = meetingLink; return null; } - - FirebaseCrashlytics.instance.setUserIdentifier(_tokenData.toString()); return _tokenData; } diff --git a/example/pubspec.lock b/example/pubspec.lock index 39097fee5..e727d3665 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: f175bc1414e4edf8c5b83372c98eeabecf8353f39c9da423c2cfdf1f1f508788 + sha256: "6a0ad72b2bcdb461749e40c01c478212a78db848dfcb2f10f2a461988bc5fb29" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" archive: dependency: transitive description: @@ -189,42 +189,42 @@ packages: dependency: "direct main" description: name: file_picker - sha256: dcde5ad1a0cebcf3715ea3f24d0db1888bf77027a26c77d7779e8ef63b8ade62 + sha256: b85eb92b175767fdaa0c543bf3b0d1f610fe966412ea72845fe5ba7801e763ff url: "https://pub.dev" source: hosted - version: "5.2.9" + version: "5.2.10" firebase_analytics: dependency: "direct main" description: name: firebase_analytics - sha256: acba5361bdc2b2f711c47ae09171d9864c1e5f46156ec5ad8c4ce619dc55b968 + sha256: "2d8f475f79658a8e1865ee8a9e2e8eea70de5e487e3a646d9073dc3d1520d3e8" url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.2.1" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - sha256: "5019bb18deed5b92e0f22b11b496e8265548034179e55ac7a12987fabf133d16" + sha256: a667807edbcd3f5a6336275a21c8802de8f98f0a91b8c97abb76119b142aa91d url: "https://pub.dev" source: hosted - version: "3.4.0" + version: "3.4.1" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - sha256: "5bcdf3a63d1c6fe2426e22252b41d8579b8b7dd121225bcd623f4920d4cef4f9" + sha256: "907285030d59570d7c1a8d721912db990957ab9b87736e50a9457491c16bcffe" url: "https://pub.dev" source: hosted - version: "0.5.2" + version: "0.5.2+1" firebase_core: dependency: "direct main" description: name: firebase_core - sha256: ed611fb8e67e43ecc7956f242cecca383d87cf71aace27287aa5dd4bdba4ac07 + sha256: "239e4ac688674a7e7b5476fd16b0d8e2b5a453d464f32091af3ce1df4ebb7316" url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" firebase_core_platform_interface: dependency: transitive description: @@ -245,58 +245,58 @@ packages: dependency: "direct main" description: name: firebase_crashlytics - sha256: "42cf6a137eaae7e485e6cc9794336e8e518c506b691aa6e19ff918206c535bec" + sha256: "02ce958507138d938b4611e3a4910667a44b969b0c20a810bbc97bbf967ba0d7" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.2" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface - sha256: baa4c3d4af426d29800f0d80d165f31df4548985db151fd761346e07ed433d31 + sha256: b9c7b8498c877a2901ad323fc92c10f672be1597bc82d08f121f6228f321a7e0 url: "https://pub.dev" source: hosted - version: "3.4.0" + version: "3.4.1" firebase_dynamic_links: dependency: "direct main" description: name: firebase_dynamic_links - sha256: "07534e65f1417e2a59f64fa1f551d8f33b3cfe959fc24fd3833e8a810b9239c6" + sha256: e23f9d7323efc4532226d18cf1b7c05d1e348267a1a52bc1a18576a4d5f76849 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.1.1" firebase_dynamic_links_platform_interface: dependency: transitive description: name: firebase_dynamic_links_platform_interface - sha256: "8f9e655dbaba284b656549a8aa8eb4cade7354f37ef56aa415ec9ec65cef3118" + sha256: afcefb6b49416f4c0631fb5a80f516729fc39cd8163de27e287f2d72ac017fbc url: "https://pub.dev" source: hosted - version: "0.2.4" + version: "0.2.4+1" firebase_performance: dependency: "direct main" description: name: firebase_performance - sha256: cd5fd125a002c8e46e050d5b16c90033e6a90395ee2c44cc50a7c1178f0dd2e0 + sha256: "14f4d1e89e757f0aa1dec83c13ca390bbd728aca1ccc3ad19e6a23e2710f45b7" url: "https://pub.dev" source: hosted - version: "0.9.1" + version: "0.9.1+1" firebase_performance_platform_interface: dependency: transitive description: name: firebase_performance_platform_interface - sha256: "587d23cfea672563fe1429f5dd47f4066fcb71e9a1ae82140647d14e36bd9767" + sha256: "0914a49c4ca2cc74ac4c7fde719f280896b4c1d1bbe5fa72e059da0803cbc493" url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "0.1.2+1" firebase_performance_web: dependency: transitive description: name: firebase_performance_web - sha256: "99c5ba2f56e397ef2710ca60e65a2af036447ac6794328fb8ebabede4569c125" + sha256: "8192e4e112e9e09d2c9bbc8ab51d7c4e34ea618d15452d0ecfa6141e8babbd40" url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "0.1.2+1" flutter: dependency: "direct main" description: flutter @@ -330,10 +330,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: c224ac897bed083dabf11f238dd11a239809b446740be0c2044608c50029ffdf + sha256: "8ffe990dac54a4a5492747added38571a5ab474c8e5d196809ea08849c69b1bb" url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.0.13" flutter_staggered_grid_view: dependency: "direct main" description: @@ -388,17 +388,17 @@ packages: dependency: "direct main" description: name: google_fonts - sha256: "927573f2e8a8d65c17931e21918ad0ab0666b1b636537de7c4932bdb487b190f" + sha256: "6b6f10f0ce3c42f6552d1c70d2c28d764cf22bb487f50f66cca31dcd5194f4d6" url: "https://pub.dev" source: hosted - version: "4.0.3" + version: "4.0.4" hmssdk_flutter: dependency: "direct main" description: path: ".." relative: true source: path - version: "1.5.0" + version: "1.6.0" html: dependency: transitive description: @@ -443,10 +443,10 @@ packages: dependency: "direct main" description: name: intl - sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" url: "https://pub.dev" source: hosted - version: "0.18.0" + version: "0.18.1" js: dependency: transitive description: @@ -515,10 +515,10 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: cbff87676c352d97116af6dbea05aa28c4d65eb0f6d5677a520c11a69ca9a24d + sha256: "10259b111176fba5c505b102e3a5b022b51dd97e30522e906d6922c745584745" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.2" package_info_plus_platform_interface: dependency: transitive description: @@ -563,10 +563,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: da97262be945a72270513700a92b39dd2f4a54dad55d061687e2e37a6390366a + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" url: "https://pub.dev" source: hosted - version: "2.0.25" + version: "2.0.27" path_provider_foundation: dependency: transitive description: @@ -595,10 +595,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130 + sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.1.6" pedantic: dependency: transitive description: @@ -715,10 +715,10 @@ packages: dependency: "direct main" description: name: share_plus - sha256: "692261968a494e47323dcc8bc66d8d52e81bc27cb4b808e4e8d7e8079d4cc01a" + sha256: b1f15232d41e9701ab2f04181f21610c36c83a12ae426b79b4bd011c567934b1 url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.4" share_plus_platform_interface: dependency: transitive description: @@ -739,10 +739,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: "7fa90471a6875d26ad78c7e4a675874b2043874586891128dc5899662c97db46" + sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" shared_preferences_foundation: dependency: transitive description: @@ -888,10 +888,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: a52628068d282d01a07cd86e6ba99e497aa45ce8c91159015b2416907d78e411 + sha256: "22f8db4a72be26e9e3a4aa3f194b1f7afbc76d20ec141f84be1d787db2155cbd" url: "https://pub.dev" source: hosted - version: "6.0.27" + version: "6.0.31" url_launcher_ios: dependency: transitive description: @@ -904,10 +904,10 @@ packages: dependency: transitive description: name: url_launcher_linux - sha256: "206fb8334a700ef7754d6a9ed119e7349bc830448098f21a69bf1b4ed038cabc" + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.5" url_launcher_macos: dependency: transitive description: @@ -936,10 +936,10 @@ packages: dependency: transitive description: name: url_launcher_windows - sha256: a83ba3607a507758669cfafb03f9de09bf6e6280c14d9b9cb18f013e406dcacd + sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" uuid: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e7b30247b..ba4806bec 100644 --- a/example/pubspec.yaml +++ b/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.0.7+7 +version: 1.6.0 environment: sdk: ">=2.12.0 <3.0.0" diff --git a/ios/Classes/Models/HMSAudioAction.swift b/ios/Classes/Actions/HMSAudioAction.swift similarity index 100% rename from ios/Classes/Models/HMSAudioAction.swift rename to ios/Classes/Actions/HMSAudioAction.swift diff --git a/ios/Classes/Models/HMSAudioDeviceAction.swift b/ios/Classes/Actions/HMSAudioDeviceAction.swift similarity index 100% rename from ios/Classes/Models/HMSAudioDeviceAction.swift rename to ios/Classes/Actions/HMSAudioDeviceAction.swift diff --git a/ios/Classes/Models/HMSCameraControlsAction.swift b/ios/Classes/Actions/HMSCameraControlsAction.swift similarity index 99% rename from ios/Classes/Models/HMSCameraControlsAction.swift rename to ios/Classes/Actions/HMSCameraControlsAction.swift index a2a84bbfc..3d8c2b185 100644 --- a/ios/Classes/Models/HMSCameraControlsAction.swift +++ b/ios/Classes/Actions/HMSCameraControlsAction.swift @@ -166,6 +166,7 @@ class HMSCameraControlsAction { /// - Returns: the string represents the current time in the time zone of the device running the application. static private func getTimeStamp() -> String { let formatter = DateFormatter() + formatter.timeStyle = .medium return formatter.string(from: Date()) } diff --git a/ios/Classes/Models/HMSCommonAction.swift b/ios/Classes/Actions/HMSCommonAction.swift similarity index 100% rename from ios/Classes/Models/HMSCommonAction.swift rename to ios/Classes/Actions/HMSCommonAction.swift diff --git a/ios/Classes/Models/HMSHLSAction.swift b/ios/Classes/Actions/HMSHLSAction.swift similarity index 100% rename from ios/Classes/Models/HMSHLSAction.swift rename to ios/Classes/Actions/HMSHLSAction.swift diff --git a/ios/Classes/Models/HMSMessageAction.swift b/ios/Classes/Actions/HMSMessageAction.swift similarity index 100% rename from ios/Classes/Models/HMSMessageAction.swift rename to ios/Classes/Actions/HMSMessageAction.swift diff --git a/ios/Classes/Models/HMSPIPAction.swift b/ios/Classes/Actions/HMSPIPAction.swift similarity index 99% rename from ios/Classes/Models/HMSPIPAction.swift rename to ios/Classes/Actions/HMSPIPAction.swift index 02d11fde9..34e1977de 100644 --- a/ios/Classes/Models/HMSPIPAction.swift +++ b/ios/Classes/Actions/HMSPIPAction.swift @@ -78,7 +78,7 @@ class HMSPIPAction { model?.color = .black } - let controller = UIHostingController(rootView: PiPView(model: model!)) + let controller = UIHostingController(rootView: HMSPiPView(model: model!)) pipVideoCallViewController.view.addConstrained(subview: controller.view) diff --git a/ios/Classes/Models/HMSRecordingAction.swift b/ios/Classes/Actions/HMSRecordingAction.swift similarity index 100% rename from ios/Classes/Models/HMSRecordingAction.swift rename to ios/Classes/Actions/HMSRecordingAction.swift diff --git a/ios/Classes/Models/HMSRemoteVideoTrackAction.swift b/ios/Classes/Actions/HMSRemoteVideoTrackAction.swift similarity index 100% rename from ios/Classes/Models/HMSRemoteVideoTrackAction.swift rename to ios/Classes/Actions/HMSRemoteVideoTrackAction.swift diff --git a/ios/Classes/Models/HMSRoomAction.swift b/ios/Classes/Actions/HMSRoomAction.swift similarity index 100% rename from ios/Classes/Models/HMSRoomAction.swift rename to ios/Classes/Actions/HMSRoomAction.swift diff --git a/ios/Classes/Actions/HMSSessionStoreAction.swift b/ios/Classes/Actions/HMSSessionStoreAction.swift new file mode 100644 index 000000000..2381c5998 --- /dev/null +++ b/ios/Classes/Actions/HMSSessionStoreAction.swift @@ -0,0 +1,89 @@ +// +// HMSSessionStoreAction.swift +// hmssdk_flutter +// +// Created by Yogesh Singh on 25/04/23. +// + +import Foundation +import HMSSDK + +class HMSSessionStoreAction { + + static func sessionStoreActions(_ call: FlutterMethodCall, _ result: @escaping FlutterResult, _ plugin: SwiftHmssdkFlutterPlugin) { + + switch call.method { + case "get_session_metadata_for_key": + getSessionMetadata(call, result, plugin) + + case "set_session_metadata_for_key": + setSessionMetadata(call, result, plugin) + + default: + result(FlutterMethodNotImplemented) + } + } + + static private func getSessionMetadata(_ call: FlutterMethodCall, _ result: @escaping FlutterResult, _ plugin: SwiftHmssdkFlutterPlugin) { + + guard let store = plugin.sessionStore + else { + HMSErrorLogger.returnHMSException(#function, "Session Store is null", "NULL ERROR", result) + return + } + + guard let arguments = call.arguments as? [AnyHashable: Any], + let key = arguments["key"] as? String + else { + HMSErrorLogger.returnArgumentsError("key is null") + HMSErrorLogger.returnHMSException(#function, "Key to be fetched from Session Store is null.", "NULL ERROR", result) + return + } + + store.object(forKey: key) { value, error in + + if let error = error { + HMSErrorLogger.returnHMSException(#function, "Error in fetching key: \(key) from Session Store. Error: \(error.localizedDescription)", "Key Fetching error", result) + return + } + + if value is String? || value is NSNull { + result(HMSResultExtension.toDictionary(true, value)) + } else { + HMSErrorLogger.returnHMSException(#function, "Session metadata type is not compatible, Please use String? type while setting metadata", "Type Incompatibility Error", result) + } + + } + + } + + static private func setSessionMetadata(_ call: FlutterMethodCall, _ result: @escaping FlutterResult, _ plugin: SwiftHmssdkFlutterPlugin) { + + guard let store = plugin.sessionStore + else { + HMSErrorLogger.logError(#function,"Session Store is null.","NULL Error") + result(HMSErrorExtension.getError("Session Store is null.")) + return + } + + guard let arguments = call.arguments as? [AnyHashable: Any], + let key = arguments["key"] as? String + else { + HMSErrorLogger.logError(#function,"Key for the object to be set in Session Store is null.","NULL Error") + result(HMSErrorExtension.getError("Key for the object to be set in Session Store is null.")) + return + } + + let data = arguments["data"] + + store.set(data as Any, forKey: key) { _, error in + + if let error = error { + HMSErrorLogger.logError(#function,"Error in setting data: \(data ?? "null") for key: \(key) to the Session Store. Error: \(error.localizedDescription)","Key Error") + result(HMSErrorExtension.getError("Error in setting data: \(data ?? "null") for key: \(key) to the Session Store. Error: \(error.localizedDescription)")) + return + } + result(nil) + } + } +} diff --git a/ios/Classes/Models/HMSVideoAction.swift b/ios/Classes/Actions/HMSVideoAction.swift similarity index 100% rename from ios/Classes/Models/HMSVideoAction.swift rename to ios/Classes/Actions/HMSVideoAction.swift diff --git a/ios/Classes/Models/HMSAudioFilePlayerNodeExtension.swift b/ios/Classes/Models/HMSAudioFilePlayerNodeExtension.swift index e83ba062c..edd570c38 100644 --- a/ios/Classes/Models/HMSAudioFilePlayerNodeExtension.swift +++ b/ios/Classes/Models/HMSAudioFilePlayerNodeExtension.swift @@ -11,48 +11,64 @@ import HMSSDK class HMSAudioFilePlayerNodeExtension { static func play(_ call: [AnyHashable: Any], _ playerNode: HMSAudioFilePlayerNode, _ result: @escaping FlutterResult) { + guard let fileURL = call["file_url"] as? String else { + HMSErrorLogger.returnArgumentsError("Invalid file") + HMSErrorLogger.returnHMSException(#function, "Error in playing the file", "File Error", result) + return + } + guard let url = URL(string: fileURL) else { + HMSErrorLogger.returnArgumentsError("File URL is invalid") + HMSErrorLogger.returnHMSException(#function, "Error in playing the file", "File Error", result) + return + } do { - try playerNode.play(fileUrl: URL(string: call["file_url"] as! String)!, loops: call["loops"] as? Bool ?? false, interrupts: call["interrupts"] as? Bool ?? false) + try + playerNode.play(fileUrl: url, loops: call["loops"] as? Bool ?? false, interrupts: call["interrupts"] as? Bool ?? false) + result(HMSResultExtension.toDictionary(true, nil)) } catch { - result(HMSErrorExtension.toDictionary(error)) + result(HMSResultExtension.toDictionary(false, HMSErrorExtension.toDictionary(error))) } } - static func pause( _ playerNode: HMSAudioFilePlayerNode) { + static func pause( _ playerNode: HMSAudioFilePlayerNode, _ result: @escaping FlutterResult) { playerNode.pause() + result(HMSResultExtension.toDictionary(true, nil)) } static func resume( _ playerNode: HMSAudioFilePlayerNode, _ result: @escaping FlutterResult) { do { try playerNode.resume() + result(HMSResultExtension.toDictionary(true, nil)) } catch { - result(HMSErrorExtension.toDictionary(error)) + result(HMSResultExtension.toDictionary(false, HMSErrorExtension.toDictionary(error))) } } - static func stop( _ playerNode: HMSAudioFilePlayerNode) { + static func stop( _ playerNode: HMSAudioFilePlayerNode, _ result: @escaping FlutterResult) { playerNode.stop() + result(HMSResultExtension.toDictionary(true, nil)) } - static func setVolume(_ call: [AnyHashable: Any], _ playerNode: HMSAudioFilePlayerNode) { + static func setVolume(_ call: [AnyHashable: Any], _ playerNode: HMSAudioFilePlayerNode, _ result: @escaping FlutterResult) { playerNode.volume = Float(call["volume"] as! Double) + result(HMSResultExtension.toDictionary(true, nil)) } static func isPlaying(_ playerNode: HMSAudioFilePlayerNode, _ result: FlutterResult) { var dict = [String: Any]() dict["is_playing"] = playerNode.isPlaying - result(dict) + result(HMSResultExtension.toDictionary(true, dict)) } static func currentDuration(_ playerNode: HMSAudioFilePlayerNode, _ result: FlutterResult) { var dict = [String: Any]() dict["current_duration"] = playerNode.currentTime - result(dict) + result(HMSResultExtension.toDictionary(true, dict)) } static func duration(_ playerNode: HMSAudioFilePlayerNode, _ result: FlutterResult) { var dict = [String: Any]() dict["duration"] = playerNode.duration - result(dict) + result(HMSResultExtension.toDictionary(true, dict)) } } diff --git a/ios/Classes/Models/HMSErrorLogger.swift b/ios/Classes/Models/HMSErrorLogger.swift index 8133bb303..a8b83c06d 100644 --- a/ios/Classes/Models/HMSErrorLogger.swift +++ b/ios/Classes/Models/HMSErrorLogger.swift @@ -24,7 +24,7 @@ class HMSErrorLogger { * This method is used to log of arguments passed from flutter channel is null * This does not stop the function execution. Function still executes normally */ - static func returnArgumentsError(errorMessage: String) { + static func returnArgumentsError(_ errorMessage: String) { print("FL_HMSSDK Args Error \(errorMessage)") } diff --git a/ios/Classes/Models/HMSSessionStoreKeyChangeListener.swift b/ios/Classes/Models/HMSSessionStoreKeyChangeListener.swift new file mode 100644 index 000000000..cd4e83b76 --- /dev/null +++ b/ios/Classes/Models/HMSSessionStoreKeyChangeListener.swift @@ -0,0 +1,20 @@ +// +// HMSSessionStoreKeyChangeListener.swift +// hmssdk_flutter +// +// Created by Yogesh Singh on 26/04/23. +// + +import Foundation + +class HMSSessionStoreKeyChangeListener: NSObject { + + let uid: String + + let observer: NSObjectProtocol + + init(_ uid: String, _ observer: NSObjectProtocol) { + self.uid = uid + self.observer = observer + } +} diff --git a/ios/Classes/Models/HMSTrackSettingsExtension.swift b/ios/Classes/Models/HMSTrackSettingsExtension.swift index 360dcda6c..12a1ab3d0 100644 --- a/ios/Classes/Models/HMSTrackSettingsExtension.swift +++ b/ios/Classes/Models/HMSTrackSettingsExtension.swift @@ -53,27 +53,53 @@ class HMSTrackSettingsExtension { dict["track_description"] = hmsAudioTrackSettings.trackDescription dict["max_bitrate"] = hmsAudioTrackSettings.maxBitrate dict["audio_source"] = audioMixerSourceMap.keys.map {$0} + dict["audio_mode"] = getStringFromAudioMode(from: hmsAudioTrackSettings.audioMode) return dict } static func setTrackSetting(_ settingsDict: [AnyHashable: Any], _ audioMixerSourceMap: [String: HMSAudioNode], _ result: @escaping FlutterResult) -> HMSTrackSettings? { var audioSettings: HMSAudioTrackSettings? - if let audioSettingsDict = settingsDict["audio_track_setting"] as? [AnyHashable: Any], - let initialMuteState = audioSettingsDict["track_initial_state"] as? String { + + if let audioSettingsDict = settingsDict["audio_track_setting"] as? [AnyHashable: Any] { + + var initialMuteState: HMSTrackMuteState? + if let muteState = audioSettingsDict["track_initial_state"] as? String { + initialMuteState = getinitialMuteState(from: muteState) + } if #available(iOS 13.0, *), !audioMixerSourceMap.isEmpty { do { let audioMixerSource = try HMSAudioMixerSource(nodes: audioMixerSourceMap.values.map {$0}) - audioSettings = HMSAudioTrackSettings(maxBitrate: 32, trackDescription: "track_description", initialMuteState: getinitialMuteState(from: initialMuteState), audioSource: audioMixerSource) + audioSettings = HMSAudioTrackSettings.build({ builder in + + builder.audioSource = audioMixerSource + + if let muteState = initialMuteState { + builder.initialMuteState = muteState + } + + if let mode = getAudioMode(from: audioSettingsDict["audio_mode"] as? String) { + builder.audioMode = mode + } + }) } catch { print(#function, HMSErrorExtension.toDictionary(error)) result(false) } } else { - audioSettings = HMSAudioTrackSettings(maxBitrate: 32, trackDescription: "track_description", initialMuteState: getinitialMuteState(from: initialMuteState), audioSource: nil) + audioSettings = HMSAudioTrackSettings.build({ builder in + + if let muteState = initialMuteState { + builder.initialMuteState = muteState + } + + if let mode = getAudioMode(from: audioSettingsDict["audio_mode"] as? String) { + builder.audioMode = mode + } + }) } } @@ -111,4 +137,29 @@ class HMSTrackSettingsExtension { return HMSTrackMuteState.mute } + static private func getAudioMode(from mode: String?) -> HMSAudioMode? { + switch mode { + case "voice": + return .voice + + case "music": + return .music + + default: + return nil + } + } + + static private func getStringFromAudioMode(from mode: HMSAudioMode) -> String? { + switch mode { + case .music: + return "music" + + case .voice: + return "voice" + + default: + return nil + } + } } diff --git a/ios/Classes/SwiftHmssdkFlutterPlugin.swift b/ios/Classes/SwiftHmssdkFlutterPlugin.swift index 0bdbc470c..ae03fe79e 100644 --- a/ios/Classes/SwiftHmssdkFlutterPlugin.swift +++ b/ios/Classes/SwiftHmssdkFlutterPlugin.swift @@ -14,17 +14,24 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene var previewEventChannel: FlutterEventChannel? var logsEventChannel: FlutterEventChannel? var rtcStatsEventChannel: FlutterEventChannel? + var sessionEventChannel: FlutterEventChannel? var eventSink: FlutterEventSink? var previewSink: FlutterEventSink? var logsSink: FlutterEventSink? var rtcSink: FlutterEventSink? + var sessionSink: FlutterEventSink? + var roleChangeRequest: HMSRoleChangeRequest? internal var hmsSDK: HMSSDK? private var isStatsActive = false + internal var sessionStore: HMSSessionStore? + + private var sessionStoreChangeObservers = [HMSSessionStoreKeyChangeListener]() + // MARK: - Flutter Setup public static func register(with registrar: FlutterPluginRegistrar) { @@ -35,12 +42,14 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene let previewChannel = FlutterEventChannel(name: "preview_event_channel", binaryMessenger: registrar.messenger()) let logsChannel = FlutterEventChannel(name: "logs_event_channel", binaryMessenger: registrar.messenger()) let rtcChannel = FlutterEventChannel(name: "rtc_event_channel", binaryMessenger: registrar.messenger()) + let sessionChannel = FlutterEventChannel(name: "session_event_channel", binaryMessenger: registrar.messenger()) let instance = SwiftHmssdkFlutterPlugin(channel: channel, meetingEventChannel: eventChannel, previewEventChannel: previewChannel, logsEventChannel: logsChannel, - rtcStatsEventChannel: rtcChannel) + rtcStatsEventChannel: rtcChannel, + sessionEventChannel: sessionChannel) let videoViewFactory = HMSFlutterPlatformViewFactory(plugin: instance) registrar.register(videoViewFactory, withId: "HMSFlutterPlatformView") @@ -49,6 +58,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene previewChannel.setStreamHandler(instance) logsChannel.setStreamHandler(instance) rtcChannel.setStreamHandler(instance) + sessionChannel.setStreamHandler(instance) registrar.addMethodCallDelegate(instance, channel: channel) } @@ -57,13 +67,15 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene meetingEventChannel: FlutterEventChannel, previewEventChannel: FlutterEventChannel, logsEventChannel: FlutterEventChannel, - rtcStatsEventChannel: FlutterEventChannel) { + rtcStatsEventChannel: FlutterEventChannel, + sessionEventChannel: FlutterEventChannel) { self.channel = channel self.meetingEventChannel = meetingEventChannel self.previewEventChannel = previewEventChannel self.logsEventChannel = logsEventChannel self.rtcStatsEventChannel = rtcStatsEventChannel + self.sessionEventChannel = sessionEventChannel } public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { @@ -82,6 +94,8 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene logsSink = events case "rtc_stats": rtcSink = events + case "session_store": + sessionSink = events default: return FlutterError(code: #function, message: "invalid event sink name", details: arguments) } @@ -98,25 +112,31 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene meetingEventChannel!.setStreamHandler(nil) eventSink = nil } else { - print("meetingEventChannel not found", #function) + print(#function, "meetingEventChannel not found") } if previewEventChannel != nil { previewEventChannel!.setStreamHandler(nil) previewSink = nil } else { - print("previewEventChannel not found", #function) + print(#function, "previewEventChannel not found") } if logsEventChannel != nil { logsEventChannel!.setStreamHandler(nil) logsSink = nil } else { - print("logsEventChannel not found", #function) + print(#function, "logsEventChannel not found") } if rtcStatsEventChannel != nil { rtcStatsEventChannel!.setStreamHandler(nil) rtcSink = nil } else { - print("rtcStatsEventChannel not found", #function) + print(#function, "rtcStatsEventChannel not found") + } + if sessionEventChannel != nil { + sessionEventChannel!.setStreamHandler(nil) + sessionSink = nil + } else { + print(#function, "sessionEventChannel not found") } } @@ -139,6 +159,9 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene case "switch_audio", "is_audio_mute", "mute_room_audio_locally", "un_mute_room_audio_locally", "set_volume", "toggle_mic_mute_state": HMSAudioAction.audioActions(call, result, hmsSDK) + case "set_playback_allowed_for_track": + setPlaybackAllowedForTrack(call, result) + // MARK: - Video Helpers case "switch_video", "switch_camera", "is_video_mute", "mute_room_video_locally", "un_mute_room_video_locally", "toggle_camera_mute_state": @@ -183,23 +206,34 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene case "start_screen_share", "stop_screen_share", "is_screen_share_active": screenShareActions(call, result) + // MARK: - Track Settings + case "get_track_settings": trackSettingsAction(call, result) break + + // MARK: - Local Audio Share + case "play_audio_share", "stop_audio_share", "pause_audio_share", "resume_audio_share", "set_audio_share_volume", "audio_share_playing", "audio_share_current_time", "audio_share_duration": audioShareAction(call, result) + + // MARK: - Switch Audio Output + case "switch_audio_output", "get_audio_devices_list": HMSAudioDeviceAction.audioActions(call, result, hmsSDK) + // MARK: - Session Metadata + case "get_session_metadata", "set_session_metadata": sessionMetadataAction(call, result) - case "set_playback_allowed_for_track": - setPlaybackAllowedForTrack(call, result) + // MARK: - Simulcast case "set_simulcast_layer", "get_layer", "get_layer_definition": HMSRemoteVideoTrackExtension.remoteVideoTrackActions(call, result, hmsSDK!) + // MARK: - PIP Mode + case "setup_pip", "start_pip", "stop_pip", "is_pip_available", "is_pip_active", "change_track_pip", "change_text_pip", "destroy_pip": guard #available(iOS 15.0, *) else { print(#function, HMSErrorExtension.getError("iOS 15 or above is required")) @@ -207,12 +241,27 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene return } HMSPIPAction.pipAction(call, result, hmsSDK, self) + // MARK: - Capture HMSVideoView Snapshot + case "capture_snapshot": captureSnapshot(call, result) + // MARK: - Advanced Camera Controls + case "capture_image_at_max_supported_resolution", "is_tap_to_focus_supported", "is_zoom_supported", "is_flash_supported", "toggle_flash": HMSCameraControlsAction.cameraControlsAction(call, result, hmsSDK) + // MARK: - Session Store + + case "get_session_metadata_for_key", "set_session_metadata_for_key": + HMSSessionStoreAction.sessionStoreActions(call, result, self) + + case "add_key_change_listener": + addKeyChangeListener(call, result) + + case "remove_key_change_listener": + removeKeyChangeListener(call, result) + default: result(FlutterMethodNotImplemented) } @@ -348,17 +397,17 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene HMSAudioFilePlayerNodeExtension.play(arguments, audioNode as! HMSAudioFilePlayerNode, result) break case "stop_audio_share": - HMSAudioFilePlayerNodeExtension.stop(audioNode as! HMSAudioFilePlayerNode) + HMSAudioFilePlayerNodeExtension.stop(audioNode as! HMSAudioFilePlayerNode, result) break case "pause_audio_share": - HMSAudioFilePlayerNodeExtension.pause(audioNode as! HMSAudioFilePlayerNode) + HMSAudioFilePlayerNodeExtension.pause(audioNode as! HMSAudioFilePlayerNode, result) break case "resume_audio_share": HMSAudioFilePlayerNodeExtension.resume(audioNode as! HMSAudioFilePlayerNode, result) break case "set_audio_share_volume": if arguments["name"] as! String != "mic_node" { - HMSAudioFilePlayerNodeExtension.setVolume(arguments, audioNode as! HMSAudioFilePlayerNode) + HMSAudioFilePlayerNodeExtension.setVolume(arguments, audioNode as! HMSAudioFilePlayerNode, result) } else { HMSMicNodeExtension.setVolume(arguments, audioNode as! HMSMicNode) } @@ -435,16 +484,168 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene } } + // MARK: - Session Store + + /** + * This method is used to add key change listener for + * keys passed while calling this method + * + * Parameters: + * - keys: List List of keys for which metadata updates need to be listened. + * - keyChangeListener: Instance of HMSKeyChangeListener to listen to the metadata changes for corresponding keys + */ + private func addKeyChangeListener(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { + + guard let store = sessionStore + else { + HMSErrorLogger.logError(#function,"Session Store is null","NULL ERROR") + result(HMSErrorExtension.getError("Session Store is null")) + return + } + + guard let arguments = call.arguments as? [AnyHashable: Any] + else { + HMSErrorLogger.returnArgumentsError("keys is null") + result(HMSErrorExtension.getError("No arguments passed which can be attached to Key Change Listener on the Session Store.")) + return + } + + guard let keys = arguments["keys"] as? [String] + else { + HMSErrorLogger.logError(#function,"No keys passed which can be attached to Key Change Listener on the Session Store. Available arguments: \(arguments)","NULL ERROR") + result(HMSErrorExtension.getError("No keys passed which can be attached to Key Change Listener on the Session Store. Available arguments: \(arguments)")) + return + } + + guard let uid = arguments["uid"] as? String + else { + HMSErrorLogger.logError(#function,"No uid passed for key change listener Available arguments: \(arguments)", "NULL ERROR") + result(HMSErrorExtension.getError("No uid passed for key change listener Available arguments: \(arguments)")) + return + } + + store.observeChanges(forKeys: keys, changeObserver: { [weak self] key, value in + + var data = [String: Any]() + + data["event_name"] = "on_key_changed" + + var dict: [String: Any] = ["key": key] + + if value is String? || value is NSNull { + dict["value"] = value + } else { + HMSErrorLogger.logError(#function, "Session metadata type is not compatible, Please use String? type while setting metadata", "Type Incompatibility Error") + dict["value"] = nil + } + + dict["uid"] = uid + data["data"] = dict + + self?.sessionSink?(data) + + }) { [weak self] observer, error in + + if let error = error { + HMSErrorLogger.logError(#function,"Error in observing changes for key: \(keys) in the Session Store. Error: \(error.localizedDescription)","KEY CHANGE ERROR") + result(HMSErrorExtension.getError("Error in observing changes for key: \(keys) in the Session Store. Error: \(error.localizedDescription)")) + return + } + + guard let observer = observer + else { + HMSErrorLogger.logError(#function,"Unknown Error in observing changes for key: \(keys) in the Session Store.","KEY CHANGE ERROR") + result(HMSErrorExtension.getError("Unknown Error in observing changes for key: \(keys) in the Session Store.")) + return + } + + guard let self = self + else { + HMSErrorLogger.logError(#function,"Could not find self instance while observing changes for key: \(keys) in the Session Store.","KEY CHANGE ERROR") + result(HMSErrorExtension.getError("Could not find self instance while observing changes for key: \(keys) in the Session Store.")) + return + } + + self.sessionStoreChangeObservers.append(HMSSessionStoreKeyChangeListener(uid, observer)) + + result(nil) + } + } + + /*** + * This method is used to remove the attached key change listeners + * attached using [addKeyChangeListener] method + */ + private func removeKeyChangeListener(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { + +// There is no need to call removeKeyChangeListener is +// there is no keyChangeListener attached + if sessionStoreChangeObservers.isEmpty { + result(HMSResultExtension.toDictionary(true, nil)) + return + } + + guard let store = sessionStore + else { + HMSErrorLogger.returnHMSException(#function, "Session Store is null", "NULL ERROR", result) + return + } + + guard let arguments = call.arguments as? [AnyHashable: Any] + else { + HMSErrorLogger.returnHMSException(#function, "No arguments to identify which Key Change Listener should be removed from the Session Store.", "Remove Key Error", result) + return + } + + guard let uid = arguments["uid"] as? String + else { + HMSErrorLogger.returnHMSException(#function, "No identifier passed which can be used. Available arguments: \(arguments)", "Unique Id Error", result) + return + } + + guard let keyChangeListenersToBeRemovedIndex = sessionStoreChangeObservers.firstIndex(where: { + $0.uid == uid + }) + else { + HMSErrorLogger.returnHMSException(#function, "No listener found to remove", "Listener Error", result) + return + } + + store.removeObserver(sessionStoreChangeObservers[keyChangeListenersToBeRemovedIndex].observer) + + sessionStoreChangeObservers.remove(at: keyChangeListenersToBeRemovedIndex) + + result(HMSResultExtension.toDictionary(true, nil)) + } + + /** + This takes care of removing all the key change listeners attached during the session + This is used while cleaning the room state i.e after calling leave room, + onRemovedFromRoom or endRoom + */ + private func removeAllKeyChangeListener() { + sessionStoreChangeObservers.forEach {[weak self] observer in + self?.sessionStore?.removeObserver(observer.observer) + } + sessionStoreCleanup() + } + + private func sessionStoreCleanup() { + sessionStore = nil + sessionStoreChangeObservers = [] + } + // MARK: - Room Actions + private func build(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { - let arguments = call.arguments as! [AnyHashable: Any] + let arguments = call.arguments as? [AnyHashable: Any] // TODO: add checks for 100ms Extension Target - if let prefExtension = arguments["preferred_extension"] as? String { + if let prefExtension = arguments?["preferred_extension"] as? String { preferredExtension = prefExtension } - if let iOSScreenshareConfig = arguments["ios_screenshare_config"] as? [String: String] { + if let iOSScreenshareConfig = arguments?["ios_screenshare_config"] as? [String: String] { if let prefExtension = iOSScreenshareConfig["preferred_extension"] { preferredExtension = prefExtension } else { @@ -454,13 +655,13 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene } var setLogger = false - if let hmsLogSettings = arguments["hms_log_settings"] as? [AnyHashable: Any] { + if let hmsLogSettings = arguments?["hms_log_settings"] as? [AnyHashable: Any] { let level = hmsLogSettings["log_level"] as! String logLevel = getLogLevel(from: level) setLogger = true } - let dartSDKVersion = arguments["dart_sdk_version"] as! String - let hmsSDKVersion = arguments["hmssdk_version"] as! String + let dartSDKVersion = arguments?["dart_sdk_version"] as! String + let hmsSDKVersion = arguments?["hmssdk_version"] as! String let framework = HMSFrameworkInfo(type: .flutter, version: dartSDKVersion, sdkVersion: hmsSDKVersion) audioMixerSourceMap = [:] @@ -470,11 +671,11 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene result(false) return } - if let appGroup = arguments["app_group"] as? String { + if let appGroup = arguments?["app_group"] as? String { sdk.appGroup = appGroup } - if let iOSScreenshareConfig = arguments["ios_screenshare_config"] as? [String: String] { + if let iOSScreenshareConfig = arguments?["ios_screenshare_config"] as? [String: String] { if let appGroup = iOSScreenshareConfig["app_group"] { sdk.appGroup = appGroup } else { @@ -490,7 +691,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene } var trackSettings: HMSTrackSettings? - if let settingsDict = arguments["hms_track_setting"] as? [AnyHashable: Any] { + if let settingsDict = arguments?["hms_track_setting"] as? [AnyHashable: Any] { self.audioMixerSourceInit(settingsDict, sdk, result) trackSettings = HMSTrackSettingsExtension.setTrackSetting(settingsDict, self.audioMixerSourceMap, result) } @@ -547,11 +748,11 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene } private func leave(_ result: @escaping FlutterResult) { - hmsSDK?.leave { _, error in + hmsSDK?.leave { [weak self] _, error in if let error = error { result(HMSErrorExtension.toDictionary(error)) } else { - self.destroyPIPController() + self?.performCleanupOnLeavingRoom() result(nil) } } @@ -651,11 +852,11 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene let lock = arguments["lock"] as? Bool ?? false let reason = arguments["reason"] as? String ?? "End room invoked" - hmsSDK?.endRoom(lock: lock, reason: reason) { _, error in + hmsSDK?.endRoom(lock: lock, reason: reason) { [weak self] _, error in if let error = error { result(HMSErrorExtension.toDictionary(error)) } else { - self.destroyPIPController() + self?.performCleanupOnLeavingRoom() result(nil) } } @@ -963,7 +1164,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene "data": [ "room": HMSRoomExtension.toDictionary(room), "local_tracks": tracks - ] + ] as [String: Any] ] as [String: Any] previewEnded = false previewSink?(data) @@ -987,7 +1188,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene "data": [ "room": HMSRoomExtension.toDictionary(room), "update": HMSRoomExtension.getValueOf(update) - ] + ] as [String: Any] ] as [String: Any] if previewEnded { eventSink?(data) @@ -1005,7 +1206,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene "data": [ "peer": HMSPeerExtension.toDictionary(peer), "update": HMSPeerExtension.getValueOf(update) - ] + ] as [String: Any] ] as [String: Any] if previewEnded { @@ -1023,7 +1224,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene "peer": HMSPeerExtension.toDictionary(peer), "track": HMSTrackExtension.toDictionary(track), "update": HMSTrackExtension.getValueOf(update) - ] + ] as [String: Any] ] as [String: Any] if peer.isLocal && track.source.uppercased() == "SCREEN" { if update == .trackAdded { @@ -1109,7 +1310,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene ] ] as [String: Any] - destroyPIPController() + performCleanupOnLeavingRoom() eventSink?(data) } @@ -1149,7 +1350,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene "local_video_stats": HMSStatsExtension.toDictionary(localVideoStats), "track": HMSTrackExtension.toDictionary(track), "peer": HMSPeerExtension.toDictionary(peer) - ] + ] as [String: Any] ] as [String: Any] rtcSink?(data) @@ -1199,6 +1400,14 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene } } + public func on(sessionStoreAvailable store: HMSSessionStore) { + sessionStore = store + + let data = ["event_name": "on_session_store_available"] + + eventSink?(data) + } + // MARK: - Helper Functions private func getConfig(from arguments: [AnyHashable: Any]) -> HMSConfig? { @@ -1276,11 +1485,16 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene eventSink?(data) } - func destroyPIPController() { + private func destroyPIPController() { if #available(iOS 15.0, *) { if HMSPIPAction.pipController != nil { HMSPIPAction.disposePIP(nil) } } } + + private func performCleanupOnLeavingRoom() { + destroyPIPController() + removeAllKeyChangeListener() + } } diff --git a/ios/Classes/PiPView.swift b/ios/Classes/Views/HMSPiPView.swift similarity index 98% rename from ios/Classes/PiPView.swift rename to ios/Classes/Views/HMSPiPView.swift index 2edce07ef..fcb6b439a 100644 --- a/ios/Classes/PiPView.swift +++ b/ios/Classes/Views/HMSPiPView.swift @@ -1,5 +1,5 @@ // -// PiPView.swift +// HMSPiPView.swift // HMSSDK // // Copyright © 2022 100ms. All rights reserved. @@ -9,7 +9,7 @@ import SwiftUI import HMSSDK @available(iOS 15.0, *) -struct PiPView: View { +struct HMSPiPView: View { @ObservedObject var model: PiPModel diff --git a/lib/assets/sdk-versions.json b/lib/assets/sdk-versions.json index 435740882..1c2f57684 100644 --- a/lib/assets/sdk-versions.json +++ b/lib/assets/sdk-versions.json @@ -1,6 +1,6 @@ { - "flutter": "1.5.0", - "ios": "0.9.2", + "flutter": "1.6.0", + "ios": "0.9.3", "iOSBroadcastExtension": "0.0.9", - "android": "2.6.1" + "android": "2.6.2" } diff --git a/lib/hmssdk_flutter.dart b/lib/hmssdk_flutter.dart index 3ac1cb5db..7256839ea 100644 --- a/lib/hmssdk_flutter.dart +++ b/lib/hmssdk_flutter.dart @@ -20,6 +20,7 @@ export 'src/enum/hms_stats_listener_method.dart'; export 'src/enum/hms_track_init_state.dart'; export 'src/enum/hms_Quality_limitation_reason.dart'; export 'src/enum/hms_simulcast_layer.dart'; +export 'src/enum/hms_audio_mode.dart'; //EXCEPTIONS export 'src/exceptions/hms_exception.dart'; export 'src/exceptions/hms_in_sufficient_data.dart'; @@ -89,3 +90,5 @@ export 'src/model/hms_ios_pip_controller.dart'; export 'src/model/hms_ios_screenshare_config.dart'; export 'src/model/hms_log_list.dart'; export 'src/model/hms_camera_controls.dart'; +export 'src/model/hms_session_store.dart'; +export 'src/model/hms_key_change_listener.dart'; diff --git a/lib/src/common/platform_methods.dart b/lib/src/common/platform_methods.dart index c47f3bd9e..c505e8258 100644 --- a/lib/src/common/platform_methods.dart +++ b/lib/src/common/platform_methods.dart @@ -169,7 +169,11 @@ enum PlatformMethod { getAuthTokenByRoomCode, captureImageAtMaxSupportedResolution, isFlashSupported, - toggleFlash + toggleFlash, + getSessionMetadataForKey, + setSessionMetadataForKey, + addKeyChangeListener, + removeKeyChangeListener } extension PlatformMethodValues on PlatformMethod { @@ -409,6 +413,14 @@ extension PlatformMethodValues on PlatformMethod { return "is_flash_supported"; case PlatformMethod.toggleFlash: return "toggle_flash"; + case PlatformMethod.getSessionMetadataForKey: + return "get_session_metadata_for_key"; + case PlatformMethod.setSessionMetadataForKey: + return "set_session_metadata_for_key"; + case PlatformMethod.addKeyChangeListener: + return "add_key_change_listener"; + case PlatformMethod.removeKeyChangeListener: + return "remove_key_change_listener"; default: return 'unknown'; } @@ -650,6 +662,14 @@ extension PlatformMethodValues on PlatformMethod { return PlatformMethod.isFlashSupported; case "toggle_flash": return PlatformMethod.toggleFlash; + case "get_session_metadata_for_key": + return PlatformMethod.getSessionMetadataForKey; + case "set_session_metadata_for_key": + return PlatformMethod.setSessionMetadataForKey; + case "add_key_change_listener": + return PlatformMethod.addKeyChangeListener; + case "remove_key_change_listener": + return PlatformMethod.removeKeyChangeListener; default: return PlatformMethod.unknown; } diff --git a/lib/src/enum/hms_action_result_listener_method.dart b/lib/src/enum/hms_action_result_listener_method.dart index ea103ab95..b3b9f935f 100644 --- a/lib/src/enum/hms_action_result_listener_method.dart +++ b/lib/src/enum/hms_action_result_listener_method.dart @@ -21,8 +21,10 @@ enum HMSActionResultListenerMethod { stopScreenShare, startAudioShare, stopAudioShare, + @Deprecated('use [setSessionMetadataForKey]') setSessionMetadata, switchCamera, changeRoleOfPeersWithRoles, + setSessionMetadataForKey, unknown } diff --git a/lib/src/enum/hms_audio_mode.dart b/lib/src/enum/hms_audio_mode.dart new file mode 100644 index 000000000..1471115f9 --- /dev/null +++ b/lib/src/enum/hms_audio_mode.dart @@ -0,0 +1,25 @@ +enum HMSAudioMode { VOICE, MUSIC } + +extension HMSAudioModeValues on HMSAudioMode { + static HMSAudioMode getAudioModeFromName(String name) { + switch (name) { + case "voice": + return HMSAudioMode.VOICE; + case "music": + return HMSAudioMode.MUSIC; + default: + return HMSAudioMode.VOICE; + } + } + + static String getNameFromHMSAudioMode(HMSAudioMode mode) { + switch (mode) { + case HMSAudioMode.VOICE: + return "voice"; + case HMSAudioMode.MUSIC: + return "music"; + default: + return "voice"; + } + } +} diff --git a/lib/src/enum/hms_key_change_listener_method.dart b/lib/src/enum/hms_key_change_listener_method.dart new file mode 100644 index 000000000..090069072 --- /dev/null +++ b/lib/src/enum/hms_key_change_listener_method.dart @@ -0,0 +1,13 @@ +/// Enum for key change listener methods +enum HMSKeyChangeListenerMethod { onKeyChanged, unknown } + +extension HMSKeyChangeListenerMethodValues on HMSKeyChangeListenerMethod { + static HMSKeyChangeListenerMethod getMethodFromName(String name) { + switch (name) { + case "on_key_changed": + return HMSKeyChangeListenerMethod.onKeyChanged; + default: + return HMSKeyChangeListenerMethod.unknown; + } + } +} diff --git a/lib/src/enum/hms_update_listener_method.dart b/lib/src/enum/hms_update_listener_method.dart index c70ddd0bd..1cac55dfb 100644 --- a/lib/src/enum/hms_update_listener_method.dart +++ b/lib/src/enum/hms_update_listener_method.dart @@ -12,6 +12,7 @@ enum HMSUpdateListenerMethod { onChangeTrackStateRequest, onRemovedFromRoom, onAudioDeviceChanged, + onSessionStoreAvailable, unknown } @@ -44,6 +45,8 @@ extension HMSUpdateListenerMethodValues on HMSUpdateListenerMethod { return HMSUpdateListenerMethod.onRemovedFromRoom; case 'on_audio_device_changed': return HMSUpdateListenerMethod.onAudioDeviceChanged; + case 'on_session_store_available': + return HMSUpdateListenerMethod.onSessionStoreAvailable; default: return HMSUpdateListenerMethod.unknown; } diff --git a/lib/src/hmssdk.dart b/lib/src/hmssdk.dart index 13bae2e33..1d09cf9d1 100644 --- a/lib/src/hmssdk.dart +++ b/lib/src/hmssdk.dart @@ -1235,6 +1235,7 @@ class HMSSDK { /// **hmsActionResultListener** - [hmsActionResultListener] is a callback instance on which [HMSActionResultListener.onSuccess] and [HMSActionResultListener.onException] will be called. /// ///Refer [session metadata guide here](https://www.100ms.live/docs/flutter/v2/features/session-metadata) + @Deprecated('Use [setSessionMetadataForKey]') Future setSessionMetadata( {required String? metadata, HMSActionResultListener? hmsActionResultListener}) async { @@ -1260,6 +1261,7 @@ class HMSSDK { ///Method to fetch the latest metadata from the server and returns it /// ///Refer [session metadata guide here](https://www.100ms.live/docs/flutter/v2/features/session-metadata) + @Deprecated('Use [getSessionMetadataForKey]') Future getSessionMetadata() async { var result = await PlatformService.invokeMethod(PlatformMethod.getSessionMetadata); diff --git a/lib/src/model/hms_audio_file_player_node.dart b/lib/src/model/hms_audio_file_player_node.dart index c7fcecc78..ba6f62e05 100644 --- a/lib/src/model/hms_audio_file_player_node.dart +++ b/lib/src/model/hms_audio_file_player_node.dart @@ -45,18 +45,18 @@ class HMSAudioFilePlayerNode extends HMSAudioNode { "loops": loop, "interrupts": interrupts }); - if (result == null) { + if (result["success"]) { return null; } else { - return HMSException.fromMap(result["error"]); + return HMSException.fromMap(result["data"]["error"]); } } ///The [pause] function on [HMSAudioFilePlayerNode] to pause a file on a local device in a meeting room. /// ///Refer [Audio sharing in iOS guide here](https://www.100ms.live/docs/flutter/v2/features/audio_sharing#i-os-setup) - void pause() { - PlatformService.invokeMethod(PlatformMethod.pauseAudioShare, + Future pause() async { + await PlatformService.invokeMethod(PlatformMethod.pauseAudioShare, arguments: {"name": methodName}); } @@ -64,18 +64,18 @@ class HMSAudioFilePlayerNode extends HMSAudioNode { var result = await PlatformService.invokeMethod( PlatformMethod.resumeAudioShare, arguments: {"name": methodName}); - if (result == null) { + if (result["success"]) { return null; } else { - return HMSException.fromMap(result["error"]); + return HMSException.fromMap(result["data"]["error"]); } } ///The [stop] function on [HMSAudioFilePlayerNode] to stop a file on a local device in a meeting room. /// ///Refer [Audio sharing in iOS guide here](https://www.100ms.live/docs/flutter/v2/features/audio_sharing#i-os-setup) - void stop() { - PlatformService.invokeMethod(PlatformMethod.stopAudioShare, + Future stop() async { + await PlatformService.invokeMethod(PlatformMethod.stopAudioShare, arguments: {"name": methodName}); } @@ -86,8 +86,8 @@ class HMSAudioFilePlayerNode extends HMSAudioNode { var result = await PlatformService.invokeMethod( PlatformMethod.audioSharePlaying, arguments: {"name": methodName}); - if (result != null) { - return result["is_playing"]; + if (result["success"]) { + return result["data"]["is_playing"]; } return false; } @@ -95,12 +95,12 @@ class HMSAudioFilePlayerNode extends HMSAudioNode { ///The [currentDuration] function on [HMSAudioFilePlayerNode] will return the current duration of audio shared. /// ///Refer [Audio sharing in iOS guide here](https://www.100ms.live/docs/flutter/v2/features/audio_sharing#i-os-setup) - Future currentDuration() async { + Future currentDuration() async { var result = await PlatformService.invokeMethod( PlatformMethod.audioShareCurrentTime, arguments: {"name": methodName}); - if (result != null) { - return result["current_duration"]; + if (result["success"]) { + return result["data"]["current_duration"]; } return null; } @@ -108,12 +108,12 @@ class HMSAudioFilePlayerNode extends HMSAudioNode { ///The [duration] function on [HMSAudioFilePlayerNode] will return the total duration of audio shared. /// ///Refer [Audio sharing in iOS guide here](https://www.100ms.live/docs/flutter/v2/features/audio_sharing#i-os-setup) - Future duration() async { + Future duration() async { var result = await PlatformService.invokeMethod( PlatformMethod.audioShareDuration, arguments: {"name": methodName}); - if (result != null) { - return result["duration"]; + if (result["success"]) { + return result["data"]["duration"]; } return null; } diff --git a/lib/src/model/hms_audio_track_setting.dart b/lib/src/model/hms_audio_track_setting.dart index 9bfb49fa4..428c85582 100644 --- a/lib/src/model/hms_audio_track_setting.dart +++ b/lib/src/model/hms_audio_track_setting.dart @@ -12,18 +12,26 @@ class HMSAudioTrackSetting { /// The default is on if it is supported. /// Please note that on some devices the hardware wrongly reports the HW echo canceler to be present whereas it does not work /// In such as application need to set this to false, so that SW echo canceler is picked up. + /// Refer: Read more about useHardwareAcousticEchoCanceler [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/track/set-track-settings#usehardwareacousticechocanceler) final bool? useHardwareAcousticEchoCanceler; ///[audioSource] only for iOS. Used for audioSharing use cases. + ///Refer: Read more about audio source [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/local-audio-share#i-os-setup) HMSAudioMixerSource? audioSource; ///[trackInitialState] property to set the initial state of the audio track i.e Mute/Unmute.By default it's unmuted. + ///Refer: Read more about trackInitialState [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/set-up-video-conferencing/join#join-with-muted-audio-video) final HMSTrackInitState? trackInitialState; + ///[audioMode] property to set the audio mode of audio track i.e voice or music mode + ///Refer: Read more about audio mode [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/configure-your-device/microphone/music-mode) + final HMSAudioMode? audioMode; + HMSAudioTrackSetting( {this.useHardwareAcousticEchoCanceler, this.audioSource, - this.trackInitialState = HMSTrackInitState.UNMUTED}); + this.trackInitialState = HMSTrackInitState.UNMUTED, + this.audioMode}); factory HMSAudioTrackSetting.fromMap(Map map) { List nodeList = []; @@ -40,6 +48,10 @@ class HMSAudioTrackSetting { audioMixerSource = HMSAudioMixerSource(node: nodeList); } HMSAudioMixerSource(node: nodeList); + HMSAudioMode? audioMode; + if ((map.containsKey("audio_mode")) && (map["audio_mode"] != null)) { + audioMode = HMSAudioModeValues.getAudioModeFromName(map["audio_mode"]); + } return HMSAudioTrackSetting( useHardwareAcousticEchoCanceler: map['user_hardware_acoustic_echo_canceler'] ?? null, @@ -47,7 +59,8 @@ class HMSAudioTrackSetting { trackInitialState: map.containsKey("track_initial_state") ? HMSTrackInitStateValue.getHMSTrackInitStateFromName( map['track_initial_state']) - : HMSTrackInitState.UNMUTED); + : HMSTrackInitState.UNMUTED, + audioMode: audioMode); } Map toMap() { @@ -56,7 +69,10 @@ class HMSAudioTrackSetting { 'audio_source': audioSource?.toList(), 'track_initial_state': HMSTrackInitStateValue.getValuefromHMSTrackInitState( - trackInitialState) + trackInitialState), + 'audio_mode': (audioMode != null) + ? HMSAudioModeValues.getNameFromHMSAudioMode(audioMode!) + : null }; } } diff --git a/lib/src/model/hms_camera_controls.dart b/lib/src/model/hms_camera_controls.dart index 1528fc218..ed08cf467 100644 --- a/lib/src/model/hms_camera_controls.dart +++ b/lib/src/model/hms_camera_controls.dart @@ -3,15 +3,21 @@ import 'package:hmssdk_flutter/src/exceptions/hms_exception.dart'; import 'package:hmssdk_flutter/src/service/platform_service.dart'; ///[HMSCameraControls] contains the common camera functions for android and iOS +/// +///Refer [camera controls guide here](https://www.100ms.live/docs/flutter/v2/how-to-guides/configure-your-device/camera/camera-controls) class HMSCameraControls { ///[captureImageAtMaxSupportedResolution] is used to capture images at the original camera ///resolution. - ///[withFlash] parameter turns flash ON if set to TRUE. Default value is FALSE + /// + /// **Parameters**: + /// + /// **withFlash** - parameter turns flash ON if set to TRUE. Default value is FALSE /// ///Note: [withFlash] only works if current facing camera supports flash. If it doesn't support flash /// then image will be captured without flash even if [withFlash] is set as TRUE /// To avoid this consider checking the flash capabilities using [isFlashSupported] method /// before calling [captureImageAtMaxSupportedResolution] method + ///Refer: Read more about captureImageAtMaxSupportedResolution [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/configure-your-device/camera/camera-controls#capture-at-the-highest-resolution-offered-by-the-camera) static Future captureImageAtMaxSupportedResolution( {bool withFlash = false}) async { var result = await PlatformService.invokeMethod( @@ -26,6 +32,8 @@ class HMSCameraControls { ///[isFlashSupported] is used to check whether the current facing camera supports /// flash or not. + /// + ///Refer: Read more about isFlashSupported [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/configure-your-device/camera/camera-controls#check-if-flash-feature-is-available) static Future isFlashSupported() async { var result = await PlatformService.invokeMethod(PlatformMethod.isFlashSupported); @@ -44,6 +52,7 @@ class HMSCameraControls { /// ///Note: [toggleFlash] only works if camera is turned ON /// i.e. video is unmuted. + ///Read more about toggleFlash [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/configure-your-device/camera/camera-controls#toggle-flash) static Future toggleFlash() async { var result = await PlatformService.invokeMethod(PlatformMethod.toggleFlash); if (result["success"]) { diff --git a/lib/src/model/hms_key_change_listener.dart b/lib/src/model/hms_key_change_listener.dart new file mode 100644 index 000000000..89bf968b2 --- /dev/null +++ b/lib/src/model/hms_key_change_listener.dart @@ -0,0 +1,17 @@ +/// 100ms HMSKeyChangeListener +/// +/// 100ms SDK provides callback whenever a key in session metadata is changed +/// +/// Implement this listener in the class wherever you wish to listen to changes to those keys +/// +/// Remember to call HMSSessionStore's [addKeyChangeListener] method with corresponding keys to get the updates +abstract class HMSKeyChangeListener { + ///This gets called whenever data corresponding to a key is changed + /// + ///This also gets called when key is set for the first time or set to null + /// + /// - Parameters: + /// - key: the key whose metadata is changed + /// - value: new value of the corresponding key + void onKeyChanged({required String key, required String? value}) {} +} diff --git a/lib/src/model/hms_key_change_observer.dart b/lib/src/model/hms_key_change_observer.dart new file mode 100644 index 000000000..5e809fc94 --- /dev/null +++ b/lib/src/model/hms_key_change_observer.dart @@ -0,0 +1,8 @@ +import 'package:hmssdk_flutter/src/model/hms_key_change_listener.dart'; + +class HMSKeyChangeObserver { + final String uid; + final HMSKeyChangeListener hmsKeyChangeListener; + + HMSKeyChangeObserver({required this.uid, required this.hmsKeyChangeListener}); +} diff --git a/lib/src/model/hms_session_store.dart b/lib/src/model/hms_session_store.dart new file mode 100644 index 000000000..0c8f2f380 --- /dev/null +++ b/lib/src/model/hms_session_store.dart @@ -0,0 +1,101 @@ +import 'package:hmssdk_flutter/hmssdk_flutter.dart'; +import 'package:hmssdk_flutter/src/model/hms_key_change_observer.dart'; +import 'package:hmssdk_flutter/src/service/platform_service.dart'; + +/// [HMSSessionStore] class takes care of the session metadata for a session +/// +/// HMSUpdateListener's [onSessionStoreAvailable] method returns a object of [HMSSessionStore] +/// which can be used to call session metadata methods +/// +class HMSSessionStore { + ///[addKeyChangeListener] method is used to attach listener to particular keys + /// + /// **Parameters**: + /// + /// **keys** A list of keys to be listened + /// + /// **hmsKeyChangeListener** An instance of [HMSKeyChangeListener] implemented in the class where changes needs to be listened + /// + ///Refer: Read more about addKeyChangeListener [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/room/session-store#retrieve-the-current-value-and-receive-updates) + Future addKeyChangeListener( + {required List keys, + required HMSKeyChangeListener hmsKeyChangeListener}) async { + String uid = DateTime.now().millisecondsSinceEpoch.toString(); + dynamic result = await PlatformService.invokeMethod( + PlatformMethod.addKeyChangeListener, + arguments: {"keys": keys, "uid": uid}); + if (result == null) { + PlatformService.addKeyChangeObserver(HMSKeyChangeObserver( + uid: uid, hmsKeyChangeListener: hmsKeyChangeListener)); + return null; + } else { + return HMSException.fromMap(result["error"]); + } + } + + ///[removeKeyChangeListener] method is used to remove a key change listener + /// + /// **Parameters**: + /// + /// **hmsKeyChangeListener** An instance of [HMSKeyChangeListener] which was attaced earlier in [addKeyChangeListener] + /// + ///Refer: Read more about removeKeyChangeListener [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/room/session-store#stop-listening-to-updates-for-keys) + Future removeKeyChangeListener( + {required HMSKeyChangeListener hmsKeyChangeListener}) async { + return PlatformService.removeKeyChangeObserver(hmsKeyChangeListener); + } + + ///[getSessionMetadataForKey] method is used to get metadata corresponding to the given key. + /// If there is no data corresponding to the given key it returns null. + /// + /// **Parameters**: + /// + /// **key** key for which metadata is required + /// + ///Refer: Read more about getSessionMetadataForKey [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/room/session-store#retrieve-the-current-value-once) + Future getSessionMetadataForKey({required String key}) async { + dynamic result = await PlatformService.invokeMethod( + PlatformMethod.getSessionMetadataForKey, + arguments: {"key": key}); + if (result["success"]) { + return result["data"]; + } else { + return HMSException.fromMap(result["data"]["error"]); + } + } + + ///[setSessionMetadataForKey] is used to set metadata for a particular key + /// + /// **Parameters**: + /// + /// **key** key for metadata needs to be set + /// + /// **data** data corresponding to the given key + /// + /// **hmsActionResultListener** [hmsActionResultListener] is a callback instance on which [HMSActionResultListener.onSuccess] and [HMSActionResultListener.onException] will be called. + /// + ///Refer: Read more about setSessionMetadataForKey [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/interact-with-room/room/session-store#setting-a-value-for-a-specific-key) + Future setSessionMetadataForKey( + {required String key, + required String? data, + HMSActionResultListener? hmsActionResultListener}) async { + Map arguments = { + "key": key, + "data": data, + }; + dynamic result = await PlatformService.invokeMethod( + PlatformMethod.setSessionMetadataForKey, + arguments: arguments); + if (hmsActionResultListener != null) { + if (result == null) { + hmsActionResultListener.onSuccess( + methodType: HMSActionResultListenerMethod.setSessionMetadataForKey, + arguments: arguments); + } else { + hmsActionResultListener.onException( + methodType: HMSActionResultListenerMethod.setSessionMetadataForKey, + hmsException: HMSException.fromMap(result["error"])); + } + } + } +} diff --git a/lib/src/model/hms_update_listener.dart b/lib/src/model/hms_update_listener.dart index d9d6a3ca1..9baf13a25 100644 --- a/lib/src/model/hms_update_listener.dart +++ b/lib/src/model/hms_update_listener.dart @@ -99,4 +99,10 @@ abstract class HMSUpdateListener { void onAudioDeviceChanged( {HMSAudioDevice? currentAudioDevice, List? availableAudioDevice}); + + /// Whenever a user joins a room [onSessionStoreAvailable] is fired to get an instance of [HMSSessionStore] + /// which can be used to perform session metadata operations + /// - Parameters: + /// - hmsSessionStore: An instance of HMSSessionStore which will be used to call session metadata methods + void onSessionStoreAvailable({HMSSessionStore? hmsSessionStore}); } diff --git a/lib/src/model/platform_method_response.dart b/lib/src/model/platform_method_response.dart index 289fde41f..f53865bb5 100644 --- a/lib/src/model/platform_method_response.dart +++ b/lib/src/model/platform_method_response.dart @@ -1,5 +1,6 @@ // Project imports: import 'package:hmssdk_flutter/hmssdk_flutter.dart'; +import 'package:hmssdk_flutter/src/enum/hms_key_change_listener_method.dart'; import 'package:hmssdk_flutter/src/enum/hms_logs_update_listener.dart'; ///PlatformMethodResponse contains all the responses sent back from the platform @@ -59,3 +60,14 @@ class HMSStatsListenerMethodResponse { HMSStatsListenerMethodResponse( {required this.method, required this.data, required this.response}); } + +///HMSKeyChangeListenerMethodResponse contains all the responses sent from the session store channel +/// +/// Checkout different responses in [HMSKeyChangeListenerMethod] enum +class HMSKeyChangeListenerMethodResponse { + final HMSKeyChangeListenerMethod method; + final Map data; + + HMSKeyChangeListenerMethodResponse( + {required this.method, required this.data}); +} diff --git a/lib/src/service/platform_service.dart b/lib/src/service/platform_service.dart index fabc23c1e..f7f292235 100644 --- a/lib/src/service/platform_service.dart +++ b/lib/src/service/platform_service.dart @@ -13,7 +13,9 @@ import 'dart:async'; import 'package:flutter/services.dart'; // Project imports: import 'package:hmssdk_flutter/hmssdk_flutter.dart'; +import 'package:hmssdk_flutter/src/enum/hms_key_change_listener_method.dart'; import 'package:hmssdk_flutter/src/enum/hms_logs_update_listener.dart'; +import 'package:hmssdk_flutter/src/model/hms_key_change_observer.dart'; class PlatformService { ///used to pass data to platform using methods @@ -34,6 +36,10 @@ class PlatformService { static const EventChannel _rtcStatsChannel = const EventChannel("rtc_event_channel"); + ///used to get stream of session store changes + static const EventChannel _sessionStoreChannel = + const EventChannel("session_event_channel"); + ///add meeting listeners. static List updateListeners = []; @@ -42,6 +48,8 @@ class PlatformService { ///add preview listeners. static List previewListeners = []; + static List keyChangeObservers = []; + ///List for event Listener static List statsListeners = []; static bool isStartedListening = false; @@ -92,6 +100,33 @@ class PlatformService { logsListeners.remove(hmsLogListener); } + static void addKeyChangeObserver(HMSKeyChangeObserver hmsKeyChangeObserver) { + keyChangeObservers.add(hmsKeyChangeObserver); + } + + static Future removeKeyChangeObserver( + HMSKeyChangeListener hmsKeyChangeListener) async { + int index = keyChangeObservers.indexWhere((observer) => + observer.hmsKeyChangeListener.hashCode == + hmsKeyChangeListener.hashCode); + if (index != -1) { + var result = await invokeMethod(PlatformMethod.removeKeyChangeListener, + arguments: {"uid": keyChangeObservers[index].uid}); + if (result["success"]) { + keyChangeObservers.removeAt(index); + return null; + } else { + return HMSException.fromMap(result["data"]["error"]); + } + } else { + return HMSException( + message: "hmsKeyChangeListener not found", + description: "No listener found to remove", + action: "Listener Error", + isTerminal: true); + } + } + ///used to invoke different methods at platform side and returns something but not neccessarily static Future invokeMethod(PlatformMethod method, {Map? arguments}) async { @@ -230,6 +265,10 @@ class PlatformService { }); break; + case HMSUpdateListenerMethod.onSessionStoreAvailable: + notifyUpdateListeners(method, {}); + break; + case HMSUpdateListenerMethod.unknown: break; } @@ -421,6 +460,24 @@ class PlatformService { break; } }); + + _sessionStoreChannel + .receiveBroadcastStream({'name': 'session_store'}).map((event) { + HMSKeyChangeListenerMethod method = + HMSKeyChangeListenerMethodValues.getMethodFromName( + event['event_name']); + Map data = event['data']; + return HMSKeyChangeListenerMethodResponse(method: method, data: data); + }).listen((event) { + HMSKeyChangeListenerMethod method = event.method; + switch (method) { + case HMSKeyChangeListenerMethod.onKeyChanged: + notifySessionStoreListeners(method, event.data); + break; + case HMSKeyChangeListenerMethod.unknown: + break; + } + }); } static void notifyLogsUpdateListeners( @@ -571,8 +628,30 @@ class PlatformService { availableAudioDevice: arguments["available_audio_device"])); break; + case HMSUpdateListenerMethod.onSessionStoreAvailable: + updateListeners.forEach((e) => + e.onSessionStoreAvailable(hmsSessionStore: HMSSessionStore())); + break; + case HMSUpdateListenerMethod.unknown: break; } } + + static void notifySessionStoreListeners( + HMSKeyChangeListenerMethod method, Map arguments) { + switch (method) { + case HMSKeyChangeListenerMethod.onKeyChanged: + int index = keyChangeObservers + .indexWhere((observer) => observer.uid == arguments["uid"]); + if (index != -1) { + keyChangeObservers[index] + .hmsKeyChangeListener + .onKeyChanged(key: arguments["key"], value: arguments["value"]); + } + break; + case HMSKeyChangeListenerMethod.unknown: + break; + } + } } diff --git a/pubspec.yaml b/pubspec.yaml index 75e49bbc1..76beae5ba 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,10 +1,10 @@ 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.5.0 +version: 1.6.0 homepage: https://www.100ms.live/ repository: https://github.com/100mslive/100ms-flutter issue_tracker: https://github.com/100mslive/100ms-flutter/issues -documentation: https://www.100ms.live/docs/flutter/v2/get-started/quickstart +documentation: https://www.100ms.live/docs environment: sdk: ">=2.12.0 <3.0.0" diff --git a/sample apps/bloc/pubspec.lock b/sample apps/bloc/pubspec.lock index 1ec2deedf..212a31894 100644 --- a/sample apps/bloc/pubspec.lock +++ b/sample apps/bloc/pubspec.lock @@ -5,63 +5,72 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" bloc: dependency: "direct main" description: name: bloc - url: "https://pub.dartlang.org" + sha256: "318e6cc6803d93b8d2de5f580e452ca565bcaa44f724d5156c71961426b88e03" + url: "https://pub.dev" source: hosted version: "8.0.3" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" equatable: dependency: "direct main" description: name: equatable - url: "https://pub.dartlang.org" + sha256: c6094fd1efad3046334a9c40bee022147e55c25401ccd89b94e373e3edadd375 + url: "https://pub.dev" source: hosted version: "2.0.3" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" flutter: @@ -73,14 +82,16 @@ packages: dependency: "direct main" description: name: flutter_bloc - url: "https://pub.dartlang.org" + sha256: "7b84d9777db3e30a5051c6718331be57e4cfc0c2424be82ac1771392cad7dbe8" + url: "https://pub.dev" source: hosted version: "8.0.1" flutter_lints: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_test: @@ -92,7 +103,8 @@ packages: dependency: "direct main" description: name: focus_detector - url: "https://pub.dartlang.org" + sha256: "05e32d9dd378cd54f1a3f9ce813c05156f28eb83f8e68f5bf1a37e9cdb21af1c" + url: "https://pub.dev" source: hosted version: "2.0.1" hmssdk_flutter: @@ -101,117 +113,141 @@ packages: path: "../.." relative: true source: path - version: "0.7.6" + version: "1.6.0" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "2ed163531e071c2c6b7c659635112f24cb64ecbebf6af46b550d536c0b1aa112" + url: "https://pub.dev" source: hosted version: "0.13.4" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: db3060f22889f3d9d55f6a217565486737037eec3609f7f3eca4d0c67ee0d8a0 + url: "https://pub.dev" source: hosted version: "4.0.1" + js: + dependency: transitive + description: + name: js + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" + source: hosted + version: "0.6.5" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + url: "https://pub.dev" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" source: hosted version: "1.0.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" permission_handler: dependency: "direct main" description: name: permission_handler - url: "https://pub.dartlang.org" + sha256: "5749ebeb7ec0c3865ea17e3eb337174b87747be816dab582c551e1aff6f6bbf3" + url: "https://pub.dev" source: hosted version: "9.2.0" permission_handler_android: dependency: transitive description: name: permission_handler_android - url: "https://pub.dartlang.org" + sha256: a512e0fa8abcb0659d938ec2df93a70eb1df1fdea5fdc6d79a866bfd858a28fc + url: "https://pub.dev" source: hosted version: "9.0.2+1" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - url: "https://pub.dartlang.org" + sha256: "6367799be76d1fe70ffe2df7f025abfe28818b450f550621778995badbebf519" + url: "https://pub.dev" source: hosted version: "9.0.4" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - url: "https://pub.dartlang.org" + sha256: ca16451bfdc6d26693d10b37b2d81370bdf3f0318422f3eecfd6004f5bd7d21f + url: "https://pub.dev" source: hosted version: "3.7.0" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - url: "https://pub.dartlang.org" + sha256: "40ad5ab4d3c65d75c7f3a069065c77503aae19a1cf01ba246d43489e14f1b90c" + url: "https://pub.dev" source: hosted version: "0.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: "075f927ebbab4262ace8d0b283929ac5410c0ac4e7fc123c76429564facfb757" + url: "https://pub.dev" source: hosted version: "2.1.2" provider: dependency: transitive description: name: provider - url: "https://pub.dartlang.org" + sha256: "8d7d4c2df46d6a6270a4e10404bfecb18a937e3e00f710c260d0a10415ce6b7b" + url: "https://pub.dev" source: hosted version: "6.0.3" rxdart: dependency: "direct main" description: name: rxdart - url: "https://pub.dartlang.org" + sha256: "933db29250b286ecfe08a552f991f0e9f245f3f8ba1e5fb37f2f55d1f82888cb" + url: "https://pub.dev" source: hosted version: "0.27.4" sky_engine: @@ -223,65 +259,74 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + url: "https://pub.dev" source: hosted version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" visibility_detector: dependency: transitive description: name: visibility_detector - url: "https://pub.dartlang.org" + sha256: ec932527913f32f65aa01d3a393504240b9e9021ecc77123f017755605e48832 + url: "https://pub.dev" source: hosted version: "0.2.2" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.18.0 <3.0.0" flutter: ">=2.8.0" diff --git a/sample apps/flutter-hls-quickstart/lib/main.dart b/sample apps/flutter-hls-quickstart/lib/main.dart index 0b4648056..5b3c09152 100644 --- a/sample apps/flutter-hls-quickstart/lib/main.dart +++ b/sample apps/flutter-hls-quickstart/lib/main.dart @@ -81,8 +81,8 @@ class _MyHomePageState extends State { context, CupertinoPageRoute( builder: (_) => MeetingPage( - authToken:"ENTER YOUR AUTH TOKEN HERE", - /* + authToken: "ENTER YOUR AUTH TOKEN HERE", + /* * Paste Auth Token for your Room from 100ms Dashboard here * https://dashboard.100ms.live/ */ @@ -113,8 +113,8 @@ class _MyHomePageState extends State { context, CupertinoPageRoute( builder: (_) => HLSViewerPage( - authToken:"ENTER YOUR AUTH TOKEN HERE", - /* + authToken: "ENTER YOUR AUTH TOKEN HERE", + /* * Paste Auth Token for your Room from 100ms Dashboard here * https://dashboard.100ms.live/ */ diff --git a/sample apps/getx/pubspec.lock b/sample apps/getx/pubspec.lock index bc3973dc2..e6166d449 100644 --- a/sample apps/getx/pubspec.lock +++ b/sample apps/getx/pubspec.lock @@ -5,58 +5,66 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" source: hosted version: "1.3.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.17.0" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -66,7 +74,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_test: @@ -78,112 +87,136 @@ packages: dependency: "direct main" description: name: focus_detector - url: "https://pub.dartlang.org" + sha256: "05e32d9dd378cd54f1a3f9ce813c05156f28eb83f8e68f5bf1a37e9cdb21af1c" + url: "https://pub.dev" source: hosted version: "2.0.1" get: dependency: "direct main" description: name: get - url: "https://pub.dartlang.org" + sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a" + url: "https://pub.dev" source: hosted - version: "4.6.1" + version: "4.6.5" hmssdk_flutter: dependency: "direct main" description: - path: "../.." - relative: true - source: path - version: "0.7.4" + name: hmssdk_flutter + sha256: "1323678b739bb0768adea396d618eed839c3c2c15eb135166988a06a92562baa" + url: "https://pub.dev" + source: hosted + version: "1.3.2" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted - version: "0.13.4" + version: "0.13.5" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 + url: "https://pub.dev" source: hosted version: "4.0.0" + js: + dependency: transitive + description: + name: js + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" + source: hosted + version: "0.6.5" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + url: "https://pub.dev" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.3" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.8.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.8.2" permission_handler: dependency: "direct main" description: name: permission_handler - url: "https://pub.dartlang.org" + sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" + url: "https://pub.dev" source: hosted - version: "9.2.0" + version: "10.2.0" permission_handler_android: dependency: transitive description: name: permission_handler_android - url: "https://pub.dartlang.org" + sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2" + url: "https://pub.dev" source: hosted - version: "9.0.2+1" + version: "10.2.0" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - url: "https://pub.dartlang.org" + sha256: ee96ac32f5a8e6f80756e25b25b9f8e535816c8e6665a96b6d70681f8c4f7e85 + url: "https://pub.dev" source: hosted - version: "9.0.4" + version: "9.0.8" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - url: "https://pub.dartlang.org" + sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + url: "https://pub.dev" source: hosted - version: "3.7.0" + version: "3.9.0" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - url: "https://pub.dartlang.org" + sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b + url: "https://pub.dev" source: hosted - version: "0.1.0" + version: "0.1.2" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: "075f927ebbab4262ace8d0b283929ac5410c0ac4e7fc123c76429564facfb757" + url: "https://pub.dev" source: hosted version: "2.1.2" sky_engine: @@ -195,65 +228,74 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.8" + version: "0.4.16" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + url: "https://pub.dev" source: hosted version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" visibility_detector: dependency: transitive description: name: visibility_detector - url: "https://pub.dartlang.org" + sha256: ec932527913f32f65aa01d3a393504240b9e9021ecc77123f017755605e48832 + url: "https://pub.dev" source: hosted version: "0.2.2" sdks: - dart: ">=2.16.1 <3.0.0" + dart: ">=2.18.0 <3.0.0" flutter: ">=2.8.0" diff --git a/sample apps/mobx/pubspec.lock b/sample apps/mobx/pubspec.lock index c39e1b1d7..93d0a01c7 100644 --- a/sample apps/mobx/pubspec.lock +++ b/sample apps/mobx/pubspec.lock @@ -5,175 +5,200 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: "3444216bfd127af50bbe4862d8843ed44db946dd933554f0d7285e89f10e28ac" + url: "https://pub.dev" source: hosted version: "50.0.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: "68796c31f510c8455a06fed75fc97d8e5ad04d324a830322ab3efc9feb6201c1" + url: "https://pub.dev" source: hosted version: "5.2.0" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 + url: "https://pub.dev" source: hosted version: "2.3.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + url: "https://pub.dev" source: hosted version: "2.3.1" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" source: hosted version: "1.1.1" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf" + url: "https://pub.dev" source: hosted version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + sha256: "7c35a3a7868626257d8aee47b51c26b9dba11eaddf3431117ed2744951416aab" + url: "https://pub.dev" source: hosted version: "2.1.0" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + url: "https://pub.dev" source: hosted version: "2.3.3" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292" + url: "https://pub.dev" source: hosted version: "7.2.7" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + sha256: "59e08b0079bb75f7e27392498e26339387c1089c6bd58525a14eb8508637277b" + url: "https://pub.dev" source: hosted version: "8.4.2" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted version: "1.2.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" + url: "https://pub.dev" source: hosted version: "2.0.2" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" + url: "https://pub.dev" source: hosted version: "4.4.0" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" source: hosted version: "3.1.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" source: hosted version: "3.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: caac504f942f41dfadcf45229ce8c47065b93919a12739f20d6173a883c5ec73 + url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.2" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" + url: "https://pub.dev" source: hosted version: "2.2.4" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted version: "6.1.4" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec" + url: "https://pub.dev" source: hosted version: "1.0.1" flutter: @@ -185,14 +210,16 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_mobx: dependency: "direct main" description: name: flutter_mobx - url: "https://pub.dartlang.org" + sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e" + url: "https://pub.dev" source: hosted version: "2.0.6+5" flutter_test: @@ -200,228 +227,268 @@ packages: description: flutter source: sdk version: "0.0.0" + focus_detector: + dependency: "direct main" + description: + name: focus_detector + sha256: "05e32d9dd378cd54f1a3f9ce813c05156f28eb83f8e68f5bf1a37e9cdb21af1c" + url: "https://pub.dev" + source: hosted + version: "2.0.1" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" source: hosted version: "3.2.0" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + url: "https://pub.dev" source: hosted version: "2.1.1" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 + url: "https://pub.dev" source: hosted version: "2.2.0" hmssdk_flutter: dependency: "direct main" description: - path: "../.." - relative: true - source: path - version: "1.2.0" + name: hmssdk_flutter + sha256: "1323678b739bb0768adea396d618eed839c3c2c15eb135166988a06a92562baa" + url: "https://pub.dev" + source: hosted + version: "1.3.2" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + url: "https://pub.dev" source: hosted version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted version: "4.0.2" intl: dependency: "direct main" description: name: intl - url: "https://pub.dartlang.org" + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + url: "https://pub.dev" source: hosted version: "0.18.0" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + sha256: "0d4c73c3653ab85bf696d51a9657604c900a370549196a91f33e4c39af760852" + url: "https://pub.dev" source: hosted version: "1.0.3" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted version: "0.6.5" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: "3520fa844009431b5d4491a5a778603520cdc399ab3406332dcc50f93547258c" + url: "https://pub.dev" source: hosted version: "4.7.0" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + url: "https://pub.dev" source: hosted version: "1.0.1" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 + url: "https://pub.dev" source: hosted version: "1.1.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted version: "1.8.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: "52e38f7e1143ef39daf532117d6b8f8f617bf4bcd6044ed8c29040d20d269630" + url: "https://pub.dev" source: hosted version: "1.0.3" mobx: dependency: "direct main" description: name: mobx - url: "https://pub.dartlang.org" + sha256: "6738620307a424d2c9ad8b873f4dce391c44e9135eb4e75668ac8202fec7a9b8" + url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" mobx_codegen: dependency: "direct main" description: name: mobx_codegen - url: "https://pub.dartlang.org" + sha256: "86122e410d8ea24dda0c69adb5c2a6ccadd5ce02ad46e144764e0d0184a06181" + url: "https://pub.dev" source: hosted version: "2.1.1" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" source: hosted version: "2.1.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted version: "1.8.2" permission_handler: dependency: "direct main" description: name: permission_handler - url: "https://pub.dartlang.org" + sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" + url: "https://pub.dev" source: hosted version: "10.2.0" permission_handler_android: dependency: transitive description: name: permission_handler_android - url: "https://pub.dartlang.org" + sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2" + url: "https://pub.dev" source: hosted version: "10.2.0" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - url: "https://pub.dartlang.org" + sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163" + url: "https://pub.dev" source: hosted version: "9.0.7" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - url: "https://pub.dartlang.org" + sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + url: "https://pub.dev" source: hosted version: "3.9.0" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - url: "https://pub.dartlang.org" + sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b + url: "https://pub.dev" source: hosted version: "0.1.2" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" source: hosted version: "2.1.3" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + url: "https://pub.dev" source: hosted version: "2.1.3" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + url: "https://pub.dev" source: hosted version: "1.2.1" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + url: "https://pub.dev" source: hosted version: "1.4.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + url: "https://pub.dev" source: hosted version: "1.0.3" sky_engine: @@ -433,98 +500,120 @@ packages: dependency: transitive description: name: source_gen - url: "https://pub.dartlang.org" + sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d" + url: "https://pub.dev" source: hosted version: "1.2.6" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" source: hosted version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.4.16" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + sha256: c386d07d7f5efc613479a7c4d9d64b03710b03cfaa7e8ad5f2bfb295a1f0dfad + url: "https://pub.dev" source: hosted version: "1.0.0" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" source: hosted version: "1.3.1" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + visibility_detector: + dependency: transitive + description: + name: visibility_detector + sha256: ec932527913f32f65aa01d3a393504240b9e9021ecc77123f017755605e48832 + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "0.2.2" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + url: "https://pub.dev" source: hosted version: "1.0.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" + url: "https://pub.dev" source: hosted version: "2.2.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" source: hosted version: "3.1.1" sdks: