From 7b46746aefaade17aa0a2a06529b6dabe75778f1 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 3 Aug 2026 20:17:31 +0100 Subject: [PATCH 1/2] chore: raise minimum Flutter to 3.44 and iOS deployment target to 13.0 Two floors land in the same bump. The UIScene plugin APIs this SDK is about to adopt -- the `FlutterSceneLifeCycleDelegate` protocol and `FlutterPluginRegistrar.addSceneDelegate:` -- first shipped in Flutter 3.38, and `UIScene` itself is iOS 13+. Flutter 3.44 then made Swift Package Manager the default dependency manager rather than the opt-in experiment it had been since 3.24, and that is the floor the upcoming CocoaPods -> SwiftPM migration needs: below it a consumer would have to turn on an experimental feature by hand just to build this plugin. So raise the Flutter floor straight to 3.44 (Dart 3.12) rather than 3.38, and pull the toolchain and CI up to 3.47.3, the current stable. Because 3.44+ migrates an Xcode project to SwiftPM the first time it builds, the example and test_integration apps pin `enable-swift-package-manager: false` in their pubspecs for now. That keeps this commit a version bump and lets the migration land as its own reviewable change, which drops those pins along with the Podfiles. Alongside the version bumps: - Drop two lints the newer analyzer rejects: `package_api_docs`, which was removed, and `avoid_null_checks_in_equality_operators`, now deprecated. Drop the two redundant `!` assertions in `codec.dart` it also flags. - Silence `prefer_initializing_formals`. Dart 3.13 extended it to private fields initialised from a named parameter, but `this._field` in a named parameter list is only legal under the off-by-default `private-named-parameters` experiment, so its seven reports have no fix. - Silence `experimental_member_use` on the example app's deliberate use of the experimental `Push.reset`. - Take the `build/`, `android/` and `ios/` analyzer excludes that `flutter pub get` now writes into `analysis_options.yaml` itself, rather than have the file churn on every fetch. - Gitignore `ios/Flutter/ephemeral/`, which Flutter generates in both example projects. - Regenerating the CocoaPods projects also drops stale Firebase, Toast and nanopb framework entries from the example's `project.pbxproj`; those pods are no longer in its Podfile. Groundwork for #592 and #602. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/check.yaml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/flutter_example_app.yaml | 4 +- .github/workflows/flutter_integration.yaml | 4 +- .github/workflows/ios_unit_tests.yml | 2 +- .tool-versions | 2 +- PushNotifications.md | 2 +- README.md | 4 +- analysis_options.yaml | 10 ++- example/ios/.gitignore | 1 + example/ios/Flutter/AppFrameworkInfo.plist | 2 - example/ios/Podfile | 9 +- example/ios/Podfile.lock | 6 +- example/ios/Runner.xcodeproj/project.pbxproj | 37 +++----- .../xcshareddata/xcschemes/Runner.xcscheme | 5 +- example/ios/Runner/Info.plist | 4 + .../push_notification_service.dart | 3 + example/pubspec.lock | 20 ++--- example/pubspec.yaml | 10 ++- ios/ably_flutter.podspec | 3 +- lib/src/platform/src/codec.dart | 4 +- pubspec.lock | 64 +++++++------- pubspec.yaml | 13 ++- test_integration/ios/.gitignore | 1 + .../ios/Flutter/AppFrameworkInfo.plist | 2 - test_integration/ios/Podfile | 2 +- test_integration/ios/Podfile.lock | 6 +- .../ios/Runner.xcodeproj/project.pbxproj | 6 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 + test_integration/pubspec.lock | 88 +++++++++---------- test_integration/pubspec.yaml | 9 +- 31 files changed, 173 insertions(+), 156 deletions(-) diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 12ba268e3..f4c42dc4f 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -19,7 +19,7 @@ jobs: - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - flutter-version: '3.24' + flutter-version: '3.47.3' cache: true # This step requires fetch of test_integration packages because flutter format and diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3f9cb3860..83cd926dd 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,7 +16,7 @@ jobs: - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - flutter-version: '3.24' + flutter-version: '3.47.3' cache: true - name: Use Intro Blurb As Homepage diff --git a/.github/workflows/flutter_example_app.yaml b/.github/workflows/flutter_example_app.yaml index 5667878ae..d41e1f59e 100644 --- a/.github/workflows/flutter_example_app.yaml +++ b/.github/workflows/flutter_example_app.yaml @@ -17,7 +17,7 @@ jobs: - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - flutter-version: "3.24" + flutter-version: "3.47.3" cache: true - name: "Build example app for iOS" @@ -39,7 +39,7 @@ jobs: - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - flutter-version: "3.29" + flutter-version: "3.47.3" cache: true - name: "Build example app for Android" diff --git a/.github/workflows/flutter_integration.yaml b/.github/workflows/flutter_integration.yaml index b6bb41ebe..4df1f8b11 100644 --- a/.github/workflows/flutter_integration.yaml +++ b/.github/workflows/flutter_integration.yaml @@ -18,7 +18,7 @@ jobs: - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - flutter-version: '3.29' + flutter-version: '3.47.3' cache: true # test_integration package depends on ably_flutter, so before we run integration @@ -81,7 +81,7 @@ jobs: - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - flutter-version: '3.29' + flutter-version: '3.47.3' cache: true - name: 'Run Flutter Driver tests' diff --git a/.github/workflows/ios_unit_tests.yml b/.github/workflows/ios_unit_tests.yml index 71510f3d2..916a7033c 100644 --- a/.github/workflows/ios_unit_tests.yml +++ b/.github/workflows/ios_unit_tests.yml @@ -18,7 +18,7 @@ jobs: - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: - flutter-version: '3.29' + flutter-version: '3.47.3' cache: true - name: Set up iOS test project diff --git a/.tool-versions b/.tool-versions index 2d7c47ed4..544ec6c3d 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ ruby 3.4.5 -flutter 3.29.0 +flutter 3.47.3-stable diff --git a/PushNotifications.md b/PushNotifications.md index 6ecf4acda..9c9995536 100644 --- a/PushNotifications.md +++ b/PushNotifications.md @@ -25,7 +25,7 @@ See [issue #226](https://github.com/ably/ably-flutter/issues/226). - Android API level 19+ (Android 4.4+) - Android devices - Android emulator (with Google APIs) -- iOS 10+ +- iOS 13+ - Physical devices only - **Not supported:** iOS Simulator. Calling [`UIApplication:registerForRemoteNotifications`](https://developer.apple.com/documentation/uikit/uiapplication/1623078-registerforremotenotifications) will result in [`application:didFailToRegisterForRemoteNotificationsWithError`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622962-application) method being called in your AppDelegate with an error: `remote notifications are not supported in the simulator`). This is an iOS simulator limitation. diff --git a/README.md b/README.md index febbb2d81..da15acb09 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ This SDK supports the following platforms: | Platform | Support | |----------|---------| | Android | Android 4.4 (API level 19) or newer. Java 8 language features supported via [Desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring). | -| iOS | iOS 10 or newer | -| Flutter | Flutter 2.5.0 or higher | +| iOS | iOS 13 or newer | +| Flutter | Flutter 3.44.0 or higher | > [!NOTE] > If your project needs support for SDK Version lower than 24, Android Gradle Plugin 4.0.0+ must be used. diff --git a/analysis_options.yaml b/analysis_options.yaml index f815b7078..91aa6cefb 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -4,6 +4,9 @@ analyzer: # Templates for code generation can be excluded from analysis exclude: - bin/templates/** + - build/** + - android/** + - ios/** language: # Replacements for deprecated implicit-casts: false # Following https://dart.dev/guides/language/analysis-options#enabling-additional-type-checks @@ -18,6 +21,11 @@ analyzer: # allow self-reference to deprecated members # suppresses issues for deprecated members of the library like ClientOptions.fallbackHostsUseDefault deprecated_member_use_from_same_package: ignore + # Dart 3.13's analyzer extended this rule to private fields initialised from + # a named parameter, but the fix it suggests -- `this._field` in the + # parameter list -- is only legal under the off-by-default + # `private-named-parameters` experiment, so the reports are unactionable. + prefer_initializing_formals: ignore linter: # subject to false positives, perhaps worth suppressing in code in such cases @@ -37,7 +45,6 @@ linter: - avoid_implementing_value_types - avoid_init_to_null - avoid_js_rounded_ints - - avoid_null_checks_in_equality_operators - avoid_positional_boolean_parameters - avoid_redundant_argument_values - avoid_relative_lib_imports @@ -73,7 +80,6 @@ linter: - no_runtimeType_toString - omit_local_variable_types - only_throw_errors - - package_api_docs - prefer_adjacent_string_concatenation - prefer_asserts_in_initializer_lists - prefer_expression_function_bodies diff --git a/example/ios/.gitignore b/example/ios/.gitignore index e96ef602b..eb5573aef 100644 --- a/example/ios/.gitignore +++ b/example/ios/.gitignore @@ -20,6 +20,7 @@ Flutter/Flutter.podspec Flutter/Generated.xcconfig Flutter/app.flx Flutter/app.zip +Flutter/ephemeral/ Flutter/flutter_assets/ Flutter/flutter_export_environment.sh ServiceDefinitions.json diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index f2872cf47..ab8e063fe 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -20,7 +20,5 @@ ???? CFBundleVersion 1.0 - MinimumOSVersion - 9.0 diff --git a/example/ios/Podfile b/example/ios/Podfile index b5196d5f2..10f3c9b47 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '12.0' +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -38,11 +38,4 @@ post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) end - installer.generated_projects.each do |project| - project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '10.0' - end - end - end end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index ee9865844..232d372f4 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -42,14 +42,14 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Ably: 1756d6590a572809c10fc4bcc32e05fe9e7867d7 - ably_flutter: 95785161fc2858c7be524af4334925d30682b3b0 + ably_flutter: 03c57b59bcbf92ba2bd6910f10ed4e155bced176 AblyDeltaCodec: add5d06a756b3581b12aab5b5500a320b8c55bea device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896 - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100 fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1 msgpack: c85f6251873059738472ae136951cec5f30f3251 -PODFILE CHECKSUM: 5dac7b8eff57b86c98038531a0cc7562fb467acc +PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b COCOAPODS: 1.16.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 96babbb61..8d1a6f302 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -157,7 +157,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -203,10 +203,12 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -224,39 +226,21 @@ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Ably/Ably.framework", "${BUILT_PRODUCTS_DIR}/AblyDeltaCodec/AblyDeltaCodec.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework", - "${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework", - "${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework", - "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", - "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", - "${BUILT_PRODUCTS_DIR}/Toast/Toast.framework", "${BUILT_PRODUCTS_DIR}/ably_flutter/ably_flutter.framework", "${BUILT_PRODUCTS_DIR}/device_info_plus/device_info_plus.framework", "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework", "${BUILT_PRODUCTS_DIR}/fluttertoast/fluttertoast.framework", "${BUILT_PRODUCTS_DIR}/msgpack/msgpack.framework", - "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Ably.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AblyDeltaCodec.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Toast.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ably_flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fluttertoast.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/msgpack.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -265,6 +249,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -374,7 +359,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -400,7 +385,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -465,7 +450,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -514,7 +499,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -540,7 +525,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -576,7 +561,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a33..9c12df59c 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index ed3e8743b..ca132f81e 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -49,5 +49,9 @@ UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/example/lib/push_notifications/push_notification_service.dart b/example/lib/push_notifications/push_notification_service.dart index 4769a7e64..dc52b70f1 100644 --- a/example/lib/push_notifications/push_notification_service.dart +++ b/example/lib/push_notifications/push_notification_service.dart @@ -104,6 +104,9 @@ class PushNotificationService { Future deactivateDevice() => getPushFromAblyClient().deactivate(); + // `reset` is deliberately exercised here despite being experimental: this + // example app is how we manually verify it. + // ignore: experimental_member_use Future resetActivation() => getPushFromAblyClient().reset(); Future getDevice() async { diff --git a/example/pubspec.lock b/example/pubspec.lock index 8e79682cc..77ff86524 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -28,10 +28,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" clock: dependency: transitive description: @@ -190,18 +190,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.0" path: dependency: transitive description: @@ -299,10 +299,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: f36f9f3be64c6198714492bb455c11056e33e2f85d9a0b676a48301e44fdcf47 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.4.2" web: dependency: transitive description: @@ -344,5 +344,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.24.0" + dart: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bedd473e4..6570a2316 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,8 +3,8 @@ description: Demonstrates how to use the Ably Flutter plugin. publish_to: "none" environment: - sdk: ">=3.3.0 <4.0.0" - flutter: "3.24.0" + sdk: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" dependencies: flutter: @@ -28,4 +28,10 @@ dev_dependencies: flutter_lints: ^1.0.4 flutter: + # Flutter 3.44 turns Swift Package Manager on by default, and building this + # app would migrate its Xcode project off CocoaPods on the spot. Hold that + # off so the migration can land as its own reviewable commit rather than as + # a side effect of a version bump. + config: + enable-swift-package-manager: false uses-material-design: true diff --git a/ios/ably_flutter.podspec b/ios/ably_flutter.podspec index 37f36835d..659909e0e 100644 --- a/ios/ably_flutter.podspec +++ b/ios/ably_flutter.podspec @@ -20,7 +20,8 @@ Pod::Spec.new do |s| s.dependency 'Flutter' s.dependency 'Ably', '1.2.53' s.platform = :ios - s.ios.deployment_target = '10.0' + # UIScene, and therefore `FlutterSceneLifeCycleDelegate`, is iOS 13+ only. + s.ios.deployment_target = '13.0' # Flutter 3.x ships both arm64 and x86_64 simulator slices; no arch restriction needed. s.pod_target_xcconfig = { diff --git a/lib/src/platform/src/codec.dart b/lib/src/platform/src/codec.dart index 953d7d5b7..6ebe9ecb6 100644 --- a/lib/src/platform/src/codec.dart +++ b/lib/src/platform/src/codec.dart @@ -32,7 +32,7 @@ class _CodecPair { ); } if (value == null) return null; - return _encoder!(value as T); + return _encoder(value as T); } /// @nodoc @@ -46,7 +46,7 @@ class _CodecPair { ); } if (jsonMap == null) return null; - return _decoder!(jsonMap); + return _decoder(jsonMap); } } diff --git a/pubspec.lock b/pubspec.lock index e7d20b3e8..0144121b7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,34 +21,34 @@ packages: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.1" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: "direct main" description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.19.1" fake_async: dependency: "direct dev" description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" flutter: dependency: "direct main" description: flutter @@ -71,26 +71,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -103,34 +103,34 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.20" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: "direct main" description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9" url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.19.0" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" sky_engine: dependency: transitive description: flutter @@ -148,18 +148,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: @@ -180,18 +180,18 @@ packages: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.12" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: f36f9f3be64c6198714492bb455c11056e33e2f85d9a0b676a48301e44fdcf47 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.4.2" vm_service: dependency: transitive description: @@ -201,5 +201,5 @@ packages: source: hosted version: "14.3.0" sdks: - dart: ">=3.4.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8974c9cab..73024fc7d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,8 +4,17 @@ version: 1.2.44 repository: https://github.com/ably/ably-pubsub-flutter environment: - sdk: ">=2.14.0 <4.0.0" - flutter: ">=2.5.0" + # Two iOS floors meet at Flutter 3.44: + # + # - The UIScene plugin APIs the iOS side relies on + # (`FlutterSceneLifeCycleDelegate` and + # `FlutterPluginRegistrar.addSceneDelegate:`) first shipped in 3.38. See + # PushNotifications.md. + # - 3.44 is the first release where Swift Package Manager is the default + # dependency manager rather than an opt-in experiment, which is what lets + # this plugin ship a SwiftPM manifest and retire its podspec. + sdk: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" dependencies: collection: ^1.15.0 diff --git a/test_integration/ios/.gitignore b/test_integration/ios/.gitignore index e96ef602b..eb5573aef 100644 --- a/test_integration/ios/.gitignore +++ b/test_integration/ios/.gitignore @@ -20,6 +20,7 @@ Flutter/Flutter.podspec Flutter/Generated.xcconfig Flutter/app.flx Flutter/app.zip +Flutter/ephemeral/ Flutter/flutter_assets/ Flutter/flutter_export_environment.sh ServiceDefinitions.json diff --git a/test_integration/ios/Flutter/AppFrameworkInfo.plist b/test_integration/ios/Flutter/AppFrameworkInfo.plist index 8c6e56146..ab8e063fe 100644 --- a/test_integration/ios/Flutter/AppFrameworkInfo.plist +++ b/test_integration/ios/Flutter/AppFrameworkInfo.plist @@ -20,7 +20,5 @@ ???? CFBundleVersion 1.0 - MinimumOSVersion - 12.0 diff --git a/test_integration/ios/Podfile b/test_integration/ios/Podfile index 2c068c404..10f3c9b47 100644 --- a/test_integration/ios/Podfile +++ b/test_integration/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '12.0' +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/test_integration/ios/Podfile.lock b/test_integration/ios/Podfile.lock index 9b1ef0c69..16743f678 100644 --- a/test_integration/ios/Podfile.lock +++ b/test_integration/ios/Podfile.lock @@ -27,11 +27,11 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Ably: 1756d6590a572809c10fc4bcc32e05fe9e7867d7 - ably_flutter: 95785161fc2858c7be524af4334925d30682b3b0 + ably_flutter: 03c57b59bcbf92ba2bd6910f10ed4e155bced176 AblyDeltaCodec: add5d06a756b3581b12aab5b5500a320b8c55bea - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 msgpack: c85f6251873059738472ae136951cec5f30f3251 -PODFILE CHECKSUM: 4e8f8b2be68aeea4c0d5beb6ff1e79fface1d048 +PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b COCOAPODS: 1.16.2 diff --git a/test_integration/ios/Runner.xcodeproj/project.pbxproj b/test_integration/ios/Runner.xcodeproj/project.pbxproj index b2609ce9a..2006eada7 100644 --- a/test_integration/ios/Runner.xcodeproj/project.pbxproj +++ b/test_integration/ios/Runner.xcodeproj/project.pbxproj @@ -342,7 +342,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -428,7 +428,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -477,7 +477,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/test_integration/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/test_integration/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 4f746537f..fc5ae0316 100644 --- a/test_integration/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/test_integration/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> @@ -45,6 +46,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/test_integration/pubspec.lock b/test_integration/pubspec.lock index 8f513be99..d21302a5e 100644 --- a/test_integration/pubspec.lock +++ b/test_integration/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d" url: "https://pub.dev" source: hosted - version: "67.0.0" + version: "93.0.0" ably_flutter: dependency: "direct main" description: @@ -20,18 +20,18 @@ packages: dependency: transitive description: name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "10.0.1" args: dependency: "direct main" description: name: args - sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.7.0" async: dependency: transitive description: @@ -52,10 +52,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" charcode: dependency: transitive description: @@ -64,6 +64,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" clock: dependency: transitive description: @@ -92,10 +100,10 @@ packages: dependency: transitive description: name: coverage - sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + sha256: "956a3de0725ca232ad353565a8290d3357592bf4250f6f298a185e2d949c5d3d" url: "https://pub.dev" source: hosted - version: "1.7.2" + version: "1.15.1" crypto: dependency: transitive description: @@ -116,10 +124,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" file: dependency: transitive description: @@ -204,38 +212,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" - js: - dependency: transitive - description: - name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" - url: "https://pub.dev" - source: hosted - version: "0.6.5" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -256,26 +256,26 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd" url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.20" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.0" mime: dependency: transitive description: @@ -445,26 +445,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" + sha256: ca578dc12bb8b2f40b67b7d3bd2fac4f31c01a6ff7130a14e2597b919934507f url: "https://pub.dev" source: hosted - version: "1.25.15" + version: "1.31.1" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.12" test_core: dependency: transitive description: name: test_core - sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" + sha256: d2e98ec12998368dc59ddd47ab709f2cd55acd6b66dc7db764455a44082f4bc5 url: "https://pub.dev" source: hosted - version: "0.6.8" + version: "0.6.18" typed_data: dependency: transitive description: @@ -477,10 +477,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: f36f9f3be64c6198714492bb455c11056e33e2f85d9a0b676a48301e44fdcf47 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.4.2" vm_service: dependency: transitive description: @@ -525,10 +525,10 @@ packages: dependency: transitive description: name: yaml - sha256: "3cee79b1715110341012d27756d9bae38e650588acd38d3f3c610822e1337ace" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.3" sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" diff --git a/test_integration/pubspec.yaml b/test_integration/pubspec.yaml index 5d487661e..ba6cfc7b8 100644 --- a/test_integration/pubspec.yaml +++ b/test_integration/pubspec.yaml @@ -4,7 +4,8 @@ publish_to: "none" version: 1.0.0+1 environment: - sdk: ">=2.14.0 <4.0.0" + sdk: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" dependencies: flutter: @@ -24,4 +25,10 @@ dev_dependencies: flutter_lints: ^1.0.4 flutter: + # Flutter 3.44 turns Swift Package Manager on by default, and building this + # app would migrate its Xcode project off CocoaPods on the spot. Hold that + # off so the migration can land as its own reviewable commit rather than as + # a side effect of a version bump. + config: + enable-swift-package-manager: false uses-material-design: true From a54ce209125def3200e80b4964f9ffbf7060a1cf Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 10 Sep 2026 13:07:54 +0100 Subject: [PATCH 2/2] style: apply the Dart 3.13 formatter `dart format --set-exit-if-changed .` is a CI gate, and the formatter's output changed with the SDK bump in the previous commit, so the whole tree has to be reformatted. Kept as its own commit because it touches 134 files and none of it is behavioural -- review it separately from, or skip it alongside, the SwiftPM and UIScene work that follows. Co-Authored-By: Claude Opus 5 (1M context) --- bin/codegen_context.dart | 142 ++--- bin/templates/platformconstants.dart.dart | 3 +- bin/templates/platformconstants.h.dart | 3 +- bin/templates/platformconstants.java.dart | 3 +- bin/templates/platformconstants.m.dart | 3 +- example/lib/app_provisioning.dart | 47 +- example/lib/main.dart | 44 +- example/lib/nested_realtime_events.dart | 21 +- example/lib/op_state.dart | 7 +- ...droid_push_notification_configuration.dart | 3 +- .../push_notification_handlers.dart | 35 +- .../push_notification_message_examples.dart | 80 +-- .../push_notification_service.dart | 79 ++- example/lib/ui/ably_service.dart | 38 +- example/lib/ui/api_key_service.dart | 15 +- example/lib/ui/auth.dart | 31 +- example/lib/ui/bool_stream_button.dart | 13 +- example/lib/ui/paginated_result_viewer.dart | 28 +- .../push_notifications_activation_sliver.dart | 114 ++-- ...push_notifications_device_information.dart | 103 ++-- ..._notifications_ios_permissions_sliver.dart | 56 +- .../push_notifications_publishing_sliver.dart | 69 +-- .../push_notifications_received_sliver.dart | 103 ++-- .../push_notifications_sliver.dart | 82 +-- ...sh_notifications_subscriptions_sliver.dart | 304 +++++----- .../push_realtime_client_received_sliver.dart | 63 +- example/lib/ui/realtime_presence_sliver.dart | 146 ++--- example/lib/ui/realtime_sliver.dart | 357 +++++------ example/lib/ui/rest_sliver.dart | 145 ++--- example/lib/ui/system_details_sliver.dart | 37 +- example/lib/ui/text_row.dart | 17 +- example/lib/ui/utilities.dart | 22 +- lib/src/authentication/src/auth_options.dart | 4 +- .../authentication/src/client_options.dart | 41 +- lib/src/authentication/src/token_details.dart | 10 +- lib/src/authentication/src/token_request.dart | 15 +- lib/src/crypto/src/crypto.dart | 29 +- lib/src/error/src/ably_exception.dart | 12 +- lib/src/error/src/error_info.dart | 3 +- lib/src/logging/src/log_handler.dart | 5 +- lib/src/message/src/delta_extras.dart | 9 +- lib/src/message/src/message.dart | 56 +- lib/src/message/src/message_data.dart | 2 +- lib/src/message/src/message_extras.dart | 10 +- lib/src/message/src/presence_message.dart | 66 +- lib/src/platform/src/ably_event_message.dart | 5 +- lib/src/platform/src/ably_message.dart | 25 +- .../background_android_isolate_platform.dart | 8 +- .../platform/src/cipher_params_internal.dart | 19 +- lib/src/platform/src/codec.dart | 568 ++++++++++-------- lib/src/platform/src/method_call_handler.dart | 21 +- lib/src/platform/src/paginated_result.dart | 22 +- lib/src/platform/src/platform.dart | 48 +- lib/src/platform/src/platform_object.dart | 30 +- .../push_notification_events_internal.dart | 18 +- lib/src/platform/src/realtime/connection.dart | 15 +- lib/src/platform/src/realtime/presence.dart | 24 +- lib/src/platform/src/realtime/realtime.dart | 24 +- .../src/realtime/realtime_channel.dart | 43 +- lib/src/platform/src/rest/rest_channel.dart | 27 +- lib/src/platform/src/rest/rest_presence.dart | 4 +- lib/src/platform/src/streams_channel.dart | 109 ++-- .../src/admin/push_device_registrations.dart | 14 +- .../src/device_push_details.dart | 6 +- .../src/ios_notification_settings.dart | 18 +- .../push_notifications/src/local_device.dart | 14 +- .../push_notifications/src/notification.dart | 11 +- lib/src/push_notifications/src/push.dart | 11 +- .../push_notifications/src/push_channel.dart | 32 +- .../src/push_channel_subscriptions.dart | 4 +- .../src/push_notification_events.dart | 3 +- .../src/remote_message.dart | 31 +- .../realtime/src/connection_state_change.dart | 7 +- lib/src/realtime/src/realtime_auth.dart | 42 +- .../src/realtime_channel_options.dart | 6 +- .../realtime/src/realtime_history_params.dart | 9 +- lib/src/rest/src/rest_auth.dart | 40 +- lib/src/rest/src/rest_history_params.dart | 9 +- lib/src/rest/src/rest_presence_params.dart | 6 +- test/ably_event_listener_test.dart | 5 +- test/ably_flutter_plugin_test.dart | 42 +- test/mock_method_call_manager.dart | 30 +- test/models/message_test.dart | 43 +- test/models/presence_message_test.dart | 70 ++- test/realtime/channel_test.dart | 33 +- test/rest/channel_test.dart | 25 +- test/rest/channels_test.dart | 11 +- test_integration/lib/app_provisioning.dart | 47 +- test_integration/lib/config/test_factory.dart | 9 +- test_integration/lib/driver_data_handler.dart | 18 +- .../lib/factory/error_handler.dart | 16 +- test_integration/lib/factory/reporter.dart | 6 +- test_integration/lib/test/basic_test.dart | 5 +- ...ypto_ensure_supported_key_length_test.dart | 5 +- .../crypto/crypto_get_default_params.dart | 5 +- .../realtime_auth_client_id_test.dart | 17 +- .../test/realtime/realtime_auth_url_test.dart | 21 +- .../realtime/realtime_authorize_test.dart | 35 +- .../realtime_encrypted_publish_test.dart | 44 +- .../test/realtime/realtime_events_test.dart | 11 +- ...ltime_history_with_auth_callback_test.dart | 4 +- .../realtime_presence_enter_update_leave.dart | 28 +- .../test/realtime/realtime_presence_get.dart | 13 +- .../realtime/realtime_presence_subscribe.dart | 12 +- .../test/realtime/realtime_publish_test.dart | 23 +- ...ltime_publish_with_auth_callback_test.dart | 4 +- .../lib/test/realtime/realtime_subscribe.dart | 4 +- .../test/rest/rest_auth_client_id_test.dart | 17 +- .../lib/test/rest/rest_authorize_test.dart | 35 +- .../lib/test/rest/rest_capability_test.dart | 13 +- .../rest/rest_create_token_request_test.dart | 34 +- .../rest/rest_encrypted_publish_test.dart | 44 +- .../lib/test/rest/rest_history_test.dart | 16 +- .../rest_history_with_auth_callback_test.dart | 6 +- .../lib/test/rest/rest_presence_get_test.dart | 13 +- .../test/rest/rest_presence_history_test.dart | 5 +- .../lib/test/rest/rest_publish_test.dart | 23 +- .../rest_publish_with_auth_callback_test.dart | 6 +- .../test/rest/rest_request_token_test.dart | 9 +- .../lib/test/rest/rest_time_test.dart | 5 +- test_integration/lib/test_dispatcher.dart | 130 ++-- test_integration/lib/utils/data.dart | 40 +- test_integration/lib/utils/encoders.dart | 113 ++-- test_integration/lib/utils/realtime.dart | 15 +- test_integration/lib/utils/rest.dart | 18 +- test_integration/test_driver/runner.dart | 8 +- .../basic_platform_tests.dart | 6 +- .../test_implementation/crypto_tests.dart | 25 +- .../test_implementation/helper_tests.dart | 3 +- .../test_implementation/realtime_tests.dart | 441 +++++++------- .../test_implementation/rest_tests.dart | 145 +++-- .../test_implementation/utils.dart | 28 +- .../test_driver/tests_abstract.dart | 15 +- .../test_driver/tests_config.dart | 97 +-- 134 files changed, 2938 insertions(+), 2706 deletions(-) diff --git a/bin/codegen_context.dart b/bin/codegen_context.dart index 3b91e3079..baace2ed7 100644 --- a/bin/codegen_context.dart +++ b/bin/codegen_context.dart @@ -95,7 +95,7 @@ const List> _platformMethods = [ {'name': 'onRealtimePresenceMessage', 'value': 'onRealtimePresenceMessage'}, { 'name': 'publishRealtimeChannelMessage', - 'value': 'publishRealtimeChannelMessage' + 'value': 'publishRealtimeChannelMessage', }, {'name': 'releaseRealtimeChannel', 'value': 'releaseRealtimeChannel'}, {'name': 'realtimeHistory', 'value': 'realtimeHistory'}, @@ -104,7 +104,7 @@ const List> _platformMethods = [ {'name': 'realtimeAuthAuthorize', 'value': 'realtimeAuthAuthorize'}, { 'name': 'realtimeAuthCreateTokenRequest', - 'value': 'realtimeAuthCreateTokenRequest' + 'value': 'realtimeAuthCreateTokenRequest', }, {'name': 'realtimeAuthRequestToken', 'value': 'realtimeAuthRequestToken'}, {'name': 'realtimeAuthGetClientId', 'value': 'realtimeAuthGetClientId'}, @@ -124,7 +124,7 @@ const List> _platformMethods = [ // Used only on iOS { 'name': 'pushGetNotificationSettings', - 'value': 'pushGetNotificationSettings' + 'value': 'pushGetNotificationSettings', }, // Used only on iOS {'name': 'pushOpenSettingsFor', 'value': 'pushOpenSettingsFor'}, @@ -135,11 +135,11 @@ const List> _platformMethods = [ // Push Notification Events { 'name': 'pushNotificationTapLaunchedAppFromTerminated', - 'value': 'pushNotificationTapLaunchedAppFromTerminated' + 'value': 'pushNotificationTapLaunchedAppFromTerminated', }, { 'name': 'pushOnShowNotificationInForeground', - 'value': 'pushOnShowNotificationInForeground' + 'value': 'pushOnShowNotificationInForeground', }, {'name': 'pushOnMessage', 'value': 'pushOnMessage'}, {'name': 'pushOnBackgroundMessage', 'value': 'pushOnBackgroundMessage'}, @@ -147,17 +147,17 @@ const List> _platformMethods = [ // Used only on Android { 'name': 'pushBackgroundFlutterApplicationReadyOnAndroid', - 'value': 'pushBackgroundFlutterApplicationReadyOnAndroid' + 'value': 'pushBackgroundFlutterApplicationReadyOnAndroid', }, // Realtime events { 'name': 'onRealtimeConnectionStateChanged', - 'value': 'onRealtimeConnectionStateChanged' + 'value': 'onRealtimeConnectionStateChanged', }, { 'name': 'onRealtimeChannelStateChanged', - 'value': 'onRealtimeChannelStateChanged' + 'value': 'onRealtimeChannelStateChanged', }, {'name': 'onRealtimeChannelMessage', 'value': 'onRealtimeChannelMessage'}, @@ -183,15 +183,15 @@ const List> _objects = [ 'clientId', 'options', 'messages', - ] + ], }, { 'name': 'AblyMessage', - 'properties': ['registrationHandle', 'type', 'message'] + 'properties': ['registrationHandle', 'type', 'message'], }, { 'name': 'AblyEventMessage', - 'properties': ['eventName', 'type', 'message'] + 'properties': ['eventName', 'type', 'message'], }, { 'name': 'ErrorInfo', @@ -201,20 +201,20 @@ const List> _objects = [ 'statusCode', 'href', 'requestId', - 'cause' - ] + 'cause', + ], }, { 'name': 'MessageData', - 'properties': ['data', 'type'] + 'properties': ['data', 'type'], }, { 'name': 'DeltaExtras', - 'properties': ['format', 'from'] + 'properties': ['format', 'from'], }, { 'name': 'MessageExtras', - 'properties': ['extras', 'delta'] + 'properties': ['extras', 'delta'], }, { 'name': 'ClientOptions', @@ -255,15 +255,15 @@ const List> _objects = [ 'channelRetryTimeout', 'transportParams', 'dartVersion', - ] + ], }, { 'name': 'RestChannelOptions', - 'properties': ['cipherParams'] + 'properties': ['cipherParams'], }, { 'name': 'RealtimeChannelOptions', - 'properties': ['params', 'modes', 'cipherParams'] + 'properties': ['params', 'modes', 'cipherParams'], }, { 'name': 'CipherParams', @@ -276,8 +276,8 @@ const List> _objects = [ 'expires', 'issued', 'capability', - 'clientId' - ] + 'clientId', + ], }, { 'name': 'AuthOptions', @@ -291,8 +291,8 @@ const List> _objects = [ 'authHeaders', 'authParams', 'queryTime', - 'useTokenAuth' - ] + 'useTokenAuth', + ], }, { 'name': 'TokenParams', @@ -301,8 +301,8 @@ const List> _objects = [ 'clientId', 'nonce', 'timestamp', - 'ttl' - ] + 'ttl', + ], }, { 'name': 'TokenRequest', @@ -313,8 +313,8 @@ const List> _objects = [ 'mac', 'nonce', 'timestamp', - 'ttl' - ] + 'ttl', + ], }, { 'name': 'EnumConstants', @@ -342,8 +342,8 @@ const List> _objects = [ 'presence', 'publish', 'subscribe', - 'presenceSubscribe' - ] + 'presenceSubscribe', + ], }, { 'name': 'FormFactorEnum', @@ -355,8 +355,8 @@ const List> _objects = [ 'watch', 'car', 'embedded', - 'other' - ] + 'other', + ], }, { 'name': 'LogLevelEnum', @@ -364,19 +364,19 @@ const List> _objects = [ }, { 'name': 'DevicePlatformEnum', - 'properties': ['ios', 'android', 'browser'] + 'properties': ['ios', 'android', 'browser'], }, { 'name': 'DevicePushStateEnum', - 'properties': ['active', 'failing', 'failed'] + 'properties': ['active', 'failing', 'failed'], }, { 'name': 'ConnectionStateChange', - 'properties': ['current', 'previous', 'event', 'retryIn', 'reason'] + 'properties': ['current', 'previous', 'event', 'retryIn', 'reason'], }, { 'name': 'ChannelStateChange', - 'properties': ['current', 'previous', 'event', 'resumed', 'reason'] + 'properties': ['current', 'previous', 'event', 'resumed', 'reason'], }, { 'name': 'Message', @@ -388,8 +388,8 @@ const List> _objects = [ 'encoding', 'data', 'name', - 'extras' - ] + 'extras', + ], }, { 'name': 'PresenceMessage', @@ -402,46 +402,27 @@ const List> _objects = [ 'encoding', 'extras', 'timestamp', - ] + ], }, { 'name': 'PaginatedResult', - 'properties': ['items', 'type', 'hasNext'] + 'properties': ['items', 'type', 'hasNext'], }, { 'name': 'RestHistoryParams', - 'properties': [ - 'start', - 'end', - 'direction', - 'limit', - ] + 'properties': ['start', 'end', 'direction', 'limit'], }, { 'name': 'RealtimeHistoryParams', - 'properties': [ - 'start', - 'end', - 'direction', - 'limit', - 'untilAttach', - ] + 'properties': ['start', 'end', 'direction', 'limit', 'untilAttach'], }, { 'name': 'RestPresenceParams', - 'properties': [ - 'limit', - 'clientId', - 'connectionId', - ] + 'properties': ['limit', 'clientId', 'connectionId'], }, { 'name': 'RealtimePresenceParams', - 'properties': [ - 'waitForSync', - 'clientId', - 'connectionId', - ] + 'properties': ['waitForSync', 'clientId', 'connectionId'], }, { 'name': 'DeviceDetails', @@ -451,20 +432,20 @@ const List> _objects = [ 'platform', 'formFactor', 'metadata', - 'devicePushDetails' - ] + 'devicePushDetails', + ], }, { 'name': 'DevicePushDetails', - 'properties': ['recipient', 'state', 'errorReason'] + 'properties': ['recipient', 'state', 'errorReason'], }, { 'name': 'LocalDevice', - 'properties': ['deviceSecret', 'deviceIdentityToken'] + 'properties': ['deviceSecret', 'deviceIdentityToken'], }, { 'name': 'PushChannelSubscription', - 'properties': ['channel', 'deviceId', 'clientId'] + 'properties': ['channel', 'deviceId', 'clientId'], }, { 'name': 'PushRequestPermission', @@ -477,7 +458,7 @@ const List> _objects = [ 'providesAppNotificationSettings', 'provisional', 'announcement', - ] + ], }, { 'name': 'UNNotificationSettings', @@ -496,15 +477,15 @@ const List> _objects = [ 'announcementSetting', 'scheduledDeliverySetting', 'timeSensitiveSetting', - ] + ], }, { 'name': 'UNNotificationSettingEnum', - 'properties': ['notSupported', 'disabled', 'enabled'] + 'properties': ['notSupported', 'disabled', 'enabled'], }, { 'name': 'UNAlertStyleEnum', - 'properties': ['none', 'banner', 'alert'] + 'properties': ['none', 'banner', 'alert'], }, { 'name': 'UNAuthorizationStatusEnum', @@ -514,31 +495,28 @@ const List> _objects = [ 'authorized', 'provisional', 'ephemeral', - ] + ], }, { 'name': 'UNShowPreviewsSettingEnum', - 'properties': ['always', 'whenAuthenticated', 'never'] + 'properties': ['always', 'whenAuthenticated', 'never'], }, { 'name': 'RemoteMessage', - 'properties': [ - 'data', - 'notification', - ] + 'properties': ['data', 'notification'], }, { 'name': 'Notification', - 'properties': ['title', 'body'] + 'properties': ['title', 'body'], }, { 'name': 'CryptoGetParams', - 'properties': ['algorithm', 'key'] + 'properties': ['algorithm', 'key'], }, { 'name': 'CryptoGenerateRandomKey', - 'properties': ['keyLength'] - } + 'properties': ['keyLength'], + }, ]; // exporting all the constants as a single map @@ -546,5 +524,5 @@ const List> _objects = [ Map context = { 'types': _types, 'methods': _platformMethods, - 'objects': _objects + 'objects': _objects, }; diff --git a/bin/templates/platformconstants.dart.dart b/bin/templates/platformconstants.dart.dart index 7864dcde3..fbeec905e 100644 --- a/bin/templates/platformconstants.dart.dart +++ b/bin/templates/platformconstants.dart.dart @@ -1,6 +1,7 @@ String getPrefix(String str) => (str.length > 26) ? '\n ' : ' '; -String $(Map c) => ''' +String $(Map c) => + ''' // ignore_for_file: public_member_api_docs class CodecTypes { diff --git a/bin/templates/platformconstants.h.dart b/bin/templates/platformconstants.h.dart index 635ab269c..643957dcf 100644 --- a/bin/templates/platformconstants.h.dart +++ b/bin/templates/platformconstants.h.dart @@ -1,4 +1,5 @@ -String $(Map c) => ''' +String $(Map c) => + ''' @import Foundation; typedef NS_ENUM(UInt8, CodecType) { diff --git a/bin/templates/platformconstants.java.dart b/bin/templates/platformconstants.java.dart index 17fccf9ab..314396a9d 100644 --- a/bin/templates/platformconstants.java.dart +++ b/bin/templates/platformconstants.java.dart @@ -1,4 +1,5 @@ -String $(Map c) => ''' +String $(Map c) => + ''' package io.ably.flutter.plugin.generated; diff --git a/bin/templates/platformconstants.m.dart b/bin/templates/platformconstants.m.dart index 9ac7657b7..9f6b6a7c3 100644 --- a/bin/templates/platformconstants.m.dart +++ b/bin/templates/platformconstants.m.dart @@ -1,4 +1,5 @@ -String $(Map c) => ''' +String $(Map c) => + ''' #import "AblyPlatformConstants.h" diff --git a/example/lib/app_provisioning.dart b/example/lib/app_provisioning.dart index 87f035128..bd5b417ec 100644 --- a/example/lib/app_provisioning.dart +++ b/example/lib/app_provisioning.dart @@ -66,30 +66,27 @@ class AppProvisioning { /// A set of base headers for HTTP requests Map get _requestHeaders => { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - }; + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; /// App spec used to provision the app /// /// See: https://docs.ably.com/client-lib-development-guide/test-api Map> get _appSpec => { - 'namespaces': [ - { - 'id': 'pushenabled', - 'pushEnabled': pushEnabled, - } - ], - 'keys': [ - { - // The need to use jsonEncode here is a requirement of the - // Sandbox Test API. The capability map has to be JSON encoded - // as a string and then appropriately escaped in order for - // presentation within a string value. - 'capability': jsonEncode(keyCapabilities), - }, - ], - }; + 'namespaces': [ + {'id': 'pushenabled', 'pushEnabled': pushEnabled}, + ], + 'keys': [ + { + // The need to use jsonEncode here is a requirement of the + // Sandbox Test API. The capability map has to be JSON encoded + // as a string and then appropriately escaped in order for + // presentation within a string value. + 'capability': jsonEncode(keyCapabilities), + }, + ], + }; /// Makes request to configured Ably provisioning URL and returns a /// new key for test application instance @@ -102,8 +99,10 @@ class AppProvisioning { if (response.statusCode != HttpStatus.created) { log("Server didn't return success. ${response.body}"); - throw HttpException("Server didn't return success." - ' Status: ${response.statusCode} : ${response.body}'); + throw HttpException( + "Server didn't return success." + ' Status: ${response.statusCode} : ${response.body}', + ); } final responseBody = jsonDecode(response.body) as Map; @@ -122,8 +121,10 @@ class AppProvisioning { if (response.statusCode != HttpStatus.ok) { log("Server didn't return success. ${response.body}"); - throw HttpException("Server didn't return success." - ' Status: ${response.statusCode} : ${response.body}'); + throw HttpException( + "Server didn't return success." + ' Status: ${response.statusCode} : ${response.body}', + ); } return Map.castFrom( diff --git a/example/lib/main.dart b/example/lib/main.dart index d3057f547..f40947235 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -22,33 +22,27 @@ Future main() async { class AblyFlutterExampleApp extends StatelessWidget { final AblyService ablyService; - const AblyFlutterExampleApp({ - required this.ablyService, - Key? key, - }) : super(key: key); + const AblyFlutterExampleApp({required this.ablyService, Key? key}) + : super(key: key); @override Widget build(BuildContext context) => MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('Ably Flutter Example App'), - ), - body: Center( - child: ListView( - padding: - const EdgeInsets.symmetric(vertical: 24, horizontal: 36), - children: [ - SystemDetailsSliver( - apiKeyProvision: ablyService.apiKeyProvision, - ), - const Divider(), - RealtimeSliver(ablyService), - const Divider(), - RestSliver(ablyService.rest), - const Divider(), - PushNotificationsSliver(ablyService.pushNotificationService) - ]), - ), + home: Scaffold( + appBar: AppBar(title: const Text('Ably Flutter Example App')), + body: Center( + child: ListView( + padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 36), + children: [ + SystemDetailsSliver(apiKeyProvision: ablyService.apiKeyProvision), + const Divider(), + RealtimeSliver(ablyService), + const Divider(), + RestSliver(ablyService.rest), + const Divider(), + PushNotificationsSliver(ablyService.pushNotificationService), + ], ), - ); + ), + ), + ); } diff --git a/example/lib/nested_realtime_events.dart b/example/lib/nested_realtime_events.dart index 574c14758..9657f3fdb 100644 --- a/example/lib/nested_realtime_events.dart +++ b/example/lib/nested_realtime_events.dart @@ -15,16 +15,20 @@ void listenRealtimeConnection(ably.Realtime realtime) { // and must cancel each subscription one by one //RETAINING LISTENER - α realtime.connection.on().listen((stateChange) { - print('RETAINING LISTENER α :: Change event arrived!: ${stateChange.event}' - '\nReason: ${stateChange.reason}'); + print( + 'RETAINING LISTENER α :: Change event arrived!: ${stateChange.event}' + '\nReason: ${stateChange.reason}', + ); }); //DISPOSE ON CONNECTED final stream = realtime.connection.on(); late StreamSubscription omegaSubscription; omegaSubscription = stream.listen((stateChange) async { - print('DISPOSABLE LISTENER ω :: Change event arrived!:' - ' ${stateChange.event}'); + print( + 'DISPOSABLE LISTENER ω :: Change event arrived!:' + ' ${stateChange.event}', + ); if (stateChange.event == ably.ConnectionEvent.connected) { await omegaSubscription.cancel(); } @@ -32,8 +36,10 @@ void listenRealtimeConnection(ably.Realtime realtime) { //RETAINING LISTENER - β realtime.connection.on().listen((stateChange) { - print('RETAINING LISTENER β :: Change event arrived!:' - ' ${stateChange.event}'); + print( + 'RETAINING LISTENER β :: Change event arrived!:' + ' ${stateChange.event}', + ); // NESTED LISTENER - ξ // will be registered only when connected event is received by β listener realtime.connection.on().listen((stateChange) { @@ -54,7 +60,8 @@ void listenRealtimeConnection(ably.Realtime realtime) { //RETAINING LISTENER - γ realtime.connection.on().listen((stateChange) async { print( - 'RETAINING LISTENER γ :: Change event arrived!: ${stateChange.event}'); + 'RETAINING LISTENER γ :: Change event arrived!: ${stateChange.event}', + ); if (stateChange.event == ably.ConnectionEvent.connected) { //by the time this cancel is triggered, // preZeta will already have received current event. diff --git a/example/lib/op_state.dart b/example/lib/op_state.dart index 3a2795914..8986ec6c7 100644 --- a/example/lib/op_state.dart +++ b/example/lib/op_state.dart @@ -1,6 +1 @@ -enum OpState { - notStarted, - inProgress, - succeeded, - failed, -} +enum OpState { notStarted, inProgress, succeeded, failed } diff --git a/example/lib/push_notifications/android_push_notification_configuration.dart b/example/lib/push_notifications/android_push_notification_configuration.dart index 248628359..fac28f79a 100644 --- a/example/lib/push_notifications/android_push_notification_configuration.dart +++ b/example/lib/push_notifications/android_push_notification_configuration.dart @@ -18,7 +18,8 @@ class AndroidPushNotificationConfiguration { await _flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() + AndroidFlutterLocalNotificationsPlugin + >() ?.createNotificationChannel(channel); } } diff --git a/example/lib/push_notifications/push_notification_handlers.dart b/example/lib/push_notifications/push_notification_handlers.dart index 7dbbcc9c7..0cc11ee3b 100644 --- a/example/lib/push_notifications/push_notification_handlers.dart +++ b/example/lib/push_notifications/push_notification_handlers.dart @@ -9,7 +9,7 @@ class PushNotificationHandlers { static final notificationEvents = ably.Push.notificationEvents; static final BehaviorSubject> - _receivedMessagesBehaviorSubject = + _receivedMessagesBehaviorSubject = BehaviorSubject>.seeded([]); static ValueStream> receivedMessagesStream = @@ -17,8 +17,10 @@ class PushNotificationHandlers { static void setUpEventHandlers() { activationEvents.onUpdateFailed.listen((error) async { - logAndDisplayError(error, - prefixMessage: 'Push update registration failed'); + logAndDisplayError( + error, + prefixMessage: 'Push update registration failed', + ); }); activationEvents.onActivate.listen((error) async { logAndDisplayError(error, prefixMessage: 'Push activation failed'); @@ -39,14 +41,17 @@ class PushNotificationHandlers { notificationEvents.onMessage.listen((message) { addMessage(message); - print('RemoteMessage received while app is in foreground:\n' - 'RemoteMessage.Notification: ${message.notification}' - 'RemoteMessage.Data: ${message.data}'); + print( + 'RemoteMessage received while app is in foreground:\n' + 'RemoteMessage.Notification: ${message.notification}' + 'RemoteMessage.Data: ${message.data}', + ); }); notificationEvents.setOnShowNotificationInForeground((message) async { print( - 'Opting to show the notification when the app is in the foreground.'); + 'Opting to show the notification when the app is in the foreground.', + ); return true; }); @@ -58,8 +63,9 @@ class PushNotificationHandlers { /// You can get the notification which launched the app by a user tapping it. static void getLaunchMessage() { - notificationEvents.notificationTapLaunchedAppFromTerminated - .then((remoteMessage) { + notificationEvents.notificationTapLaunchedAppFromTerminated.then(( + remoteMessage, + ) { if (remoteMessage != null) { addMessage(remoteMessage); print('The app was launched by the user by tapping the notification'); @@ -73,11 +79,14 @@ class PushNotificationHandlers { } static Future _backgroundMessageHandler( - ably.RemoteMessage message) async { + ably.RemoteMessage message, + ) async { addMessage(message); - print('RemoteMessage received while app is in background:\n' - 'RemoteMessage.Notification: ${message.notification}' - 'RemoteMessage.Data: ${message.data}'); + print( + 'RemoteMessage received while app is in background:\n' + 'RemoteMessage.Notification: ${message.notification}' + 'RemoteMessage.Data: ${message.data}', + ); } static void addMessage(ably.RemoteMessage message) { diff --git a/example/lib/push_notifications/push_notification_message_examples.dart b/example/lib/push_notifications/push_notification_message_examples.dart index abc51b8c6..98d9b86e5 100644 --- a/example/lib/push_notifications/push_notification_message_examples.dart +++ b/example/lib/push_notifications/push_notification_message_examples.dart @@ -2,48 +2,54 @@ import 'package:ably_flutter/ably_flutter.dart' as ably; class PushNotificationMessageExamples { static final ably.Message pushNotificationMessage = ably.Message( - data: 'This is an Ably message published on channels that is also sent ' - 'as a notification message to registered push devices.', - extras: const ably.MessageExtras({ - 'push': { - 'notification': { - 'title': 'Hello from Ably!', - 'body': 'Example push notification from Ably.', - 'sound': 'default' - }, + data: + 'This is an Ably message published on channels that is also sent ' + 'as a notification message to registered push devices.', + extras: const ably.MessageExtras({ + 'push': { + 'notification': { + 'title': 'Hello from Ably!', + 'body': 'Example push notification from Ably.', + 'sound': 'default', }, - })); + }, + }), + ); static ably.Message pushDataMessage = ably.Message( - data: 'This is a Ably message published on channels that is also ' - 'sent as a data message to registered push devices.', - extras: const ably.MessageExtras({ - 'push': { - 'data': {'foo': 'bar', 'baz': 'quz'}, - 'apns': { - 'apns-headers': { - 'apns-push-type': 'background', - 'apns-priority': '5', - }, - 'aps': {'content-available': 1} - } + data: + 'This is a Ably message published on channels that is also ' + 'sent as a data message to registered push devices.', + extras: const ably.MessageExtras({ + 'push': { + 'data': {'foo': 'bar', 'baz': 'quz'}, + 'apns': { + 'apns-headers': { + 'apns-push-type': 'background', + 'apns-priority': '5', + }, + 'aps': {'content-available': 1}, }, - })); + }, + }), + ); static ably.Message pushDataNotificationMessage = ably.Message( - data: 'This is a Ably message published on channels that is also ' - 'sent as a data message to registered push devices.', - extras: const ably.MessageExtras({ - 'push': { - 'notification': { - 'title': 'Hello from Ably!', - 'body': 'Example push notification from Ably.', - 'sound': 'default' - }, - 'data': {'foo': 'bar', 'baz': 'quz'}, - 'apns': { - 'aps': {'content-available': 1} - } + data: + 'This is a Ably message published on channels that is also ' + 'sent as a data message to registered push devices.', + extras: const ably.MessageExtras({ + 'push': { + 'notification': { + 'title': 'Hello from Ably!', + 'body': 'Example push notification from Ably.', + 'sound': 'default', + }, + 'data': {'foo': 'bar', 'baz': 'quz'}, + 'apns': { + 'aps': {'content-available': 1}, }, - })); + }, + }), + ); } diff --git a/example/lib/push_notifications/push_notification_service.dart b/example/lib/push_notifications/push_notification_service.dart index dc52b70f1..f75958279 100644 --- a/example/lib/push_notifications/push_notification_service.dart +++ b/example/lib/push_notifications/push_notification_service.dart @@ -30,20 +30,20 @@ class PushNotificationService { } final BehaviorSubject> - _pushChannelDeviceSubscriptionsSubject = + _pushChannelDeviceSubscriptionsSubject = BehaviorSubject>(); ValueStream> - get pushChannelDeviceSubscriptionsStream => - _pushChannelDeviceSubscriptionsSubject.stream; + get pushChannelDeviceSubscriptionsStream => + _pushChannelDeviceSubscriptionsSubject.stream; final BehaviorSubject> - _pushChannelClientSubscriptionsSubject = + _pushChannelClientSubscriptionsSubject = BehaviorSubject>(); ValueStream> - get pushChannelClientSubscriptionsStream => - _pushChannelClientSubscriptionsSubject.stream; + get pushChannelClientSubscriptionsStream => + _pushChannelClientSubscriptionsSubject.stream; final BehaviorSubject _hasPushChannelSubject = BehaviorSubject.seeded(false); @@ -61,9 +61,9 @@ class PushNotificationService { _userNotificationPermissionGrantedSubject.stream; final BehaviorSubject - _notificationSettingsSubject = BehaviorSubject(); + _notificationSettingsSubject = BehaviorSubject(); late final ValueStream - notificationSettingsStream = _notificationSettingsSubject.stream; + notificationSettingsStream = _notificationSettingsSubject.stream; Future ensureRealtimeClientConnected() async { if (_realtime.connection.state != ably.ConnectionState.connected) { @@ -72,18 +72,21 @@ class PushNotificationService { } /// Only valid on iOS - Future requestNotificationPermission( - {bool provisional = false, - bool providesAppNotificationSettings = true}) async { + Future requestNotificationPermission({ + bool provisional = false, + bool providesAppNotificationSettings = true, + }) async { if (useRealtimeClient) { final granted = await _realtime.push.requestPermission( - provisional: provisional, - providesAppNotificationSettings: providesAppNotificationSettings); + provisional: provisional, + providesAppNotificationSettings: providesAppNotificationSettings, + ); _userNotificationPermissionGrantedSubject.add(granted); } else { final granted = await _rest.push.requestPermission( - provisional: provisional, - providesAppNotificationSettings: providesAppNotificationSettings); + provisional: provisional, + providesAppNotificationSettings: providesAppNotificationSettings, + ); _userNotificationPermissionGrantedSubject.add(granted); } await updateNotificationSettings(); @@ -95,8 +98,9 @@ class PushNotificationService { final settings = await _realtime.push.getNotificationSettings(); _notificationSettingsSubject.add(settings); } else { - _notificationSettingsSubject - .add(await _rest.push.getNotificationSettings()); + _notificationSettingsSubject.add( + await _rest.push.getNotificationSettings(), + ); } } @@ -166,21 +170,25 @@ class PushNotificationService { await ensureRealtimeClientConnected(); if (useRealtimeClient) { await _realtimeChannel!.publish( - message: PushNotificationMessageExamples.pushNotificationMessage); + message: PushNotificationMessageExamples.pushNotificationMessage, + ); } else { await _restChannel!.publish( - message: PushNotificationMessageExamples.pushNotificationMessage); + message: PushNotificationMessageExamples.pushNotificationMessage, + ); } } Future publishDataMessageToChannel() async { await ensureRealtimeClientConnected(); if (useRealtimeClient) { - await _realtimeChannel! - .publish(message: PushNotificationMessageExamples.pushDataMessage); + await _realtimeChannel!.publish( + message: PushNotificationMessageExamples.pushDataMessage, + ); } else { - await _restChannel! - .publish(message: PushNotificationMessageExamples.pushDataMessage); + await _restChannel!.publish( + message: PushNotificationMessageExamples.pushDataMessage, + ); } } @@ -188,10 +196,12 @@ class PushNotificationService { await ensureRealtimeClientConnected(); if (useRealtimeClient) { await _realtimeChannel!.publish( - message: PushNotificationMessageExamples.pushDataNotificationMessage); + message: PushNotificationMessageExamples.pushDataNotificationMessage, + ); } else { await _restChannel!.publish( - message: PushNotificationMessageExamples.pushDataNotificationMessage); + message: PushNotificationMessageExamples.pushDataNotificationMessage, + ); } } @@ -208,15 +218,18 @@ class PushNotificationService { void _getChannels() { _hasPushChannelSubject.add(false); if (useRealtimeClient) { - _realtimeChannel = - _realtime.channels.get(Constants.channelNameForPushNotifications); + _realtimeChannel = _realtime.channels.get( + Constants.channelNameForPushNotifications, + ); _pushChannel = _realtimeChannel!.push; - _pushLogMetaChannel = - _realtime.channels.get(Constants.pushMetaChannelName); + _pushLogMetaChannel = _realtime.channels.get( + Constants.pushMetaChannelName, + ); _hasPushChannelSubject.add(true); } else { - _restChannel = - _rest.channels.get(Constants.channelNameForPushNotifications); + _restChannel = _rest.channels.get( + Constants.channelNameForPushNotifications, + ); _pushChannel = _restChannel!.push; _hasPushChannelSubject.add(true); } @@ -227,7 +240,7 @@ class PushNotificationService { /// ably-cocoa will only give the one you specify in params. /// This behavior is the same for [listSubscriptionsWithDeviceId] Future> - listSubscriptionsWithClientId() async { + listSubscriptionsWithClientId() async { await getDevice(); final subscriptions = await _pushChannel!.listSubscriptions({ 'clientId': localDeviceStream.value!.clientId!, @@ -239,7 +252,7 @@ class PushNotificationService { } Future> - listSubscriptionsWithDeviceId() async { + listSubscriptionsWithDeviceId() async { await getDevice(); final subscriptions = await _pushChannel!.listSubscriptions({ 'deviceId': localDeviceStream.value!.id!, diff --git a/example/lib/ui/ably_service.dart b/example/lib/ui/ably_service.dart index d812df3d9..8ff207726 100644 --- a/example/lib/ui/ably_service.dart +++ b/example/lib/ui/ably_service.dart @@ -36,27 +36,31 @@ class AblyService { } class ExampleMessages { - static ably.Message message = ably.Message(data: const { - 'I am': null, - 'and': { - 'also': 'nested', - 'too': {'deep': true} - } - }); + static ably.Message message = ably.Message( + data: const { + 'I am': null, + 'and': { + 'also': 'nested', + 'too': {'deep': true}, + }, + }, + ); static List messages = [ ably.Message(data: 42), ably.Message(data: const {'are': 'you'}), ably.Message(data: 'ok?'), - ably.Message(data: const [ - false, - { - 'I am': null, - 'and': { - 'also': 'nested', - 'too': {'deep': true} - } - } - ]), + ably.Message( + data: const [ + false, + { + 'I am': null, + 'and': { + 'also': 'nested', + 'too': {'deep': true}, + }, + }, + ], + ), ]; } diff --git a/example/lib/ui/api_key_service.dart b/example/lib/ui/api_key_service.dart index f5d54518f..951e4c3ac 100644 --- a/example/lib/ui/api_key_service.dart +++ b/example/lib/ui/api_key_service.dart @@ -8,10 +8,7 @@ class ApiKeyService { Future getOrProvisionApiKey() async { if (envKey.isNotEmpty && envKey != defaultEnvKeyPlaceholder) { - return ApiKeyProvision( - key: envKey, - source: ApiKeySource.env, - ); + return ApiKeyProvision(key: envKey, source: ApiKeySource.env); } else { final provisionedKey = await AppProvisioning().provisionApp(); return ApiKeyProvision( @@ -27,13 +24,7 @@ class ApiKeyProvision { ApiKeySource source; - ApiKeyProvision({ - required this.key, - required this.source, - }); + ApiKeyProvision({required this.key, required this.source}); } -enum ApiKeySource { - env, - testProvision, -} +enum ApiKeySource { env, testProvision } diff --git a/example/lib/ui/auth.dart b/example/lib/ui/auth.dart index 30c3b1aaa..d0d87ac1b 100644 --- a/example/lib/ui/auth.dart +++ b/example/lib/ui/auth.dart @@ -16,20 +16,23 @@ Future> getTokenDetails( ]) async { final stringToBase64 = utf8.fuse(base64); final encoded = stringToBase64.encode('$keyName:$keySecret'); - final r = await const RetryOptions( - maxAttempts: 5, - delayFactor: Duration(seconds: 2), - ).retry(() => http.post( - Uri.parse(_tokenDetailsURL(keyName, prefix)), - headers: { - 'Authorization': 'Basic $encoded', - 'Content-Type': 'application/json', - }, - body: json.encode({ - 'keyName': keyName, - 'timestamp': DateTime.now().millisecondsSinceEpoch, - }), - )); + final r = + await const RetryOptions( + maxAttempts: 5, + delayFactor: Duration(seconds: 2), + ).retry( + () => http.post( + Uri.parse(_tokenDetailsURL(keyName, prefix)), + headers: { + 'Authorization': 'Basic $encoded', + 'Content-Type': 'application/json', + }, + body: json.encode({ + 'keyName': keyName, + 'timestamp': DateTime.now().millisecondsSinceEpoch, + }), + ), + ); print('tokenDetails from server: ${r.body}'); return Map.castFrom( jsonDecode(r.body) as Map, diff --git a/example/lib/ui/bool_stream_button.dart b/example/lib/ui/bool_stream_button.dart index bd1dd0a5a..8c4514879 100644 --- a/example/lib/ui/bool_stream_button.dart +++ b/example/lib/ui/bool_stream_button.dart @@ -38,11 +38,10 @@ class BoolStreamButton extends StatelessWidget { @override Widget build(BuildContext context) => StreamBuilder( - stream: (streams != null) ? combineStreams(streams!) : stream, - builder: (context, snapshot) => TextButton( - onPressed: - (snapshot.hasData && snapshot.data == true) ? onPressed : null, - child: child, - ), - ); + stream: (streams != null) ? combineStreams(streams!) : stream, + builder: (context, snapshot) => TextButton( + onPressed: (snapshot.hasData && snapshot.data == true) ? onPressed : null, + child: child, + ), + ); } diff --git a/example/lib/ui/paginated_result_viewer.dart b/example/lib/ui/paginated_result_viewer.dart index 8be6538ca..417f31729 100644 --- a/example/lib/ui/paginated_result_viewer.dart +++ b/example/lib/ui/paginated_result_viewer.dart @@ -24,8 +24,9 @@ class PaginatedResultViewer extends HookWidget { }) : super(key: key); Future getFirstPaginatedResult( - ValueNotifier?> currentPaginatedResult, - ValueNotifier pageNumber) async { + ValueNotifier?> currentPaginatedResult, + ValueNotifier pageNumber, + ) async { final result = await query(); firstPaginatedResult = result; currentPaginatedResult.value = result; @@ -43,9 +44,9 @@ class PaginatedResultViewer extends HookWidget { return; } if (pageNumber.value == 1) { - currentPaginatedResult.value! - .first() - .then((result) => currentPaginatedResult.value = result); + currentPaginatedResult.value!.first().then( + (result) => currentPaginatedResult.value = result, + ); } else if (currentPaginatedResult.value!.hasNext()) { currentPaginatedResult.value!.next().then((result) { currentPaginatedResult.value = result; @@ -73,7 +74,7 @@ class PaginatedResultViewer extends HookWidget { onPressed: () => getFirstPaginatedResult(currentPaginatedResult, pageNumber), icon: const Icon(Icons.refresh), - ) + ), ], ), if (subtitle != null) @@ -88,19 +89,22 @@ class PaginatedResultViewer extends HookWidget { children: (items.isEmpty) ? [const Text('No messages')] : items - .map((item) => Padding( + .map( + (item) => Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: builder(context, item, null), - )) - .toList(), + ), + ) + .toList(), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextRow('Page', '#${pageNumber.value}'), TextButton( - onPressed: - pageNumber.value != 1 ? () => pageNumber.value = 1 : null, + onPressed: pageNumber.value != 1 + ? () => pageNumber.value = 1 + : null, child: const Text('Go to first page'), ), TextButton( @@ -112,7 +116,7 @@ class PaginatedResultViewer extends HookWidget { child: const Text('Next page'), ), ], - ) + ), ], ); } diff --git a/example/lib/ui/push_notifications/push_notifications_activation_sliver.dart b/example/lib/ui/push_notifications/push_notifications_activation_sliver.dart index 3d7725a8a..16c7c5279 100644 --- a/example/lib/ui/push_notifications/push_notifications_activation_sliver.dart +++ b/example/lib/ui/push_notifications/push_notifications_activation_sliver.dart @@ -15,20 +15,23 @@ class PushNotificationsActivationSliver extends HookWidget { const PushNotificationsActivationSliver({ required PushNotificationService pushNotificationService, Key? key, - }) : _pushNotificationService = pushNotificationService, - super(key: key); + }) : _pushNotificationService = pushNotificationService, + super(key: key); Future showErrorDialog( - BuildContext context, ably.AblyException error) async { + BuildContext context, + ably.AblyException error, + ) async { await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Push notification error'), - content: - Text('Failed to perform operation on push notification service. ' - 'Please verify your push notification setup with Readme ' - 'files in the ably-flutter repository.\n\n' - '${error.errorInfo?.message}'), + content: Text( + 'Failed to perform operation on push notification service. ' + 'Please verify your push notification setup with Readme ' + 'files in the ably-flutter repository.\n\n' + '${error.errorInfo?.message}', + ), ), ); } @@ -66,16 +69,25 @@ class PushNotificationsActivationSliver extends HookWidget { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: RichText( - text: const TextSpan(children: [ - TextSpan( - text: 'Warning: ', - style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold)), - TextSpan( - text: 'APNs is not available on iOS simulators, so you cannot ' - 'activate the device Ably, since this step requires the' - ' APNs device token.', - style: TextStyle(color: Colors.black)) - ])), + text: const TextSpan( + children: [ + TextSpan( + text: 'Warning: ', + style: TextStyle( + color: Colors.red, + fontWeight: FontWeight.bold, + ), + ), + TextSpan( + text: + 'APNs is not available on iOS simulators, so you cannot ' + 'activate the device Ably, since this step requires the' + ' APNs device token.', + style: TextStyle(color: Colors.black), + ), + ], + ), + ), ); } else { return const SizedBox.shrink(); @@ -87,9 +99,9 @@ class PushNotificationsActivationSliver extends HookWidget { final isIOSSimulator = useState(false); useEffect(() { if (Platform.isIOS) { - DeviceInfoPlugin() - .iosInfo - .then((info) => isIOSSimulator.value = !info.isPhysicalDevice); + DeviceInfoPlugin().iosInfo.then( + (info) => isIOSSimulator.value = !info.isPhysicalDevice, + ); } return; }); @@ -108,29 +120,34 @@ class PushNotificationsActivationSliver extends HookWidget { children: [ Expanded( child: BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: () => handleActivateDeviceButton(context), - child: const Text('Activate device')), + stream: _pushNotificationService.hasPushChannelStream, + onPressed: () => handleActivateDeviceButton(context), + child: const Text('Activate device'), + ), ), Expanded( child: BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: () => handleDeactivateDeviceButton(context), - child: const Text('Deactivate device')), + stream: _pushNotificationService.hasPushChannelStream, + onPressed: () => handleDeactivateDeviceButton(context), + child: const Text('Deactivate device'), + ), ), Expanded( child: BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: () => handleResetDeviceButton(context), - child: const Text('Reset activation')), - ) + stream: _pushNotificationService.hasPushChannelStream, + onPressed: () => handleResetDeviceButton(context), + child: const Text('Reset activation'), + ), + ), ], ), - const Text('Once devices are activated, a Push Admin can ' - "send push messages to devices by it's device ID, client ID or " - 'FCM/ APNs token. To send push messages between users, the ' - 'device must push-subscribe to the channel and a push payload ' - 'is added to the channel message.'), + const Text( + 'Once devices are activated, a Push Admin can ' + "send push messages to devices by it's device ID, client ID or " + 'FCM/ APNs token. To send push messages between users, the ' + 'device must push-subscribe to the channel and a push payload ' + 'is added to the channel message.', + ), ], ), ); @@ -139,20 +156,24 @@ class PushNotificationsActivationSliver extends HookWidget { Future showPermissionReminder(BuildContext context) async { if (Platform.isIOS) { final authorizationStatus = _pushNotificationService - .notificationSettingsStream.value.authorizationStatus; + .notificationSettingsStream + .value + .authorizationStatus; if (authorizationStatus == ably.UNAuthorizationStatus.notDetermined) { await showDialog( context: context, builder: (context) => CupertinoAlertDialog( title: const Text('Reminder for the developer'), content: const Text( - 'You should request permission to show notifications to the ' - 'user or a provisional permissions.'), + 'You should request permission to show notifications to the ' + 'user or a provisional permissions.', + ), actions: [ CupertinoDialogAction( onPressed: () { _pushNotificationService.requestNotificationPermission( - provisional: true); + provisional: true, + ); Navigator.pop(context); }, child: const Text('Request provisional permission'), @@ -173,12 +194,13 @@ class PushNotificationsActivationSliver extends HookWidget { ); } else if (authorizationStatus == ably.UNAuthorizationStatus.denied) { await Fluttertoast.showToast( - msg: 'The user has previously denied notifications from this app.', - toastLength: Toast.LENGTH_LONG, - gravity: ToastGravity.CENTER, - backgroundColor: Colors.red, - textColor: Colors.white, - fontSize: 16); + msg: 'The user has previously denied notifications from this app.', + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.CENTER, + backgroundColor: Colors.red, + textColor: Colors.white, + fontSize: 16, + ); } } } diff --git a/example/lib/ui/push_notifications/push_notifications_device_information.dart b/example/lib/ui/push_notifications/push_notifications_device_information.dart index a4e85652b..4b5b7dd64 100644 --- a/example/lib/ui/push_notifications/push_notifications_device_information.dart +++ b/example/lib/ui/push_notifications/push_notifications_device_information.dart @@ -9,56 +9,67 @@ class PushNotificationsDeviceInformation extends StatelessWidget { const PushNotificationsDeviceInformation({ required PushNotificationService pushNotificationService, Key? key, - }) : _pushNotificationService = pushNotificationService, - super(key: key); + }) : _pushNotificationService = pushNotificationService, + super(key: key); @override Widget build(BuildContext context) => Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Local Device information', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - StreamBuilder( - stream: _pushNotificationService.localDeviceStream, - builder: (context, snapshot) { - if (snapshot.hasData && snapshot.data != null) { - final localDevice = snapshot.data!; - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - TextRow('deviceId', localDevice.id), - TextRow('clientId', localDevice.clientId), - TextRow('platform', localDevice.platform.toString()), - TextRow('formFactor', localDevice.formFactor.toString()), - TextRow('metadata', localDevice.metadata.toString()), - TextRow('DevicePushDetails state', - localDevice.push.state.toString()), - TextRow('DevicePushDetails recipient', - '${localDevice.push.recipient}'), - TextButton( - onPressed: _pushNotificationService.getDevice, - child: const Text('Refresh local device information'), - ), - ], - ); - } - return RichText( - text: const TextSpan(children: [ + padding: const EdgeInsets.symmetric(vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Text( + 'Local Device information', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + StreamBuilder( + stream: _pushNotificationService.localDeviceStream, + builder: (context, snapshot) { + if (snapshot.hasData && snapshot.data != null) { + final localDevice = snapshot.data!; + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + TextRow('deviceId', localDevice.id), + TextRow('clientId', localDevice.clientId), + TextRow('platform', localDevice.platform.toString()), + TextRow('formFactor', localDevice.formFactor.toString()), + TextRow('metadata', localDevice.metadata.toString()), + TextRow( + 'DevicePushDetails state', + localDevice.push.state.toString(), + ), + TextRow( + 'DevicePushDetails recipient', + '${localDevice.push.recipient}', + ), + TextButton( + onPressed: _pushNotificationService.getDevice, + child: const Text('Refresh local device information'), + ), + ], + ); + } + return RichText( + text: const TextSpan( + children: [ TextSpan( - text: 'Warning: ', - style: TextStyle( - color: Colors.red, fontWeight: FontWeight.bold)), + text: 'Warning: ', + style: TextStyle( + color: Colors.red, + fontWeight: FontWeight.bold, + ), + ), TextSpan( - text: 'no local device information yet.', - style: TextStyle(color: Colors.black)) - ])); - }, - ), - ], + text: 'no local device information yet.', + style: TextStyle(color: Colors.black), + ), + ], + ), + ); + }, ), - ); + ], + ), + ); } diff --git a/example/lib/ui/push_notifications/push_notifications_ios_permissions_sliver.dart b/example/lib/ui/push_notifications/push_notifications_ios_permissions_sliver.dart index 54b985a57..79aee074d 100644 --- a/example/lib/ui/push_notifications/push_notifications_ios_permissions_sliver.dart +++ b/example/lib/ui/push_notifications/push_notifications_ios_permissions_sliver.dart @@ -13,8 +13,8 @@ class PushNotificationsIOSNotificationSettingsSliver extends StatelessWidget { const PushNotificationsIOSNotificationSettingsSliver({ required PushNotificationService pushNotificationService, Key? key, - }) : _pushNotificationService = pushNotificationService, - super(key: key); + }) : _pushNotificationService = pushNotificationService, + super(key: key); Widget buildIOSPermissionSliver() { if (Platform.isIOS) { @@ -42,15 +42,18 @@ class PushNotificationsIOSNotificationSettingsSliver extends StatelessWidget { stream: _pushNotificationService.hasPushChannelStream, onPressed: () { _pushNotificationService.requestNotificationPermission( - provisional: true); + provisional: true, + ); Fluttertoast.showToast( - msg: 'Notifications will be delivered silently to ' - 'the notification center.', - toastLength: Toast.LENGTH_LONG, - gravity: ToastGravity.CENTER, - backgroundColor: Colors.red, - textColor: Colors.white, - fontSize: 16); + msg: + 'Notifications will be delivered silently to ' + 'the notification center.', + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.CENTER, + backgroundColor: Colors.red, + textColor: Colors.white, + fontSize: 16, + ); }, child: const Text('Request Provisional Permission (no alert)'), ); @@ -80,22 +83,32 @@ class PushNotificationsIOSNotificationSettingsSliver extends StatelessWidget { 'iOS Notification Settings', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), - TextRow('Authorization Status', - '${settings.authorizationStatus}'), + TextRow( + 'Authorization Status', + '${settings.authorizationStatus}', + ), TextRow('Sound', '${settings.soundSetting}'), TextRow('Badge', '${settings.badgeSetting}'), TextRow('Alert', '${settings.alertSetting}'), - TextRow('Notification Center', - '${settings.notificationCenterSetting}'), + TextRow( + 'Notification Center', + '${settings.notificationCenterSetting}', + ), TextRow('Lock Screen', '${settings.lockScreenSetting}'), TextRow('Alert Style', '${settings.alertStyle}'), TextRow('Shows Preview', '${settings.showPreviewsSetting}'), TextRow( - 'Critical Alerts', '${settings.criticalAlertSetting}'), - TextRow('providesAppNotificationSettings', - '${settings.providesAppNotificationSettings}'), + 'Critical Alerts', + '${settings.criticalAlertSetting}', + ), TextRow( - 'Siri announcements', '${settings.announcementSetting}'), + 'providesAppNotificationSettings', + '${settings.providesAppNotificationSettings}', + ), + TextRow( + 'Siri announcements', + '${settings.announcementSetting}', + ), TextButton( onPressed: _pushNotificationService.updateNotificationSettings, @@ -114,9 +127,6 @@ class PushNotificationsIOSNotificationSettingsSliver extends StatelessWidget { @override Widget build(BuildContext context) => Column( - children: [ - buildIOSPermissionSliver(), - buildIOSNotificationSettings(), - ], - ); + children: [buildIOSPermissionSliver(), buildIOSNotificationSettings()], + ); } diff --git a/example/lib/ui/push_notifications/push_notifications_publishing_sliver.dart b/example/lib/ui/push_notifications/push_notifications_publishing_sliver.dart index d29e2ee8b..788b146a4 100644 --- a/example/lib/ui/push_notifications/push_notifications_publishing_sliver.dart +++ b/example/lib/ui/push_notifications/push_notifications_publishing_sliver.dart @@ -10,48 +10,49 @@ class PushNotificationsPublishingSliver extends StatelessWidget { const PushNotificationsPublishingSliver({ required PushNotificationService pushNotificationService, Key? key, - }) : _pushNotificationService = pushNotificationService, - super(key: key); + }) : _pushNotificationService = pushNotificationService, + super(key: key); @override Widget build(BuildContext context) => Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + padding: const EdgeInsets.symmetric(vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Text( + 'Publishing to ' + '"${Constants.channelNameForPushNotifications}"', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + const Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: Text( + 'Each message sent contains a push payload, ' + 'in the ably.Message.extras field.', + ), + ), + Row( children: [ - const Text( - 'Publishing to ' - '"${Constants.channelNameForPushNotifications}"', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const Padding( - padding: EdgeInsets.symmetric(vertical: 8), - child: Text('Each message sent contains a push payload, ' - 'in the ably.Message.extras field.'), - ), - Row( - children: [ - BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: _pushNotificationService - .publishNotificationMessageToChannel, - child: const Text('Notification Message'), - ), - BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: - _pushNotificationService.publishDataMessageToChannel, - child: const Text('Data Message'), - ), - ], + BoolStreamButton( + stream: _pushNotificationService.hasPushChannelStream, + onPressed: + _pushNotificationService.publishNotificationMessageToChannel, + child: const Text('Notification Message'), ), BoolStreamButton( stream: _pushNotificationService.hasPushChannelStream, - onPressed: _pushNotificationService - .publishDataNotificationMessageToChannel, - child: const Text('Data + Notification Message'), + onPressed: _pushNotificationService.publishDataMessageToChannel, + child: const Text('Data Message'), ), ], ), - ); + BoolStreamButton( + stream: _pushNotificationService.hasPushChannelStream, + onPressed: + _pushNotificationService.publishDataNotificationMessageToChannel, + child: const Text('Data + Notification Message'), + ), + ], + ), + ); } diff --git a/example/lib/ui/push_notifications/push_notifications_received_sliver.dart b/example/lib/ui/push_notifications/push_notifications_received_sliver.dart index 1b5b9a663..1ba679589 100644 --- a/example/lib/ui/push_notifications/push_notifications_received_sliver.dart +++ b/example/lib/ui/push_notifications/push_notifications_received_sliver.dart @@ -4,60 +4,65 @@ import 'package:ably_flutter_example/ui/text_row.dart'; import 'package:flutter/material.dart'; class PushNotificationsReceivedSliver extends StatelessWidget { - const PushNotificationsReceivedSliver({ - Key? key, - }) : super(key: key); + const PushNotificationsReceivedSliver({Key? key}) : super(key: key); @override Widget build(BuildContext context) => Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + padding: const EdgeInsets.symmetric(vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Received messages', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - IconButton( - onPressed: PushNotificationHandlers.clearReceivedMessages, - icon: Icon(Icons.delete)) - ], + Text( + 'Received messages', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + IconButton( + onPressed: PushNotificationHandlers.clearReceivedMessages, + icon: Icon(Icons.delete), ), - StreamBuilder>( - stream: PushNotificationHandlers.receivedMessagesStream, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return const Text('Widget not loaded yet.'); - } - final messages = snapshot.data; - if (messages!.isEmpty) { - return const Text('No messages yet'); - } else { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: messages - .map((e) => Padding( - padding: - const EdgeInsets.symmetric(vertical: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TextRow('Notification Title', - e.notification?.title ?? 'NO TITLE'), - TextRow('Notification Body', - e.notification?.body ?? 'NO BODY'), - TextRow('Data', e.data.toString()), - ], - ), - )) - .toList(), - ); - } - }), ], ), - ); + StreamBuilder>( + stream: PushNotificationHandlers.receivedMessagesStream, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return const Text('Widget not loaded yet.'); + } + final messages = snapshot.data; + if (messages!.isEmpty) { + return const Text('No messages yet'); + } else { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: messages + .map( + (e) => Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextRow( + 'Notification Title', + e.notification?.title ?? 'NO TITLE', + ), + TextRow( + 'Notification Body', + e.notification?.body ?? 'NO BODY', + ), + TextRow('Data', e.data.toString()), + ], + ), + ), + ) + .toList(), + ); + } + }, + ), + ], + ), + ); } diff --git a/example/lib/ui/push_notifications/push_notifications_sliver.dart b/example/lib/ui/push_notifications/push_notifications_sliver.dart index 0653c4d62..2da18dcf1 100644 --- a/example/lib/ui/push_notifications/push_notifications_sliver.dart +++ b/example/lib/ui/push_notifications/push_notifications_sliver.dart @@ -12,49 +12,51 @@ class PushNotificationsSliver extends StatelessWidget { final PushNotificationService _pushNotificationService; const PushNotificationsSliver(this._pushNotificationService, {Key? key}) - : super(key: key); + : super(key: key); @override Widget build(BuildContext context) => Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Padding( - padding: EdgeInsets.only(bottom: 16), - child: Text( - 'Push Notifications', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - ), - buildSummaryText(), - PushNotificationsActivationSliver( - pushNotificationService: _pushNotificationService, - ), - PushNotificationsDeviceInformation( - pushNotificationService: _pushNotificationService, - ), - PushNotificationsIOSNotificationSettingsSliver( - pushNotificationService: _pushNotificationService, - ), - PushNotificationsSubscriptionsSliver( - pushNotificationService: _pushNotificationService, - ), - PushNotificationsPublishingSliver( - pushNotificationService: _pushNotificationService), - const PushNotificationsReceivedSliver(), - PushRealtimeClientReceivedSliver( - pushNotificationService: _pushNotificationService, - ), - ], - ); + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Padding( + padding: EdgeInsets.only(bottom: 16), + child: Text( + 'Push Notifications', + style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + ), + ), + buildSummaryText(), + PushNotificationsActivationSliver( + pushNotificationService: _pushNotificationService, + ), + PushNotificationsDeviceInformation( + pushNotificationService: _pushNotificationService, + ), + PushNotificationsIOSNotificationSettingsSliver( + pushNotificationService: _pushNotificationService, + ), + PushNotificationsSubscriptionsSliver( + pushNotificationService: _pushNotificationService, + ), + PushNotificationsPublishingSliver( + pushNotificationService: _pushNotificationService, + ), + const PushNotificationsReceivedSliver(), + PushRealtimeClientReceivedSliver( + pushNotificationService: _pushNotificationService, + ), + ], + ); Widget buildSummaryText() => const Column( - children: [ - Text( - 'Activate your device, view your local device information, ' - 'subscribe to a push channel with either your device or ' - 'client ID, and then publish to the channel.', - style: TextStyle(color: Colors.black)), - SizedBox(height: 16), - ], - ); + children: [ + Text( + 'Activate your device, view your local device information, ' + 'subscribe to a push channel with either your device or ' + 'client ID, and then publish to the channel.', + style: TextStyle(color: Colors.black), + ), + SizedBox(height: 16), + ], + ); } diff --git a/example/lib/ui/push_notifications/push_notifications_subscriptions_sliver.dart b/example/lib/ui/push_notifications/push_notifications_subscriptions_sliver.dart index f8b395bc5..4f0f684a6 100644 --- a/example/lib/ui/push_notifications/push_notifications_subscriptions_sliver.dart +++ b/example/lib/ui/push_notifications/push_notifications_subscriptions_sliver.dart @@ -11,166 +11,186 @@ class PushNotificationsSubscriptionsSliver extends StatelessWidget { const PushNotificationsSubscriptionsSliver({ required PushNotificationService pushNotificationService, Key? key, - }) : _pushNotificationService = pushNotificationService, - super(key: key); + }) : _pushNotificationService = pushNotificationService, + super(key: key); Widget buildSubscriptionsList( - Stream> stream) => - StreamBuilder>( - stream: stream, - builder: (context, snapshot) { - if (snapshot.hasData) { - final subscriptions = snapshot.data - as ably.PaginatedResult; + Stream> stream, + ) => StreamBuilder>( + stream: stream, + builder: (context, snapshot) { + if (snapshot.hasData) { + final subscriptions = + snapshot.data as ably.PaginatedResult; - if (subscriptions.items.isEmpty) { - return const Text('No subscriptions'); - } + if (subscriptions.items.isEmpty) { + return const Text('No subscriptions'); + } - final theresMoreSubscriptionsWidget = subscriptions.hasNext() - ? const Text('and more...') - : const SizedBox.shrink(); + final theresMoreSubscriptionsWidget = subscriptions.hasNext() + ? const Text('and more...') + : const SizedBox.shrink(); - return Column(children: [ - ...subscriptions.items - .map( - (e) => Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Container( - color: Colors.grey[200], - child: Column(children: [ - Text('Channel: ${e.channel}'), - if (e.deviceId != null) - Text('DeviceId: ${e.deviceId!}') - else - Text('ClientId: ${e.clientId}'), - ]), - ), + return Column( + children: [ + ...subscriptions.items + .map( + (e) => Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Container( + color: Colors.grey[200], + child: Column( + children: [ + Text('Channel: ${e.channel}'), + if (e.deviceId != null) + Text('DeviceId: ${e.deviceId!}') + else + Text('ClientId: ${e.clientId}'), + ], ), - ) - .toList(), - theresMoreSubscriptionsWidget - ]); - } - return const Text('List subscription button not pressed.'); - }); + ), + ), + ) + .toList(), + theresMoreSubscriptionsWidget, + ], + ); + } + return const Text('List subscription button not pressed.'); + }, + ); @override Widget build(BuildContext context) => Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + padding: const EdgeInsets.symmetric(vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Padding( + padding: EdgeInsets.only(bottom: 8), + child: Text( + 'Push channel subscriptions', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + ), + const Text( + 'You need to use a token/ key with the Push Admin capability ' + 'to list subscriptions by client ID or device ID. ' + 'If you subscribe both device and client to the channel, ' + 'the device will receive 2 notifications.', + ), + Row( children: [ - const Padding( - padding: EdgeInsets.only(bottom: 8), - child: Text( - 'Push channel subscriptions', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + Expanded( + child: BoolStreamButton( + stream: _pushNotificationService.hasPushChannelStream, + onPressed: () async { + try { + await _pushNotificationService.subscribeDevice(); + } on ably.AblyException catch (ablyException) { + await showPushActivationError(context, ablyException); + } + }, + child: const Text('Subscribe device'), ), ), - const Text( - 'You need to use a token/ key with the Push Admin capability ' - 'to list subscriptions by client ID or device ID. ' - 'If you subscribe both device and client to the channel, ' - 'the device will receive 2 notifications.'), - Row( - children: [ - Expanded( - child: BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: () async { - try { - await _pushNotificationService.subscribeDevice(); - } on ably.AblyException catch (ablyException) { - await showPushActivationError(context, ablyException); - } - }, - child: const Text('Subscribe device')), - ), - Expanded( - child: BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: () async { - try { - await _pushNotificationService.unsubscribeDevice(); - } on ably.AblyException catch (ablyException) { - await showPushActivationError(context, ablyException); - } - }, - child: const Text('Unsubscribe device'), - ), - ), - ], + Expanded( + child: BoolStreamButton( + stream: _pushNotificationService.hasPushChannelStream, + onPressed: () async { + try { + await _pushNotificationService.unsubscribeDevice(); + } on ably.AblyException catch (ablyException) { + await showPushActivationError(context, ablyException); + } + }, + child: const Text('Unsubscribe device'), + ), ), - BoolStreamButton( + ], + ), + BoolStreamButton( + stream: _pushNotificationService.hasPushChannelStream, + onPressed: () async { + final subscriptions = await _pushNotificationService + .listSubscriptionsWithDeviceId(); + print('Push subscriptions: ${subscriptions.items}'); + }, + child: const Text('List subscriptions with current device ID'), + ), + buildSubscriptionsList( + _pushNotificationService.pushChannelDeviceSubscriptionsStream, + ), + Row( + children: [ + Expanded( + child: BoolStreamButton( stream: _pushNotificationService.hasPushChannelStream, onPressed: () async { - final subscriptions = await _pushNotificationService - .listSubscriptionsWithDeviceId(); - print('Push subscriptions: ${subscriptions.items}'); + try { + await _pushNotificationService.subscribeClient(); + } on ably.AblyException catch (ablyException) { + await showPushActivationError(context, ablyException); + } }, - child: const Text('List subscriptions with current device ID')), - buildSubscriptionsList( - _pushNotificationService.pushChannelDeviceSubscriptionsStream), - Row( - children: [ - Expanded( - child: BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: () async { - try { - await _pushNotificationService.subscribeClient(); - } on ably.AblyException catch (ablyException) { - await showPushActivationError(context, ablyException); - } - }, - child: const Text('Subscribe client')), - ), - Expanded( - child: BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: () async { - try { - await _pushNotificationService.unsubscribeClient(); - } on ably.AblyException catch (ablyException) { - await showPushActivationError(context, ablyException); - } - }, - child: const Text('Unsubscribe client')), - ) - ], + child: const Text('Subscribe client'), + ), ), - BoolStreamButton( + Expanded( + child: BoolStreamButton( stream: _pushNotificationService.hasPushChannelStream, onPressed: () async { - final subscriptions = await _pushNotificationService - .listSubscriptionsWithClientId(); - print('Push subscriptions: ${subscriptions.items}'); + try { + await _pushNotificationService.unsubscribeClient(); + } on ably.AblyException catch (ablyException) { + await showPushActivationError(context, ablyException); + } }, - child: const Text('List subscriptions with current client ID')), - buildSubscriptionsList( - _pushNotificationService.pushChannelClientSubscriptionsStream), - buildWarningTextForListSubscriptionsOnAndroid(), + child: const Text('Unsubscribe client'), + ), + ), ], ), - ); + BoolStreamButton( + stream: _pushNotificationService.hasPushChannelStream, + onPressed: () async { + final subscriptions = await _pushNotificationService + .listSubscriptionsWithClientId(); + print('Push subscriptions: ${subscriptions.items}'); + }, + child: const Text('List subscriptions with current client ID'), + ), + buildSubscriptionsList( + _pushNotificationService.pushChannelClientSubscriptionsStream, + ), + buildWarningTextForListSubscriptionsOnAndroid(), + ], + ), + ); Widget buildWarningTextForListSubscriptionsOnAndroid() { if (Platform.isAndroid) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: RichText( - text: - const TextSpan(style: TextStyle(color: Colors.black), children: [ - TextSpan( + text: const TextSpan( + style: TextStyle(color: Colors.black), + children: [ + TextSpan( text: 'Warning: ', - style: - TextStyle(color: Colors.red, fontWeight: FontWeight.bold)), - TextSpan( - text: 'A bug in ably-java means all client ID and device ' + style: TextStyle( + color: Colors.red, + fontWeight: FontWeight.bold, + ), + ), + TextSpan( + text: + 'A bug in ably-java means all client ID and device ' 'ID subscriptions are returned when you call ' - 'push.listSubscriptions. Track ably-java issue #705'), - ]), + 'push.listSubscriptions. Track ably-java issue #705', + ), + ], + ), ), ); } @@ -180,16 +200,16 @@ class PushNotificationsSubscriptionsSliver extends StatelessWidget { Future showPushActivationError( BuildContext context, ably.AblyException exception, - ) async => - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Push notification error'), - content: - Text('Failed to perform operation on push notification service. ' - 'Please verify your push notification setup with Readme ' - 'files in the ably-flutter repository.\n\n' - '${exception.errorInfo?.message}'), - ), - ); + ) async => showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Push notification error'), + content: Text( + 'Failed to perform operation on push notification service. ' + 'Please verify your push notification setup with Readme ' + 'files in the ably-flutter repository.\n\n' + '${exception.errorInfo?.message}', + ), + ), + ); } diff --git a/example/lib/ui/push_notifications/push_realtime_client_received_sliver.dart b/example/lib/ui/push_notifications/push_realtime_client_received_sliver.dart index 84a66804e..cdf8539e7 100644 --- a/example/lib/ui/push_notifications/push_realtime_client_received_sliver.dart +++ b/example/lib/ui/push_notifications/push_realtime_client_received_sliver.dart @@ -9,35 +9,44 @@ class PushRealtimeClientReceivedSliver extends StatelessWidget { const PushRealtimeClientReceivedSliver({ required PushNotificationService pushNotificationService, Key? key, - }) : _pushNotificationService = pushNotificationService, - super(key: key); + }) : _pushNotificationService = pushNotificationService, + super(key: key); @override Widget build(BuildContext context) => Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Column( - children: [ - const Text( - 'Debugging messages (via realtime client)', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const Text('To validate messages were sent, you can subscribe to ' - 'the channel and view the device logs.'), - BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: _pushNotificationService - .subscribeToChannelWithPushChannelRule, - child: const Text('Subscribe to channel: ' - '"${Constants.channelNameForPushNotifications}"')), - const Text('To debug push notifications, ' - 'subscribe to the meta channel.'), - BoolStreamButton( - stream: _pushNotificationService.hasPushChannelStream, - onPressed: - _pushNotificationService.subscribeToPushLogMetachannel, - child: const Text('Subscribe to push metachannel: ' - '${Constants.pushMetaChannelName}')), - ], + padding: const EdgeInsets.symmetric(vertical: 8), + child: Column( + children: [ + const Text( + 'Debugging messages (via realtime client)', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), - ); + const Text( + 'To validate messages were sent, you can subscribe to ' + 'the channel and view the device logs.', + ), + BoolStreamButton( + stream: _pushNotificationService.hasPushChannelStream, + onPressed: + _pushNotificationService.subscribeToChannelWithPushChannelRule, + child: const Text( + 'Subscribe to channel: ' + '"${Constants.channelNameForPushNotifications}"', + ), + ), + const Text( + 'To debug push notifications, ' + 'subscribe to the meta channel.', + ), + BoolStreamButton( + stream: _pushNotificationService.hasPushChannelStream, + onPressed: _pushNotificationService.subscribeToPushLogMetachannel, + child: const Text( + 'Subscribe to push metachannel: ' + '${Constants.pushMetaChannelName}', + ), + ), + ], + ), + ); } diff --git a/example/lib/ui/realtime_presence_sliver.dart b/example/lib/ui/realtime_presence_sliver.dart index de5531e75..2be2778f3 100644 --- a/example/lib/ui/realtime_presence_sliver.dart +++ b/example/lib/ui/realtime_presence_sliver.dart @@ -23,47 +23,48 @@ class RealtimePresenceSliver extends HookWidget { ValueNotifier latestMessage, ably.ChannelState? channelState, ValueNotifier?> - presenceSubscription, - ) => - TextButton( - onPressed: (channelState == ably.ChannelState.attached && - presenceSubscription.value == null) - ? () { - final presenceMessageStream = channel.presence.subscribe(); - final subscription = - presenceMessageStream.listen((presenceMessage) { - latestMessage.value = presenceMessage; - }); - presenceSubscription.value = subscription; - _subscriptions.add(subscription); - } - : null, - child: const Text('Subscribe'), - ); + presenceSubscription, + ) => TextButton( + onPressed: + (channelState == ably.ChannelState.attached && + presenceSubscription.value == null) + ? () { + final presenceMessageStream = channel.presence.subscribe(); + final subscription = presenceMessageStream.listen(( + presenceMessage, + ) { + latestMessage.value = presenceMessage; + }); + presenceSubscription.value = subscription; + _subscriptions.add(subscription); + } + : null, + child: const Text('Subscribe'), + ); Widget createChannelPresenceUnsubscribeButton( ValueNotifier?> - presenceSubscription, - ) => - TextButton( - onPressed: (presenceSubscription.value != null) - ? () async { - await presenceSubscription.value!.cancel(); - presenceSubscription.value = null; - } - : null, - child: const Text('Unsubscribe'), - ); + presenceSubscription, + ) => TextButton( + onPressed: (presenceSubscription.value != null) + ? () async { + await presenceSubscription.value!.cancel(); + presenceSubscription.value = null; + } + : null, + child: const Text('Unsubscribe'), + ); Widget getRealtimeChannelPresence( - ValueNotifier> presenceMembers) => - TextButton( - onPressed: () async { - presenceMembers.value = - await channel.presence.get(const ably.RealtimePresenceParams()); - }, - child: const Text('Get Realtime presence members'), + ValueNotifier> presenceMembers, + ) => TextButton( + onPressed: () async { + presenceMembers.value = await channel.presence.get( + const ably.RealtimePresenceParams(), ); + }, + child: const Text('Get Realtime presence members'), + ); final List _presenceData = [ null, @@ -74,10 +75,10 @@ class RealtimePresenceSliver extends HookWidget { 1, 'ably', null, - {'a': 'b'} + {'a': 'b'}, ], { - 'c': ['a', 'b'] + 'c': ['a', 'b'], }, ]; @@ -88,26 +89,28 @@ class RealtimePresenceSliver extends HookWidget { .toString(); Widget enterRealtimePresence() => TextButton( - onPressed: () async { - await channel.presence.enter(_nextPresenceData); - }, - child: const Text('Enter'), - ); + onPressed: () async { + await channel.presence.enter(_nextPresenceData); + }, + child: const Text('Enter'), + ); Widget updateRealtimePresence() => TextButton( - onPressed: () async { - await channel.presence - .updateClient(Constants.clientId, _nextPresenceData); - }, - child: const Text('Update'), + onPressed: () async { + await channel.presence.updateClient( + Constants.clientId, + _nextPresenceData, ); + }, + child: const Text('Update'), + ); Widget leaveRealtimePresence() => TextButton( - onPressed: () async { - await channel.presence.leave(_nextPresenceData); - }, - child: const Text('Leave'), - ); + onPressed: () async { + await channel.presence.leave(_nextPresenceData); + }, + child: const Text('Leave'), + ); @override Widget build(BuildContext context) { @@ -128,11 +131,17 @@ class RealtimePresenceSliver extends HookWidget { Row( children: [ Expanded( - child: createChannelPresenceSubscribeButton( - latestMessage, channel.state, presenceSubscription)), + child: createChannelPresenceSubscribeButton( + latestMessage, + channel.state, + presenceSubscription, + ), + ), Expanded( - child: createChannelPresenceUnsubscribeButton( - presenceSubscription)), + child: createChannelPresenceUnsubscribeButton( + presenceSubscription, + ), + ), ], ), Text( @@ -141,15 +150,9 @@ class RealtimePresenceSliver extends HookWidget { ), Row( children: [ - Expanded( - child: enterRealtimePresence(), - ), - Expanded( - child: updateRealtimePresence(), - ), - Expanded( - child: leaveRealtimePresence(), - ), + Expanded(child: enterRealtimePresence()), + Expanded(child: updateRealtimePresence()), + Expanded(child: leaveRealtimePresence()), ], ), getRealtimeChannelPresence(presenceMembers), @@ -157,11 +160,14 @@ class RealtimePresenceSliver extends HookWidget { .map((m) => Text('${m.id}:${m.clientId}:${m.data}')) .toList(), PaginatedResultViewer( - title: 'Presence history', - query: () => channel.presence - .history(ably.RealtimeHistoryParams(limit: 10)), - builder: (context, message, _) => TextRow('clientId', - '${message.id}:${message.clientId}:${message.data}')), + title: 'Presence history', + query: () => + channel.presence.history(ably.RealtimeHistoryParams(limit: 10)), + builder: (context, message, _) => TextRow( + 'clientId', + '${message.id}:${message.clientId}:${message.data}', + ), + ), ], ), ); diff --git a/example/lib/ui/realtime_sliver.dart b/example/lib/ui/realtime_sliver.dart index 1f02e0849..e3b98f75d 100644 --- a/example/lib/ui/realtime_sliver.dart +++ b/example/lib/ui/realtime_sliver.dart @@ -18,8 +18,8 @@ class RealtimeSliver extends HookWidget { List> _subscriptions = []; RealtimeSliver(this.ablyService, {Key? key}) - : realtime = ablyService.realtime, - super(key: key) { + : realtime = ablyService.realtime, + super(key: key) { channel = realtime.channels.get(Constants.channelName); } @@ -30,70 +30,71 @@ class RealtimeSliver extends HookWidget { _subscriptions = []; } - Widget buildConnectButton() => TextButton( - onPressed: realtime.connect, - child: const Text('Connect'), - ); + Widget buildConnectButton() => + TextButton(onPressed: realtime.connect, child: const Text('Connect')); Widget buildDisconnectButton(ably.ConnectionState state) => TextButton( - onPressed: - (state == ably.ConnectionState.connected) ? realtime.close : null, - child: const Text('Disconnect'), - ); + onPressed: (state == ably.ConnectionState.connected) + ? realtime.close + : null, + child: const Text('Disconnect'), + ); - Widget buildChannelAttachButton(ably.ConnectionState connectionState, - ably.ChannelState channelState) => - TextButton( - onPressed: (connectionState == ably.ConnectionState.connected && - channelState != ably.ChannelState.attached) - ? () async { - try { - await channel.attach(); - } on ably.AblyException catch (e) { - print('Unable to attach to channel: ${e.errorInfo}'); - } - } - : null, - child: const Text('Attach'), - ); + Widget buildChannelAttachButton( + ably.ConnectionState connectionState, + ably.ChannelState channelState, + ) => TextButton( + onPressed: + (connectionState == ably.ConnectionState.connected && + channelState != ably.ChannelState.attached) + ? () async { + try { + await channel.attach(); + } on ably.AblyException catch (e) { + print('Unable to attach to channel: ${e.errorInfo}'); + } + } + : null, + child: const Text('Attach'), + ); Widget buildChannelDetachButton(ably.ChannelState channelState) => TextButton( - onPressed: (channelState == ably.ChannelState.attached) - ? channel.detach - : null, - child: const Text('Detach'), - ); + onPressed: (channelState == ably.ChannelState.attached) + ? channel.detach + : null, + child: const Text('Detach'), + ); Widget buildChannelSubscribeButton( - ably.ChannelState channelState, - ValueNotifier latestMessage, - ValueNotifier?> - channelSubscription) => - TextButton( - onPressed: (channelState == ably.ChannelState.attached && - channelSubscription.value == null) - ? () { - final subscription = channel.subscribe().listen((message) { - latestMessage.value = message; - }); - channelSubscription.value = subscription; - _subscriptions.add(subscription); - } - : null, - child: const Text('Subscribe'), - ); + ably.ChannelState channelState, + ValueNotifier latestMessage, + ValueNotifier?> channelSubscription, + ) => TextButton( + onPressed: + (channelState == ably.ChannelState.attached && + channelSubscription.value == null) + ? () { + final subscription = channel.subscribe().listen((message) { + latestMessage.value = message; + }); + channelSubscription.value = subscription; + _subscriptions.add(subscription); + } + : null, + child: const Text('Subscribe'), + ); Widget buildChannelUnsubscribeButton( - ValueNotifier?> channelSubscription) => - TextButton( - onPressed: (channelSubscription.value != null) - ? () async { - await channelSubscription.value!.cancel(); - channelSubscription.value = null; - } - : null, - child: const Text('Unsubscribe'), - ); + ValueNotifier?> channelSubscription, + ) => TextButton( + onPressed: (channelSubscription.value != null) + ? () async { + await channelSubscription.value!.cancel(); + channelSubscription.value = null; + } + : null, + child: const Text('Unsubscribe'), + ); int typeCounter = 0; int realtimePubCounter = 0; @@ -102,15 +103,20 @@ class RealtimeSliver extends HookWidget { TextButton( onPressed: (channelState == ably.ChannelState.attached) ? () async { - final data = _messagesToPublish[ - (realtimePubCounter++ % _messagesToPublish.length)]; + final data = + _messagesToPublish[(realtimePubCounter++ % + _messagesToPublish.length)]; final m = ably.Message( - name: 'Message $realtimePubCounter', data: data); + name: 'Message $realtimePubCounter', + data: data, + ); try { switch (typeCounter % 3) { case 0: await channel.publish( - name: 'Message $realtimePubCounter', data: data); + name: 'Message $realtimePubCounter', + data: data, + ); break; case 1: await channel.publish(message: m); @@ -127,9 +133,7 @@ class RealtimeSliver extends HookWidget { } } : null, - child: const Text( - 'Publish', - ), + child: const Text('Publish'), ); Widget buildReleaseRealtimeChannelButton( @@ -137,55 +141,53 @@ class RealtimeSliver extends HookWidget { ValueNotifier channelState, ValueNotifier connectionId, ValueNotifier recoveryKey, - ) => - TextButton( - onPressed: () async { - await channel.detach(); - realtime.channels.release(Constants.channelName); - channel = realtime.channels.get(Constants.channelName); - setupListeners( - connectionState, channelState, connectionId, recoveryKey); - }, - child: const Text('Release'), - ); + ) => TextButton( + onPressed: () async { + await channel.detach(); + realtime.channels.release(Constants.channelName); + channel = realtime.channels.get(Constants.channelName); + setupListeners(connectionState, channelState, connectionId, recoveryKey); + }, + child: const Text('Release'), + ); Widget buildEncryptionSwitch(ValueNotifier isEnabled) => Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Enable encryption', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - Switch( - onChanged: (switchedOn) async { - isEnabled.value = switchedOn; - if (switchedOn) { - await channel.setOptions( - await ably.RealtimeChannelOptions.withCipherKey( - keyFromPassword( - Constants.examplePasswordForEncryptedChannel, - ), - ), - ); - } else { - await channel.setOptions(const ably.RealtimeChannelOptions()); - } - }, - value: isEnabled.value, - ), - ], - ); + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Enable encryption', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + Switch( + onChanged: (switchedOn) async { + isEnabled.value = switchedOn; + if (switchedOn) { + await channel.setOptions( + await ably.RealtimeChannelOptions.withCipherKey( + keyFromPassword(Constants.examplePasswordForEncryptedChannel), + ), + ); + } else { + await channel.setOptions(const ably.RealtimeChannelOptions()); + } + }, + value: isEnabled.value, + ), + ], + ); @override Widget build(BuildContext context) { - final connectionState = - useState(realtime.connection.state); + final connectionState = useState( + realtime.connection.state, + ); final connectionId = useState(realtime.connection.id); final recoveryKey = useState(''); final channelState = useState(channel.state); final latestMessage = useState(null); - final channelSubscription = - useState?>(null); + final channelSubscription = useState?>( + null, + ); final realtimeTime = useState(null); final useEncryption = useState(false); @@ -209,12 +211,8 @@ class RealtimeSliver extends HookWidget { buildEncryptionSwitch(useEncryption), Row( children: [ - Expanded( - child: buildConnectButton(), - ), - Expanded( - child: buildDisconnectButton(connectionState.value), - ) + Expanded(child: buildConnectButton()), + Expanded(child: buildDisconnectButton(connectionState.value)), ], ), const Text( @@ -225,94 +223,109 @@ class RealtimeSliver extends HookWidget { Row( children: [ Expanded( - child: buildChannelAttachButton( - connectionState.value, channelState.value)), + child: buildChannelAttachButton( + connectionState.value, + channelState.value, + ), + ), Expanded(child: buildChannelDetachButton(channelState.value)), Expanded( - child: buildReleaseRealtimeChannelButton( - connectionState, channelState, connectionId, recoveryKey)), + child: buildReleaseRealtimeChannelButton( + connectionState, + channelState, + connectionId, + recoveryKey, + ), + ), ], ), Row( children: [ Expanded( - child: buildChannelSubscribeButton( - channelState.value, latestMessage, channelSubscription)), + child: buildChannelSubscribeButton( + channelState.value, + latestMessage, + channelSubscription, + ), + ), Expanded(child: buildChannelPublishButton(channelState.value)), Expanded(child: buildChannelUnsubscribeButton(channelSubscription)), ], ), TextRow( - 'Latest message received', latestMessage.value?.data.toString()), + 'Latest message received', + latestMessage.value?.data.toString(), + ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const TextRow('Next message to be published:', null), TextRow(' Name', 'Message $realtimePubCounter'), TextRow( - ' Data', - _messagesToPublish[ - realtimePubCounter % _messagesToPublish.length] - .toString()), + ' Data', + _messagesToPublish[realtimePubCounter % _messagesToPublish.length] + .toString(), + ), ], ), - RealtimePresenceSliver( - realtime: realtime, - channel: channel, - ), + RealtimePresenceSliver(realtime: realtime, channel: channel), PaginatedResultViewer( - title: 'History', - subtitle: const Column( - children: [ - TextRow( - 'Hint', - 'Use realtime history as a way to get messages that were' - ' published before you are attached to the channel.'), - TextRow( - 'Warning', - 'If you are already attached to the channel, you must' - ' detach and re-attach to get the latest messages ' - 'published on the channel to get history whilst ' - 'connected to a realtime channel, use ' - 'RestChannel.history instead.'), - ], - ), - query: () => channel.history( - ably.RealtimeHistoryParams( - limit: 10, - untilAttach: true, - ), - ), - builder: (context, message, _) => Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TextRow('Name', message.name), - TextRow('Data', message.data.toString()), - ], - )), + title: 'History', + subtitle: const Column( + children: [ + TextRow( + 'Hint', + 'Use realtime history as a way to get messages that were' + ' published before you are attached to the channel.', + ), + TextRow( + 'Warning', + 'If you are already attached to the channel, you must' + ' detach and re-attach to get the latest messages ' + 'published on the channel to get history whilst ' + 'connected to a realtime channel, use ' + 'RestChannel.history instead.', + ), + ], + ), + query: () => channel.history( + ably.RealtimeHistoryParams(limit: 10, untilAttach: true), + ), + builder: (context, message, _) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextRow('Name', message.name), + TextRow('Data', message.data.toString()), + ], + ), + ), ], ); } void setupListeners( - ValueNotifier connectionState, - ValueNotifier channelState, - ValueNotifier connectionId, - ValueNotifier recoveryKey) { + ValueNotifier connectionState, + ValueNotifier channelState, + ValueNotifier connectionId, + ValueNotifier recoveryKey, + ) { dispose(); - final connectionSubscription = - realtime.connection.on().listen((connectionStateChange) { + final connectionSubscription = realtime.connection.on().listen(( + connectionStateChange, + ) { if (connectionStateChange.current == ably.ConnectionState.failed) { logAndDisplayError(connectionStateChange.reason); } connectionState.value = connectionStateChange.current; connectionId.value = realtime.connection.id; - realtime.connection - .createRecoveryKey() - .then((value) => {recoveryKey.value = value}); - print('${DateTime.now()}:' - ' ConnectionStateChange event: ${connectionStateChange.event}' - '\nReason: ${connectionStateChange.reason}'); + realtime.connection.createRecoveryKey().then( + (value) => {recoveryKey.value = value}, + ); + print( + '${DateTime.now()}:' + ' ConnectionStateChange event: ${connectionStateChange.event}' + '\nReason: ${connectionStateChange.reason}', + ); }); _subscriptions.add(connectionSubscription); final channelSubscription = channel.on().listen((stateChange) { @@ -329,8 +342,8 @@ List _messagesToPublish = [ 'I am': null, 'and': { 'also': 'nested', - 'too': {'deep': true} - } + 'too': {'deep': true}, + }, }, [ 42, @@ -341,8 +354,8 @@ List _messagesToPublish = [ 'I am': null, 'and': { 'also': 'nested', - 'too': {'deep': true} - } - } - ] + 'too': {'deep': true}, + }, + }, + ], ]; diff --git a/example/lib/ui/rest_sliver.dart b/example/lib/ui/rest_sliver.dart index 3776057a9..95ad91039 100644 --- a/example/lib/ui/rest_sliver.dart +++ b/example/lib/ui/rest_sliver.dart @@ -16,51 +16,52 @@ class RestSliver extends HookWidget { } Widget buildPublishButton( - ValueNotifier messageCount, String messageName) => - TextButton( - onPressed: () async { - try { - await channel.publish( - name: messageName, data: 'Some data for $messageName'); - messageCount.value += 1; - } on ably.AblyException catch (e) { - print('Rest message sending failed:: $e :: ${e.errorInfo}'); - } - }, - child: const Text('Publish'), - ); + ValueNotifier messageCount, + String messageName, + ) => TextButton( + onPressed: () async { + try { + await channel.publish( + name: messageName, + data: 'Some data for $messageName', + ); + messageCount.value += 1; + } on ably.AblyException catch (e) { + print('Rest message sending failed:: $e :: ${e.errorInfo}'); + } + }, + child: const Text('Publish'), + ); Widget buildReleaseChannelButton() => TextButton( - onPressed: () => rest.channels.release(Constants.channelName), - child: const Text('Release channel'), - ); + onPressed: () => rest.channels.release(Constants.channelName), + child: const Text('Release channel'), + ); Widget buildEncryptionSwitch(ValueNotifier isEnabled) => Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Enable encryption', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - Switch( - onChanged: (switchedOn) async { - isEnabled.value = switchedOn; - if (switchedOn) { - await channel.setOptions( - await ably.RestChannelOptions.withCipherKey( - keyFromPassword( - Constants.examplePasswordForEncryptedChannel, - ), - ), - ); - } else { - await channel.setOptions(ably.RestChannelOptions()); - } - }, - value: isEnabled.value, - ), - ], - ); + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Enable encryption', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + Switch( + onChanged: (switchedOn) async { + isEnabled.value = switchedOn; + if (switchedOn) { + await channel.setOptions( + await ably.RestChannelOptions.withCipherKey( + keyFromPassword(Constants.examplePasswordForEncryptedChannel), + ), + ); + } else { + await channel.setOptions(ably.RestChannelOptions()); + } + }, + value: isEnabled.value, + ), + ], + ); @override Widget build(BuildContext context) { @@ -87,42 +88,46 @@ class RestSliver extends HookWidget { Row( children: [ Expanded( - child: buildPublishButton(messageCount, messageName.value)), + child: buildPublishButton(messageCount, messageName.value), + ), Expanded(child: buildReleaseChannelButton()), ], ), TextRow('Next message', messageName.value), PaginatedResultViewer( - title: 'History', - query: () => channel.history(ably.RestHistoryParams( - direction: 'forwards', - limit: 10, - )), - builder: (context, message, _) => Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TextRow('Name', message.name), - TextRow('Data', message.data.toString()), - ], - )), + title: 'History', + query: () => channel.history( + ably.RestHistoryParams(direction: 'forwards', limit: 10), + ), + builder: (context, message, _) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextRow('Name', message.name), + TextRow('Data', message.data.toString()), + ], + ), + ), PaginatedResultViewer( - title: 'Presence members', - query: () => - channel.presence.get(ably.RestPresenceParams(limit: 10)), - builder: (context, message, _) => Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TextRow('Message ID', '${message.id}'), - TextRow('Message client ID', '${message.clientId}'), - TextRow('Message data', '${message.data}'), - ], - )), + title: 'Presence members', + query: () => channel.presence.get(ably.RestPresenceParams(limit: 10)), + builder: (context, message, _) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextRow('Message ID', '${message.id}'), + TextRow('Message client ID', '${message.clientId}'), + TextRow('Message data', '${message.data}'), + ], + ), + ), PaginatedResultViewer( - title: 'Presence history', - query: () => - channel.presence.history(ably.RestHistoryParams(limit: 10)), - builder: (context, message, _) => TextRow('Message name', - '${message.id}:${message.clientId}:${message.data}')), + title: 'Presence history', + query: () => + channel.presence.history(ably.RestHistoryParams(limit: 10)), + builder: (context, message, _) => TextRow( + 'Message name', + '${message.id}:${message.clientId}:${message.data}', + ), + ), ], ); } diff --git a/example/lib/ui/system_details_sliver.dart b/example/lib/ui/system_details_sliver.dart index eabe0ad88..99dab4ab5 100644 --- a/example/lib/ui/system_details_sliver.dart +++ b/example/lib/ui/system_details_sliver.dart @@ -9,10 +9,8 @@ import 'package:flutter_hooks/flutter_hooks.dart'; class SystemDetailsSliver extends HookWidget { ApiKeyProvision apiKeyProvision; - SystemDetailsSliver({ - required this.apiKeyProvision, - Key? key, - }) : super(key: key); + SystemDetailsSliver({required this.apiKeyProvision, Key? key}) + : super(key: key); @override Widget build(BuildContext context) { @@ -39,19 +37,24 @@ class SystemDetailsSliver extends HookWidget { if (apiKeyProvision.source != ApiKeySource.env) RichText( text: const TextSpan( - style: TextStyle(color: Colors.black), - children: [ - TextSpan( - text: 'Warning: ', - style: TextStyle( - color: Colors.red, fontWeight: FontWeight.bold)), - TextSpan( - text: 'Ably API key is not configured! Application uses ' - 'auto-provisioned sandbox key. Please follow ' - 'instructions in the repository Readme file to ' - 'setup the sample with your API key.', - ) - ]), + style: TextStyle(color: Colors.black), + children: [ + TextSpan( + text: 'Warning: ', + style: TextStyle( + color: Colors.red, + fontWeight: FontWeight.bold, + ), + ), + TextSpan( + text: + 'Ably API key is not configured! Application uses ' + 'auto-provisioned sandbox key. Please follow ' + 'instructions in the repository Readme file to ' + 'setup the sample with your API key.', + ), + ], + ), ), ], ); diff --git a/example/lib/ui/text_row.dart b/example/lib/ui/text_row.dart index b70e7bf42..88da9fe45 100644 --- a/example/lib/ui/text_row.dart +++ b/example/lib/ui/text_row.dart @@ -10,8 +10,17 @@ class TextRow extends StatelessWidget { @override Widget build(BuildContext context) => RichText( - text: TextSpan(children: [ - TextSpan(text: '$label: ', style: const TextStyle(color: Colors.blue)), - TextSpan(text: text, style: const TextStyle(color: Colors.black)) - ])); + text: TextSpan( + children: [ + TextSpan( + text: '$label: ', + style: const TextStyle(color: Colors.blue), + ), + TextSpan( + text: text, + style: const TextStyle(color: Colors.black), + ), + ], + ), + ); } diff --git a/example/lib/ui/utilities.dart b/example/lib/ui/utilities.dart index c3926cfe6..76abc0c47 100644 --- a/example/lib/ui/utilities.dart +++ b/example/lib/ui/utilities.dart @@ -6,20 +6,24 @@ import 'package:crypto/crypto.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; -void logAndDisplayError(ably.ErrorInfo? errorInfo, - {String prefixMessage = ' '}) { +void logAndDisplayError( + ably.ErrorInfo? errorInfo, { + String prefixMessage = ' ', +}) { if (errorInfo == null) { return; } print(errorInfo.message); Fluttertoast.showToast( - msg: 'Error: $prefixMessage. ' - '${errorInfo.message ?? 'No error message provided'}', - toastLength: Toast.LENGTH_LONG, - gravity: ToastGravity.CENTER, - backgroundColor: Colors.red, - textColor: Colors.white, - fontSize: 16); + msg: + 'Error: $prefixMessage. ' + '${errorInfo.message ?? 'No error message provided'}', + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.CENTER, + backgroundColor: Colors.red, + textColor: Colors.white, + fontSize: 16, + ); } // This is a quick way to create a key from a password. In production, diff --git a/lib/src/authentication/src/auth_options.dart b/lib/src/authentication/src/auth_options.dart index feb3bce91..ee59776ec 100644 --- a/lib/src/authentication/src/auth_options.dart +++ b/lib/src/authentication/src/auth_options.dart @@ -82,8 +82,8 @@ class AuthOptions { /// then the Ably Token issued is [anonymous](https://ably.com/docs/core-features/authentication#identified-clients). bool? useTokenAuth; -// TODO(tiholic) missing token attribute here -// see: https://docs.ably.com/client-lib-development-guide/features/#AO2h + // TODO(tiholic) missing token attribute here + // see: https://docs.ably.com/client-lib-development-guide/features/#AO2h /// @nodoc /// Initializes an instance without any defaults diff --git a/lib/src/authentication/src/client_options.dart b/lib/src/authentication/src/client_options.dart index a0bcf46cc..b0db956ac 100644 --- a/lib/src/authentication/src/client_options.dart +++ b/lib/src/authentication/src/client_options.dart @@ -199,16 +199,16 @@ class ClientOptions extends AuthOptions { bool? useBinaryProtocol, bool? useTokenAuth, }) : super( - authCallback: authCallback, - authUrl: authUrl, - authMethod: authMethod, - key: key, - tokenDetails: tokenDetails, - authHeaders: authHeaders, - authParams: authParams, - queryTime: queryTime, - useTokenAuth: useTokenAuth, - ) { + authCallback: authCallback, + authUrl: authUrl, + authMethod: authMethod, + key: key, + tokenDetails: tokenDetails, + authHeaders: authHeaders, + authParams: authParams, + queryTime: queryTime, + useTokenAuth: useTokenAuth, + ) { /// @nodoc /// These default value assignments are only required until /// [ClientOptions.fromKey] is removed, because then defaults can be set @@ -236,16 +236,17 @@ class ClientOptions extends AuthOptions { /// /// See [AuthOptions.fromKey] for more details @Deprecated( - "Use ClientOptions constructor with named 'key' parameter instead") + "Use ClientOptions constructor with named 'key' parameter instead", + ) ClientOptions.fromKey(String key) : super.fromKey(key); -// TODO(tiholic) unimplemented: -// -// (TO3m) logExceptionReportingUrl -// (TO3l6) httpMaxRetryDuration -// (TO3l8) maxMessageSize -// (TO3l9) maxFrameSize -// (TO3o) plugins -// (TO3p) addRequestIds -// (DF1a) connectionStateTtl + // TODO(tiholic) unimplemented: + // + // (TO3m) logExceptionReportingUrl + // (TO3l6) httpMaxRetryDuration + // (TO3l8) maxMessageSize + // (TO3l9) maxFrameSize + // (TO3o) plugins + // (TO3p) addRequestIds + // (DF1a) connectionStateTtl } diff --git a/lib/src/authentication/src/token_details.dart b/lib/src/authentication/src/token_details.dart index b5f2c4f5b..e73bdc59c 100644 --- a/lib/src/authentication/src/token_details.dart +++ b/lib/src/authentication/src/token_details.dart @@ -56,9 +56,9 @@ class TokenDetails { /// Ably ensures that all fields are consistently serialized and deserialized /// across platforms. TokenDetails.fromMap(Map map) - : capability = map['capability'] as String?, - clientId = map['clientId'] as String?, - expires = map['expires'] as int?, - issued = map['issued'] as int?, - token = map['token'] as String?; + : capability = map['capability'] as String?, + clientId = map['clientId'] as String?, + expires = map['expires'] as int?, + issued = map['issued'] as int?, + token = map['token'] as String?; } diff --git a/lib/src/authentication/src/token_request.dart b/lib/src/authentication/src/token_request.dart index fdb1cae65..c2ac8d84f 100644 --- a/lib/src/authentication/src/token_request.dart +++ b/lib/src/authentication/src/token_request.dart @@ -67,12 +67,11 @@ class TokenRequest { /// Ably ensures that all fields are consistently serialized and deserialized /// across platforms. TokenRequest.fromMap(Map map) - : capability = map['capability'] as String?, - clientId = map['clientId'] as String?, - mac = map['mac'] as String?, - nonce = map['nonce'] as String?, - timestamp = - DateTime.fromMillisecondsSinceEpoch(map['timestamp'] as int), - ttl = map['ttl'] as int?, - keyName = map['keyName'] as String?; + : capability = map['capability'] as String?, + clientId = map['clientId'] as String?, + mac = map['mac'] as String?, + nonce = map['nonce'] as String?, + timestamp = DateTime.fromMillisecondsSinceEpoch(map['timestamp'] as int), + ttl = map['ttl'] as int?, + keyName = map['keyName'] as String?; } diff --git a/lib/src/crypto/src/crypto.dart b/lib/src/crypto/src/crypto.dart index e0b619b80..11fb59908 100644 --- a/lib/src/crypto/src/crypto.dart +++ b/lib/src/crypto/src/crypto.dart @@ -34,17 +34,17 @@ class Crypto { } else if (key is Uint8List) { ensureSupportedKeyLength(key); } else { - throw AblyException( - message: 'key must be a String or Uint8List.', - ); + throw AblyException(message: 'key must be a String or Uint8List.'); } return Platform().invokePlatformMethodNonNull( PlatformMethod.cryptoGetParams, - AblyMessage(message: { - TxCryptoGetParams.algorithm: defaultAlgorithm, - TxCryptoGetParams.key: key, - }), + AblyMessage( + message: { + TxCryptoGetParams.algorithm: defaultAlgorithm, + TxCryptoGetParams.key: key, + }, + ), ); } @@ -54,9 +54,7 @@ class Crypto { static void ensureSupportedKeyLength(Uint8List key) { if (key.length != keyLength256bits / 8 && key.length != keyLength128bits / 8) { - throw AblyException( - message: 'Key must be 256 bits or 128 bits long.', - ); + throw AblyException(message: 'Key must be 256 bits or 128 bits long.'); } } @@ -68,11 +66,8 @@ class Crypto { /// default algorithm: for AES this is 256 bits. static Future generateRandomKey({ int keyLength = defaultKeyLengthInBits, - }) => - Platform().invokePlatformMethodNonNull( - PlatformMethod.cryptoGenerateRandomKey, - AblyMessage(message: { - TxCryptoGenerateRandomKey.keyLength: keyLength, - }), - ); + }) => Platform().invokePlatformMethodNonNull( + PlatformMethod.cryptoGenerateRandomKey, + AblyMessage(message: {TxCryptoGenerateRandomKey.keyLength: keyLength}), + ); } diff --git a/lib/src/error/src/ably_exception.dart b/lib/src/error/src/ably_exception.dart index 99cb21a45..a90cd1241 100644 --- a/lib/src/error/src/ably_exception.dart +++ b/lib/src/error/src/ably_exception.dart @@ -17,17 +17,13 @@ class AblyException implements Exception { final ErrorInfo? errorInfo; /// initializes with no defaults - AblyException({ - this.code, - this.errorInfo, - this.message, - }); + AblyException({this.code, this.errorInfo, this.message}); /// create AblyException from [PlatformException] AblyException.fromPlatformException(PlatformException exception) - : code = exception.code, - errorInfo = exception.details as ErrorInfo?, - message = exception.message; + : code = exception.code, + errorInfo = exception.details as ErrorInfo?, + message = exception.message; @override String toString() { diff --git a/lib/src/error/src/error_info.dart b/lib/src/error/src/error_info.dart index c5686b90c..190ba5897 100644 --- a/lib/src/error/src/error_info.dart +++ b/lib/src/error/src/error_info.dart @@ -36,7 +36,8 @@ class ErrorInfo { }); @override - String toString() => 'ErrorInfo' + String toString() => + 'ErrorInfo' ' message=$message' ' code=$code' ' statusCode=$statusCode' diff --git a/lib/src/logging/src/log_handler.dart b/lib/src/logging/src/log_handler.dart index 2b4d003e9..6f5602235 100644 --- a/lib/src/logging/src/log_handler.dart +++ b/lib/src/logging/src/log_handler.dart @@ -10,7 +10,4 @@ import 'package:ably_flutter/ably_flutter.dart'; 'All usages of this type are marked as deprecated ' 'so it will be removed in a future release.', ) -typedef LogHandler = void Function({ - String? msg, - AblyException? exception, -}); +typedef LogHandler = void Function({String? msg, AblyException? exception}); diff --git a/lib/src/message/src/delta_extras.dart b/lib/src/message/src/delta_extras.dart index 12ddeceb3..2d44dc839 100644 --- a/lib/src/message/src/delta_extras.dart +++ b/lib/src/message/src/delta_extras.dart @@ -17,16 +17,13 @@ class DeltaExtras with ObjectHash { /// create instance from a map @protected DeltaExtras.fromMap(Map value) - : format = value[TxDeltaExtras.format] as String?, - from = value[TxDeltaExtras.from] as String?; + : format = value[TxDeltaExtras.format] as String?, + from = value[TxDeltaExtras.from] as String?; @override bool operator ==(Object other) => other is DeltaExtras && other.from == from && other.format == format; @override - int get hashCode => objectHash([ - from, - format, - ]); + int get hashCode => objectHash([from, format]); } diff --git a/lib/src/message/src/message.dart b/lib/src/message/src/message.dart index d63cae59a..8beded649 100644 --- a/lib/src/message/src/message.dart +++ b/lib/src/message/src/message.dart @@ -61,15 +61,15 @@ class Message with ObjectHash { @override int get hashCode => objectHash([ - id, - name, - encoding, - clientId, - timestamp, - connectionId, - data, - extras, - ]); + id, + name, + encoding, + clientId, + timestamp, + connectionId, + data, + extras, + ]); // https://docs.ably.com/client-lib-development-guide/features/#TM3 // @@ -84,22 +84,20 @@ class Message with ObjectHash { Message.fromEncoded( Map jsonObject, [ RestChannelOptions? channelOptions, - ]) : clientId = jsonObject['clientId'] as String?, - connectionId = jsonObject['connectionId'] as String?, - _data = MessageData.fromValue(jsonObject['data']), - encoding = jsonObject['encoding'] as String?, - extras = MessageExtras.fromMap( - Map.castFrom( - jsonObject['extras'] as Map, - ), - ), - id = jsonObject['id'] as String?, - name = jsonObject['name'] as String?, - timestamp = jsonObject['timestamp'] != null - ? DateTime.fromMillisecondsSinceEpoch( - jsonObject['timestamp'] as int, - ) - : null; + ]) : clientId = jsonObject['clientId'] as String?, + connectionId = jsonObject['connectionId'] as String?, + _data = MessageData.fromValue(jsonObject['data']), + encoding = jsonObject['encoding'] as String?, + extras = MessageExtras.fromMap( + Map.castFrom( + jsonObject['extras'] as Map, + ), + ), + id = jsonObject['id'] as String?, + name = jsonObject['name'] as String?, + timestamp = jsonObject['timestamp'] != null + ? DateTime.fromMillisecondsSinceEpoch(jsonObject['timestamp'] as int) + : null; /// A static factory method to create an array of Message objects from an /// [jsonArray] of deserialized Message-like object encoded using Ably's wire @@ -108,11 +106,11 @@ class Message with ObjectHash { static List fromEncodedArray( List> jsonArray, [ RestChannelOptions? channelOptions, - ]) => - jsonArray.map((e) => Message.fromEncoded(e, channelOptions)).toList(); + ]) => jsonArray.map((e) => Message.fromEncoded(e, channelOptions)).toList(); @override - String toString() => 'Message' + String toString() => + 'Message' ' id=$id' ' name=$name' ' data=$data' @@ -122,5 +120,5 @@ class Message with ObjectHash { ' timestamp=$timestamp' ' connectionId=$connectionId'; -// TODO(tiholic) add support for fromEncoded and fromEncodedArray (TM3) + // TODO(tiholic) add support for fromEncoded and fromEncodedArray (TM3) } diff --git a/lib/src/message/src/message_data.dart b/lib/src/message/src/message_data.dart index 327e81ce3..e6ffdfadc 100644 --- a/lib/src/message/src/message_data.dart +++ b/lib/src/message/src/message_data.dart @@ -8,7 +8,7 @@ class MessageData { /// /// Only Map, List, string and Buffer types are supported. MessageData(this._data) - : assert(T == Map || T == List || T == String || T == Uint8List); + : assert(T == Map || T == List || T == String || T == Uint8List); /// A getter for the [_data] object. T get data => _data; diff --git a/lib/src/message/src/message_extras.dart b/lib/src/message/src/message_extras.dart index 59c139047..d04237778 100644 --- a/lib/src/message/src/message_extras.dart +++ b/lib/src/message/src/message_extras.dart @@ -37,10 +37,7 @@ class MessageExtras with ObjectHash { ? null : DeltaExtras.fromMap(Map.from(deltaMap)); - return MessageExtras._withDelta( - mutableExtrasMap, - deltaExtras, - ); + return MessageExtras._withDelta(mutableExtrasMap, deltaExtras); } @override @@ -53,8 +50,5 @@ class MessageExtras with ObjectHash { other.delta == delta; @override - int get hashCode => objectHash([ - map, - delta, - ]); + int get hashCode => objectHash([map, delta]); } diff --git a/lib/src/message/src/presence_message.dart b/lib/src/message/src/presence_message.dart index e7b25c526..31a4a1a10 100644 --- a/lib/src/message/src/presence_message.dart +++ b/lib/src/message/src/presence_message.dart @@ -68,15 +68,15 @@ class PresenceMessage with ObjectHash { @override int get hashCode => objectHash([ - id, - encoding, - clientId, - timestamp, - connectionId, - data, - action, - extras, - ]); + id, + encoding, + clientId, + timestamp, + connectionId, + data, + action, + extras, + ]); // https://docs.ably.com/client-lib-development-guide/features/#TP4 // @@ -93,23 +93,22 @@ class PresenceMessage with ObjectHash { PresenceMessage.fromEncoded( Map jsonObject, [ RestChannelOptions? channelOptions, - ]) : id = jsonObject['id'] as String?, - action = PresenceAction.values.firstWhere((e) => - e.toString().split('.')[1] == jsonObject['action'] as String?), - clientId = jsonObject['clientId'] as String?, - connectionId = jsonObject['connectionId'] as String?, - _data = MessageData.fromValue(jsonObject['data']), - encoding = jsonObject['encoding'] as String?, - extras = MessageExtras.fromMap( - Map.castFrom( - jsonObject['extras'] as Map, - ), - ), - timestamp = jsonObject['timestamp'] != null - ? DateTime.fromMillisecondsSinceEpoch( - jsonObject['timestamp'] as int, - ) - : null; + ]) : id = jsonObject['id'] as String?, + action = PresenceAction.values.firstWhere( + (e) => e.toString().split('.')[1] == jsonObject['action'] as String?, + ), + clientId = jsonObject['clientId'] as String?, + connectionId = jsonObject['connectionId'] as String?, + _data = MessageData.fromValue(jsonObject['data']), + encoding = jsonObject['encoding'] as String?, + extras = MessageExtras.fromMap( + Map.castFrom( + jsonObject['extras'] as Map, + ), + ), + timestamp = jsonObject['timestamp'] != null + ? DateTime.fromMillisecondsSinceEpoch(jsonObject['timestamp'] as int) + : null; /// Decodes and decrypts a [jsonArray] of deserialized PresenceMessage-like /// object using the cipher in [channelOptions]. @@ -121,16 +120,15 @@ class PresenceMessage with ObjectHash { static List fromEncodedArray( List> jsonArray, [ RestChannelOptions? channelOptions, - ]) => - jsonArray - .map((jsonObject) => PresenceMessage.fromEncoded( - jsonObject, - channelOptions, - )) - .toList(); + ]) => jsonArray + .map( + (jsonObject) => PresenceMessage.fromEncoded(jsonObject, channelOptions), + ) + .toList(); @override - String toString() => 'PresenceMessage' + String toString() => + 'PresenceMessage' ' id=$id' ' data=$data' ' action=$action' diff --git a/lib/src/platform/src/ably_event_message.dart b/lib/src/platform/src/ably_event_message.dart index 607233642..4086c76fb 100644 --- a/lib/src/platform/src/ably_event_message.dart +++ b/lib/src/platform/src/ably_event_message.dart @@ -16,8 +16,5 @@ class AblyEventMessage { /// creates an instance with non-nul [eventName] /// /// [message] is optional - const AblyEventMessage({ - required this.eventName, - this.message, - }); + const AblyEventMessage({required this.eventName, this.message}); } diff --git a/lib/src/platform/src/ably_message.dart b/lib/src/platform/src/ably_message.dart index 6588d80ba..4cc7531e2 100644 --- a/lib/src/platform/src/ably_message.dart +++ b/lib/src/platform/src/ably_message.dart @@ -21,31 +21,20 @@ class AblyMessage { /// creates instance with a non-null [message] /// /// [handle] and [type] are optional - const AblyMessage({ - required this.message, - this.handle, - this.type, - }); + const AblyMessage({required this.message, this.handle, this.type}); /// @nodoc /// creates instance with [message] set to empty map /// /// [handle] and [type] are optional - static AblyMessage> empty({ - int? handle, - int? type, - }) => - AblyMessage( - message: const {}, - handle: handle, - type: type, - ); + static AblyMessage> empty({int? handle, int? type}) => + AblyMessage(message: const {}, handle: handle, type: type); /// @nodoc /// Cast ably message from [G] to [T] static AblyMessage castFrom(AblyMessage source) => AblyMessage( - message: source.message as T, - handle: source.handle, - type: source.type, - ); + message: source.message as T, + handle: source.handle, + type: source.type, + ); } diff --git a/lib/src/platform/src/background_android_isolate_platform.dart b/lib/src/platform/src/background_android_isolate_platform.dart index cf743b3b5..f8cf6cc58 100644 --- a/lib/src/platform/src/background_android_isolate_platform.dart +++ b/lib/src/platform/src/background_android_isolate_platform.dart @@ -23,7 +23,9 @@ class BackgroundIsolateAndroidPlatform { return _onPushBackgroundMessage(call.arguments as RemoteMessage); default: throw PlatformException( - code: 'invalid_method', message: 'No such method ${call.method}'); + code: 'invalid_method', + message: 'No such method ${call.method}', + ); } }); } @@ -40,7 +42,9 @@ class BackgroundIsolateAndroidPlatform { /// we explicitly launched when a RemoteMessage is received. /// Used only on Android. final MethodChannel _methodChannel = MethodChannel( - 'io.ably.flutter.plugin.background', StandardMethodCodec(Codec())); + 'io.ably.flutter.plugin.background', + StandardMethodCodec(Codec()), + ); final PushNotificationEventsInternal _pushNotificationEvents = Push.notificationEvents as PushNotificationEventsInternal; diff --git a/lib/src/platform/src/cipher_params_internal.dart b/lib/src/platform/src/cipher_params_internal.dart index 6543a864e..cb2695a98 100644 --- a/lib/src/platform/src/cipher_params_internal.dart +++ b/lib/src/platform/src/cipher_params_internal.dart @@ -33,18 +33,14 @@ class CipherParamsInternal implements CipherParams { /// @nodoc /// Create a Dart side representation of CipherParams for iOS devices - CipherParamsInternal.forIOS({ - required this.algorithm, - required this.key, - }) { + CipherParamsInternal.forIOS({required this.algorithm, required this.key}) { if (!io.Platform.isIOS) { - throw AblyException( - message: 'This method is for iOS platforms only', - ); + throw AblyException(message: 'This method is for iOS platforms only'); } if (key == null) { throw AblyException( - message: 'CipherParamsNative on iOS must have a key, as ' + message: + 'CipherParamsNative on iOS must have a key, as ' 'this key is used to regenerate the ARTCipherParams on the ' 'iOS side.', ); @@ -53,15 +49,14 @@ class CipherParamsInternal implements CipherParams { /// @nodoc /// Create a Dart side representation of CipherParams for Android devices - CipherParamsInternal.forAndroid({ - required this.androidHandle, - }) { + CipherParamsInternal.forAndroid({required this.androidHandle}) { if (!io.Platform.isAndroid) { throw AblyException(message: 'This method is for Android platforms only'); } if (androidHandle == null) { throw AblyException( - message: 'CipherParamsNative on Android must have a handle, ' + message: + 'CipherParamsNative on Android must have a handle, ' 'as this key is used to get the previously generated ' 'CipherParams on the Android side', ); diff --git a/lib/src/platform/src/codec.dart b/lib/src/platform/src/codec.dart index 6ebe9ecb6..09518e63c 100644 --- a/lib/src/platform/src/codec.dart +++ b/lib/src/platform/src/codec.dart @@ -27,9 +27,7 @@ class _CodecPair { /// This method will throw an [AblyException] if encoder is null. Map? encode(final Object? value) { if (_encoder == null) { - throw AblyException( - message: 'Codec encoder is null', - ); + throw AblyException(message: 'Codec encoder is null'); } if (value == null) return null; return _encoder(value as T); @@ -41,9 +39,7 @@ class _CodecPair { /// This method will throw an [AblyException] if decoder is null. T? decode(Map? jsonMap) { if (_decoder == null) { - throw AblyException( - message: 'Codec decoder is null', - ); + throw AblyException(message: 'Codec decoder is null'); } if (jsonMap == null) return null; return _decoder(jsonMap); @@ -66,52 +62,84 @@ class Codec extends StandardMessageCodec { codecMap = { // Ably flutter plugin protocol message CodecTypes.ablyMessage: _CodecPair>( - _encodeAblyMessage, _decodeAblyMessage), - CodecTypes.ablyEventMessage: - _CodecPair(_encodeAblyEventMessage, null), + _encodeAblyMessage, + _decodeAblyMessage, + ), + CodecTypes.ablyEventMessage: _CodecPair( + _encodeAblyEventMessage, + null, + ), // Other ably objects - CodecTypes.clientOptions: - _CodecPair(_encodeClientOptions, _decodeClientOptions), - CodecTypes.tokenParams: - _CodecPair(_encodeTokenParams, _decodeTokenParams), - CodecTypes.tokenDetails: - _CodecPair(_encodeTokenDetails, _decodeTokenDetails), - CodecTypes.tokenRequest: - _CodecPair(_encodeTokenRequest, _decodeTokenRequest), - CodecTypes.restChannelOptions: - _CodecPair(_encodeRestChannelOptions, null), + CodecTypes.clientOptions: _CodecPair( + _encodeClientOptions, + _decodeClientOptions, + ), + CodecTypes.tokenParams: _CodecPair( + _encodeTokenParams, + _decodeTokenParams, + ), + CodecTypes.tokenDetails: _CodecPair( + _encodeTokenDetails, + _decodeTokenDetails, + ), + CodecTypes.tokenRequest: _CodecPair( + _encodeTokenRequest, + _decodeTokenRequest, + ), + CodecTypes.restChannelOptions: _CodecPair( + _encodeRestChannelOptions, + null, + ), CodecTypes.realtimeChannelOptions: _CodecPair( _encodeRealtimeChannelOptions, null, ), CodecTypes.authOptions: _CodecPair(_encodeAuthOptions, null), - CodecTypes.paginatedResult: - _CodecPair>(null, _decodePaginatedResult), - CodecTypes.realtimeHistoryParams: - _CodecPair(_encodeRealtimeHistoryParams, null), - CodecTypes.restHistoryParams: - _CodecPair(_encodeRestHistoryParams, null), - CodecTypes.restPresenceParams: - _CodecPair(_encodeRestPresenceParams, null), + CodecTypes.paginatedResult: _CodecPair>( + null, + _decodePaginatedResult, + ), + CodecTypes.realtimeHistoryParams: _CodecPair( + _encodeRealtimeHistoryParams, + null, + ), + CodecTypes.restHistoryParams: _CodecPair( + _encodeRestHistoryParams, + null, + ), + CodecTypes.restPresenceParams: _CodecPair( + _encodeRestPresenceParams, + null, + ), CodecTypes.realtimePresenceParams: _CodecPair( _encodeRealtimePresenceParams, null, ), // Push Notifications - CodecTypes.deviceDetails: - _CodecPair(null, _decodeDeviceDetails), + CodecTypes.deviceDetails: _CodecPair( + null, + _decodeDeviceDetails, + ), CodecTypes.localDevice: _CodecPair(null, _decodeLocalDevice), CodecTypes.pushChannelSubscription: _CodecPair( - null, _decodePushChannelSubscription), + null, + _decodePushChannelSubscription, + ), CodecTypes.unNotificationSettings: _CodecPair( - null, _decodeUNNotificationSettings), - CodecTypes.remoteMessage: - _CodecPair(null, _decodeRemoteMessage), + null, + _decodeUNNotificationSettings, + ), + CodecTypes.remoteMessage: _CodecPair( + null, + _decodeRemoteMessage, + ), - CodecTypes.errorInfo: - _CodecPair(_encodeErrorInfo, _decodeErrorInfo), + CodecTypes.errorInfo: _CodecPair( + _encodeErrorInfo, + _decodeErrorInfo, + ), CodecTypes.messageData: _CodecPair?>( _encodeChannelMessageData, _decodeChannelMessageData, @@ -120,23 +148,33 @@ class Codec extends StandardMessageCodec { _encodeChannelMessageExtras, _decodeChannelMessageExtras, ), - CodecTypes.message: - _CodecPair(_encodeChannelMessage, _decodeChannelMessage), - CodecTypes.presenceMessage: - _CodecPair(null, _decodePresenceMessage), + CodecTypes.message: _CodecPair( + _encodeChannelMessage, + _decodeChannelMessage, + ), + CodecTypes.presenceMessage: _CodecPair( + null, + _decodePresenceMessage, + ), // Events - Connection CodecTypes.connectionStateChange: _CodecPair( - null, _decodeConnectionStateChange), + null, + _decodeConnectionStateChange, + ), // Events - Channel - CodecTypes.channelStateChange: - _CodecPair(null, _decodeChannelStateChange), + CodecTypes.channelStateChange: _CodecPair( + null, + _decodeChannelStateChange, + ), // Encryption - CodecTypes.cipherParams: - _CodecPair(_encodeCipherParams, _decodeCipherParams), + CodecTypes.cipherParams: _CodecPair( + _encodeCipherParams, + _decodeCipherParams, + ), }; } @@ -248,8 +286,11 @@ class Codec extends StandardMessageCodec { _writeToJson(jsonMap, TxClientOptions.authUrl, v.authUrl); _writeToJson(jsonMap, TxClientOptions.authMethod, v.authMethod); _writeToJson(jsonMap, TxClientOptions.key, v.key); - _writeToJson(jsonMap, TxClientOptions.tokenDetails, - _encodeTokenDetails(v.tokenDetails)); + _writeToJson( + jsonMap, + TxClientOptions.tokenDetails, + _encodeTokenDetails(v.tokenDetails), + ); _writeToJson(jsonMap, TxClientOptions.authHeaders, v.authHeaders); _writeToJson(jsonMap, TxClientOptions.authParams, v.authParams); _writeToJson(jsonMap, TxClientOptions.queryTime, v.queryTime); @@ -259,7 +300,10 @@ class Codec extends StandardMessageCodec { // ClientOptions _writeToJson(jsonMap, TxClientOptions.clientId, v.clientId); _writeToJson( - jsonMap, TxClientOptions.logLevel, _encodeLogLevel(v.logLevel)); + jsonMap, + TxClientOptions.logLevel, + _encodeLogLevel(v.logLevel), + ); //TODO handle logHandler _writeToJson(jsonMap, TxClientOptions.tls, v.tls); _writeToJson(jsonMap, TxClientOptions.restHost, v.restHost); @@ -268,32 +312,57 @@ class Codec extends StandardMessageCodec { _writeToJson(jsonMap, TxClientOptions.tlsPort, v.tlsPort); _writeToJson(jsonMap, TxClientOptions.autoConnect, v.autoConnect); _writeToJson( - jsonMap, TxClientOptions.useBinaryProtocol, v.useBinaryProtocol); + jsonMap, + TxClientOptions.useBinaryProtocol, + v.useBinaryProtocol, + ); _writeToJson(jsonMap, TxClientOptions.queueMessages, v.queueMessages); _writeToJson(jsonMap, TxClientOptions.echoMessages, v.echoMessages); _writeToJson(jsonMap, TxClientOptions.recover, v.recover); _writeToJson(jsonMap, TxClientOptions.environment, v.environment); - _writeToJson(jsonMap, TxClientOptions.idempotentRestPublishing, - v.idempotentRestPublishing); + _writeToJson( + jsonMap, + TxClientOptions.idempotentRestPublishing, + v.idempotentRestPublishing, + ); _writeToJson(jsonMap, TxClientOptions.httpOpenTimeout, v.httpOpenTimeout); _writeToJson( - jsonMap, TxClientOptions.httpRequestTimeout, v.httpRequestTimeout); + jsonMap, + TxClientOptions.httpRequestTimeout, + v.httpRequestTimeout, + ); + _writeToJson( + jsonMap, + TxClientOptions.httpMaxRetryCount, + v.httpMaxRetryCount, + ); _writeToJson( - jsonMap, TxClientOptions.httpMaxRetryCount, v.httpMaxRetryCount); - _writeToJson(jsonMap, TxClientOptions.realtimeRequestTimeout, - v.realtimeRequestTimeout); + jsonMap, + TxClientOptions.realtimeRequestTimeout, + v.realtimeRequestTimeout, + ); _writeToJson(jsonMap, TxClientOptions.fallbackHosts, v.fallbackHosts); _writeToJson( - jsonMap, - TxClientOptions.fallbackHostsUseDefault, - // ignore: deprecated_member_use_from_same_package - v.fallbackHostsUseDefault); + jsonMap, + TxClientOptions.fallbackHostsUseDefault, + // ignore: deprecated_member_use_from_same_package + v.fallbackHostsUseDefault, + ); _writeToJson( - jsonMap, TxClientOptions.fallbackRetryTimeout, v.fallbackRetryTimeout); - _writeToJson(jsonMap, TxClientOptions.defaultTokenParams, - _encodeTokenParams(v.defaultTokenParams)); + jsonMap, + TxClientOptions.fallbackRetryTimeout, + v.fallbackRetryTimeout, + ); + _writeToJson( + jsonMap, + TxClientOptions.defaultTokenParams, + _encodeTokenParams(v.defaultTokenParams), + ); _writeToJson( - jsonMap, TxClientOptions.channelRetryTimeout, v.channelRetryTimeout); + jsonMap, + TxClientOptions.channelRetryTimeout, + v.channelRetryTimeout, + ); _writeToJson(jsonMap, TxClientOptions.transportParams, v.transportParams); _writeToJson(jsonMap, TxClientOptions.dartVersion, dartVersion()); return jsonMap; @@ -338,7 +407,10 @@ class Codec extends StandardMessageCodec { _writeToJson(jsonMap, TxTokenRequest.mac, v.mac); _writeToJson(jsonMap, TxTokenRequest.nonce, v.nonce); _writeToJson( - jsonMap, TxTokenRequest.timestamp, v.timestamp?.millisecondsSinceEpoch); + jsonMap, + TxTokenRequest.timestamp, + v.timestamp?.millisecondsSinceEpoch, + ); _writeToJson(jsonMap, TxTokenRequest.ttl, v.ttl); return jsonMap; } @@ -348,8 +420,9 @@ class Codec extends StandardMessageCodec { /// returns null if [v] is null Map _encodeRestChannelOptions(final RestChannelOptions v) { final jsonMap = {}; - jsonMap[TxRestChannelOptions.cipherParams] = - _encodeCipherParams(v.cipherParams); + jsonMap[TxRestChannelOptions.cipherParams] = _encodeCipherParams( + v.cipherParams, + ); return jsonMap; } @@ -372,10 +445,12 @@ class Codec extends StandardMessageCodec { /// Encodes [RealtimeChannelOptions] to a Map /// returns null if [v] is null Map _encodeRealtimeChannelOptions( - final RealtimeChannelOptions v) { + final RealtimeChannelOptions v, + ) { final jsonMap = {}; - jsonMap[TxRealtimeChannelOptions.cipherParams] = - _encodeCipherParams(v.cipherParams); + jsonMap[TxRealtimeChannelOptions.cipherParams] = _encodeCipherParams( + v.cipherParams, + ); _writeToJson(jsonMap, TxRealtimeChannelOptions.params, v.params); _writeToJson( jsonMap, @@ -387,8 +462,9 @@ class Codec extends StandardMessageCodec { Map _encodeAuthOptions(final AuthOptions authOptions) { final jsonMap = {}; - jsonMap[TxAuthOptions.tokenDetails] = - _encodeTokenDetails(authOptions.tokenDetails); + jsonMap[TxAuthOptions.tokenDetails] = _encodeTokenDetails( + authOptions.tokenDetails, + ); jsonMap[TxAuthOptions.authUrl] = authOptions.authUrl; jsonMap[TxAuthOptions.authMethod] = authOptions.authMethod; jsonMap[TxAuthOptions.key] = authOptions.key; @@ -418,20 +494,13 @@ class Codec extends StandardMessageCodec { CipherParams _decodeCipherParams(final Map jsonMap) { if (io.Platform.isAndroid) { final cipherParamsHandle = jsonMap[TxCipherParams.androidHandle] as int; - return CipherParamsInternal.forAndroid( - androidHandle: cipherParamsHandle, - ); + return CipherParamsInternal.forAndroid(androidHandle: cipherParamsHandle); } else if (io.Platform.isIOS) { final algorithm = jsonMap[TxCipherParams.iosAlgorithm] as String; final key = jsonMap[TxCipherParams.iosKey] as Uint8List; - return CipherParamsInternal.forIOS( - algorithm: algorithm, - key: key, - ); + return CipherParamsInternal.forIOS(algorithm: algorithm, key: key); } else { - throw AblyException( - message: 'Unsupported platform', - ); + throw AblyException(message: 'Unsupported platform'); } } @@ -441,9 +510,15 @@ class Codec extends StandardMessageCodec { Map _encodeRestHistoryParams(final RestHistoryParams v) { final jsonMap = {}; _writeToJson( - jsonMap, TxRestHistoryParams.start, v.start.millisecondsSinceEpoch); + jsonMap, + TxRestHistoryParams.start, + v.start.millisecondsSinceEpoch, + ); _writeToJson( - jsonMap, TxRestHistoryParams.end, v.end.millisecondsSinceEpoch); + jsonMap, + TxRestHistoryParams.end, + v.end.millisecondsSinceEpoch, + ); _writeToJson(jsonMap, TxRestHistoryParams.direction, v.direction); _writeToJson(jsonMap, TxRestHistoryParams.limit, v.limit); return jsonMap; @@ -461,12 +536,16 @@ class Codec extends StandardMessageCodec { } Map _encodeRealtimePresenceParams( - final RealtimePresenceParams v) { + final RealtimePresenceParams v, + ) { final jsonMap = {}; _writeToJson(jsonMap, TxRealtimePresenceParams.waitForSync, v.waitForSync); _writeToJson(jsonMap, TxRealtimePresenceParams.clientId, v.clientId); _writeToJson( - jsonMap, TxRealtimePresenceParams.connectionId, v.connectionId); + jsonMap, + TxRealtimePresenceParams.connectionId, + v.connectionId, + ); return jsonMap; } @@ -516,8 +595,8 @@ class Codec extends StandardMessageCodec { final message = (v.message == null) ? null : (codecType == null) - ? v.message - : codecMap[codecType]!.encode(v.message); + ? v.message + : codecMap[codecType]!.encode(v.message); final jsonMap = {}; _writeToJson(jsonMap, TxAblyEventMessage.eventName, v.eventName); _writeToJson(jsonMap, TxAblyEventMessage.type, codecType); @@ -592,30 +671,26 @@ class Codec extends StandardMessageCodec { /// Decodes value [jsonMap] to [ClientOptions] /// returns null if [jsonMap] is null ClientOptions _decodeClientOptions(Map jsonMap) { - final tokenDetails = toJsonMap(_readFromJson>( - jsonMap, - TxClientOptions.tokenDetails, - )); - final tokenParams = toJsonMap(_readFromJson>( - jsonMap, - TxClientOptions.defaultTokenParams, - )); - final clientOptions = ClientOptions( - // AuthOptions (super class of ClientOptions) - authUrl: _readFromJson( + final tokenDetails = toJsonMap( + _readFromJson>( jsonMap, - TxClientOptions.authUrl, + TxClientOptions.tokenDetails, ), - authMethod: _readFromJson( - jsonMap, - TxClientOptions.authMethod, - ), - key: _readFromJson( + ); + final tokenParams = toJsonMap( + _readFromJson>( jsonMap, - TxClientOptions.key, + TxClientOptions.defaultTokenParams, ), - tokenDetails: - (tokenDetails == null) ? null : _decodeTokenDetails(tokenDetails), + ); + final clientOptions = ClientOptions( + // AuthOptions (super class of ClientOptions) + authUrl: _readFromJson(jsonMap, TxClientOptions.authUrl), + authMethod: _readFromJson(jsonMap, TxClientOptions.authMethod), + key: _readFromJson(jsonMap, TxClientOptions.key), + tokenDetails: (tokenDetails == null) + ? null + : _decodeTokenDetails(tokenDetails), authHeaders: _readFromJson>( jsonMap, TxClientOptions.authHeaders, @@ -624,51 +699,27 @@ class Codec extends StandardMessageCodec { jsonMap, TxClientOptions.authParams, ), - queryTime: _readFromJson( - jsonMap, - TxClientOptions.queryTime, - ), - useTokenAuth: _readFromJson( - jsonMap, - TxClientOptions.useTokenAuth, - ), + queryTime: _readFromJson(jsonMap, TxClientOptions.queryTime), + useTokenAuth: _readFromJson(jsonMap, TxClientOptions.useTokenAuth), // ClientOptions - clientId: _readFromJson( - jsonMap, - TxClientOptions.clientId, - ), + clientId: _readFromJson(jsonMap, TxClientOptions.clientId), logLevel: _decodeLogLevel(jsonMap[TxClientOptions.logLevel] as String?), //TODO handle logHandler tls: jsonMap[TxClientOptions.tls] as bool, - restHost: _readFromJson( - jsonMap, - TxClientOptions.restHost, - ), + restHost: _readFromJson(jsonMap, TxClientOptions.restHost), realtimeHost: _readFromJson( jsonMap, TxClientOptions.realtimeHost, ), - port: _readFromJson( - jsonMap, - TxClientOptions.port, - ), - tlsPort: _readFromJson( - jsonMap, - TxClientOptions.tlsPort, - ), + port: _readFromJson(jsonMap, TxClientOptions.port), + tlsPort: _readFromJson(jsonMap, TxClientOptions.tlsPort), autoConnect: jsonMap[TxClientOptions.autoConnect] as bool, useBinaryProtocol: jsonMap[TxClientOptions.useBinaryProtocol] as bool, queueMessages: jsonMap[TxClientOptions.queueMessages] as bool, echoMessages: jsonMap[TxClientOptions.echoMessages] as bool, - recover: _readFromJson( - jsonMap, - TxClientOptions.recover, - ), - environment: _readFromJson( - jsonMap, - TxClientOptions.environment, - ), + recover: _readFromJson(jsonMap, TxClientOptions.recover), + environment: _readFromJson(jsonMap, TxClientOptions.environment), idempotentRestPublishing: _readFromJson( jsonMap, TxClientOptions.idempotentRestPublishing, @@ -688,8 +739,9 @@ class Codec extends StandardMessageCodec { ), fallbackRetryTimeout: jsonMap[TxClientOptions.fallbackRetryTimeout] as int, - defaultTokenParams: - (tokenParams == null) ? null : _decodeTokenParams(tokenParams), + defaultTokenParams: (tokenParams == null) + ? null + : _decodeTokenParams(tokenParams), channelRetryTimeout: jsonMap[TxClientOptions.channelRetryTimeout] as int, transportParams: _readFromJson>( jsonMap, @@ -753,12 +805,16 @@ class Codec extends StandardMessageCodec { final type = _readFromJson(jsonMap, TxAblyMessage.type); var message = jsonMap[TxAblyMessage.message] as Object; if (type != null) { - message = codecMap[type]!.decode( - toJsonMap(_readFromJson>( - jsonMap, - TxAblyMessage.message, - )), - ) as Object; + message = + codecMap[type]!.decode( + toJsonMap( + _readFromJson>( + jsonMap, + TxAblyMessage.message, + ), + ), + ) + as Object; } return AblyMessage( message: message, @@ -769,19 +825,23 @@ class Codec extends StandardMessageCodec { DeviceDetails _decodeDeviceDetails(Map jsonMap) { final formFactor = _decodeFormFactor( - _readFromJson(jsonMap, TxDeviceDetails.formFactor)); + _readFromJson(jsonMap, TxDeviceDetails.formFactor), + ); return DeviceDetails( id: jsonMap[TxDeviceDetails.id] as String?, clientId: jsonMap[TxDeviceDetails.clientId] as String?, - platform: - _decodeDevicePlatform(jsonMap[TxDeviceDetails.platform] as String), + platform: _decodeDevicePlatform( + jsonMap[TxDeviceDetails.platform] as String, + ), formFactor: formFactor, metadata: toTypedJsonMap( - jsonMap[TxDeviceDetails.metadata] as Map?), + jsonMap[TxDeviceDetails.metadata] as Map?, + ), push: _decodeDevicePushDetails( - Map.from(jsonMap[TxDeviceDetails.devicePushDetails] - as Map), + Map.from( + jsonMap[TxDeviceDetails.devicePushDetails] as Map, + ), ), ); } @@ -794,10 +854,12 @@ class Codec extends StandardMessageCodec { jsonMap[TxDevicePushDetails.recipient] as Map?; return DevicePushDetails( - recipient: - (recipient != null) ? Map.from(recipient) : null, - state: - _decodeDevicePushState(jsonMap[TxDevicePushDetails.state] as String?), + recipient: (recipient != null) + ? Map.from(recipient) + : null, + state: _decodeDevicePushState( + jsonMap[TxDevicePushDetails.state] as String?, + ), errorReason: (jsonMapErrorReason != null) ? _decodeErrorInfo(Map.from(jsonMapErrorReason)) : null, @@ -805,11 +867,10 @@ class Codec extends StandardMessageCodec { } LocalDevice _decodeLocalDevice(Map jsonMap) => LocalDevice( - deviceDetails: _decodeDeviceDetails(jsonMap), - deviceSecret: jsonMap[TxLocalDevice.deviceSecret] as String?, - deviceIdentityToken: - jsonMap[TxLocalDevice.deviceIdentityToken] as String?, - ); + deviceDetails: _decodeDeviceDetails(jsonMap), + deviceSecret: jsonMap[TxLocalDevice.deviceSecret] as String?, + deviceIdentityToken: jsonMap[TxLocalDevice.deviceIdentityToken] as String?, + ); FormFactor _decodeFormFactor(String? enumValue) { switch (enumValue) { @@ -865,46 +926,56 @@ class Codec extends StandardMessageCodec { } PushChannelSubscription _decodePushChannelSubscription( - Map jsonMap) => - PushChannelSubscription( - channel: jsonMap[TxPushChannelSubscription.channel] as String, - clientId: jsonMap[TxPushChannelSubscription.clientId] as String?, - deviceId: jsonMap[TxPushChannelSubscription.deviceId] as String?, - ); + Map jsonMap, + ) => PushChannelSubscription( + channel: jsonMap[TxPushChannelSubscription.channel] as String, + clientId: jsonMap[TxPushChannelSubscription.clientId] as String?, + deviceId: jsonMap[TxPushChannelSubscription.deviceId] as String?, + ); UNNotificationSettings _decodeUNNotificationSettings( - Map jsonMap) => - UNNotificationSettings( - authorizationStatus: _decodeUNAuthorizationStatus( - jsonMap[TxUNNotificationSettings.authorizationStatus] as String), - soundSetting: _decodeUNNotificationSetting( - jsonMap[TxUNNotificationSettings.soundSetting] as String), - badgeSetting: _decodeUNNotificationSetting( - jsonMap[TxUNNotificationSettings.badgeSetting] as String), - alertSetting: _decodeUNNotificationSetting( - jsonMap[TxUNNotificationSettings.alertSetting] as String), - notificationCenterSetting: _decodeUNNotificationSetting( - jsonMap[TxUNNotificationSettings.notificationCenterSetting] - as String), - lockScreenSetting: _decodeUNNotificationSetting( - jsonMap[TxUNNotificationSettings.lockScreenSetting] as String), - carPlaySetting: _decodeUNNotificationSetting( - jsonMap[TxUNNotificationSettings.carPlaySetting] as String), - alertStyle: _decodeUNAlertStyle( - jsonMap[TxUNNotificationSettings.alertStyle] as String), - showPreviewsSetting: _decodeUNShowPreviewsSetting( - jsonMap[TxUNNotificationSettings.showPreviewsSetting] as String), - criticalAlertSetting: _decodeUNNotificationSetting( - jsonMap[TxUNNotificationSettings.criticalAlertSetting] as String), - providesAppNotificationSettings: - jsonMap[TxUNNotificationSettings.providesAppNotificationSettings] - as bool, - announcementSetting: _decodeUNNotificationSetting( - jsonMap[TxUNNotificationSettings.announcementSetting] as String), - scheduledDeliverySetting: _decodeUNNotificationSetting( - jsonMap[TxUNNotificationSettings.scheduledDeliverySetting] - as String), - ); + Map jsonMap, + ) => UNNotificationSettings( + authorizationStatus: _decodeUNAuthorizationStatus( + jsonMap[TxUNNotificationSettings.authorizationStatus] as String, + ), + soundSetting: _decodeUNNotificationSetting( + jsonMap[TxUNNotificationSettings.soundSetting] as String, + ), + badgeSetting: _decodeUNNotificationSetting( + jsonMap[TxUNNotificationSettings.badgeSetting] as String, + ), + alertSetting: _decodeUNNotificationSetting( + jsonMap[TxUNNotificationSettings.alertSetting] as String, + ), + notificationCenterSetting: _decodeUNNotificationSetting( + jsonMap[TxUNNotificationSettings.notificationCenterSetting] as String, + ), + lockScreenSetting: _decodeUNNotificationSetting( + jsonMap[TxUNNotificationSettings.lockScreenSetting] as String, + ), + carPlaySetting: _decodeUNNotificationSetting( + jsonMap[TxUNNotificationSettings.carPlaySetting] as String, + ), + alertStyle: _decodeUNAlertStyle( + jsonMap[TxUNNotificationSettings.alertStyle] as String, + ), + showPreviewsSetting: _decodeUNShowPreviewsSetting( + jsonMap[TxUNNotificationSettings.showPreviewsSetting] as String, + ), + criticalAlertSetting: _decodeUNNotificationSetting( + jsonMap[TxUNNotificationSettings.criticalAlertSetting] as String, + ), + providesAppNotificationSettings: + jsonMap[TxUNNotificationSettings.providesAppNotificationSettings] + as bool, + announcementSetting: _decodeUNNotificationSetting( + jsonMap[TxUNNotificationSettings.announcementSetting] as String, + ), + scheduledDeliverySetting: _decodeUNNotificationSetting( + jsonMap[TxUNNotificationSettings.scheduledDeliverySetting] as String, + ), + ); UNShowPreviewsSetting _decodeUNShowPreviewsSetting(String setting) { switch (setting) { @@ -916,7 +987,8 @@ class Codec extends StandardMessageCodec { return UNShowPreviewsSetting.never; } throw AblyException( - message: 'Platform communication error. ' + message: + 'Platform communication error. ' 'UNShowPreviewsSetting is invalid: $setting', ); } @@ -931,7 +1003,8 @@ class Codec extends StandardMessageCodec { return UNAlertStyle.none; } throw AblyException( - message: 'Platform communication error. ' + message: + 'Platform communication error. ' 'UNAlertStyle is invalid: $style', ); } @@ -950,7 +1023,8 @@ class Codec extends StandardMessageCodec { return UNAuthorizationStatus.ephemeral; } throw AblyException( - message: 'Platform communication error. ' + message: + 'Platform communication error. ' 'UNAuthorizationStatus is invalid: $status', ); } @@ -965,7 +1039,8 @@ class Codec extends StandardMessageCodec { return UNNotificationSetting.notSupported; } throw AblyException( - message: 'Platform communication error. ' + message: + 'Platform communication error. ' 'UNNotificationSetting is invalid: $setting', ); } @@ -977,13 +1052,13 @@ class Codec extends StandardMessageCodec { /// Decodes value [jsonMap] to [ErrorInfo] /// returns null if [jsonMap] is null ErrorInfo _decodeErrorInfo(Map jsonMap) => ErrorInfo( - code: jsonMap[TxErrorInfo.code] as int?, - message: jsonMap[TxErrorInfo.message] as String?, - statusCode: jsonMap[TxErrorInfo.statusCode] as int?, - href: jsonMap[TxErrorInfo.href] as String?, - requestId: jsonMap[TxErrorInfo.requestId] as String?, - cause: jsonMap[TxErrorInfo.cause] as ErrorInfo?, - ); + code: jsonMap[TxErrorInfo.code] as int?, + message: jsonMap[TxErrorInfo.message] as String?, + statusCode: jsonMap[TxErrorInfo.statusCode] as int?, + href: jsonMap[TxErrorInfo.href] as String?, + requestId: jsonMap[TxErrorInfo.requestId] as String?, + cause: jsonMap[TxErrorInfo.cause] as ErrorInfo?, + ); /// @nodoc /// Decodes [eventName] to [ConnectionEvent] enum if not null @@ -1009,7 +1084,8 @@ class Codec extends StandardMessageCodec { return ConnectionEvent.update; } throw AblyException( - message: 'Platform communication error. ' + message: + 'Platform communication error. ' 'Connection event is invalid: $eventName', ); } @@ -1098,23 +1174,34 @@ class Codec extends StandardMessageCodec { EnrichedConnectionStateChange _decodeConnectionStateChange( Map jsonMap, ) { - final connectionId = - _readFromJson(jsonMap, TxConnectionStateChange.connectionId); - final connectionKey = - _readFromJson(jsonMap, TxConnectionStateChange.connectionKey); + final connectionId = _readFromJson( + jsonMap, + TxConnectionStateChange.connectionId, + ); + final connectionKey = _readFromJson( + jsonMap, + TxConnectionStateChange.connectionKey, + ); final current = _decodeConnectionState( - _readFromJson(jsonMap, TxConnectionStateChange.current)); + _readFromJson(jsonMap, TxConnectionStateChange.current), + ); final previous = _decodeConnectionState( - _readFromJson(jsonMap, TxConnectionStateChange.previous)); + _readFromJson(jsonMap, TxConnectionStateChange.previous), + ); final event = _decodeConnectionEvent( - _readFromJson(jsonMap, TxConnectionStateChange.event)); - final retryIn = - _readFromJson(jsonMap, TxConnectionStateChange.retryIn); - final errorInfo = toJsonMap(_readFromJson>( + _readFromJson(jsonMap, TxConnectionStateChange.event), + ); + final retryIn = _readFromJson( jsonMap, - TxConnectionStateChange.reason, - )); + TxConnectionStateChange.retryIn, + ); + final errorInfo = toJsonMap( + _readFromJson>( + jsonMap, + TxConnectionStateChange.reason, + ), + ); final reason = (errorInfo == null) ? null : _decodeErrorInfo(errorInfo); return EnrichedConnectionStateChange( stateChange: ConnectionStateChange( @@ -1134,16 +1221,21 @@ class Codec extends StandardMessageCodec { /// returns null if [jsonMap] is null ChannelStateChange _decodeChannelStateChange(Map jsonMap) { final current = _decodeChannelState( - _readFromJson(jsonMap, TxChannelStateChange.current)); + _readFromJson(jsonMap, TxChannelStateChange.current), + ); final previous = _decodeChannelState( - _readFromJson(jsonMap, TxChannelStateChange.previous)); + _readFromJson(jsonMap, TxChannelStateChange.previous), + ); final event = _decodeChannelEvent( - _readFromJson(jsonMap, TxChannelStateChange.event)); + _readFromJson(jsonMap, TxChannelStateChange.event), + ); final resumed = _readFromJson(jsonMap, TxChannelStateChange.resumed)!; - final errorInfo = toJsonMap(_readFromJson>( - jsonMap, - TxChannelStateChange.reason, - )); + final errorInfo = toJsonMap( + _readFromJson>( + jsonMap, + TxChannelStateChange.reason, + ), + ); final reason = (errorInfo == null) ? null : _decodeErrorInfo(errorInfo); return ChannelStateChange( current: current, @@ -1219,14 +1311,15 @@ class Codec extends StandardMessageCodec { final timestamp = _readFromJson(jsonMap, TxPresenceMessage.timestamp); return PresenceMessage( id: _readFromJson(jsonMap, TxPresenceMessage.id), - action: _decodePresenceAction(_readFromJson( - jsonMap, - TxPresenceMessage.action, - )), + action: _decodePresenceAction( + _readFromJson(jsonMap, TxPresenceMessage.action), + ), clientId: _readFromJson(jsonMap, TxPresenceMessage.clientId), data: _readFromJson(jsonMap, TxPresenceMessage.data), - connectionId: - _readFromJson(jsonMap, TxPresenceMessage.connectionId), + connectionId: _readFromJson( + jsonMap, + TxPresenceMessage.connectionId, + ), encoding: _readFromJson(jsonMap, TxPresenceMessage.encoding), extras: _readFromJson(jsonMap, TxPresenceMessage.extras), timestamp: (timestamp == null) @@ -1240,7 +1333,8 @@ class Codec extends StandardMessageCodec { /// returns null if [jsonMap] is null PaginatedResult _decodePaginatedResult(Map jsonMap) { final type = _readFromJson(jsonMap, TxPaginatedResult.type); - final items = _readFromJson>(jsonMap, TxPaginatedResult.items) + final items = + _readFromJson>(jsonMap, TxPaginatedResult.items) ?.map((e) => codecMap[type]?.decode(toJsonMap(e as Map)) as Object) .toList() ?? []; diff --git a/lib/src/platform/src/method_call_handler.dart b/lib/src/platform/src/method_call_handler.dart index ac05625d8..badf59130 100644 --- a/lib/src/platform/src/method_call_handler.dart +++ b/lib/src/platform/src/method_call_handler.dart @@ -26,16 +26,18 @@ class AblyMethodCallHandler { case PlatformMethod.pushOnBackgroundMessage: return _onPushBackgroundMessage(call.arguments as RemoteMessage); case PlatformMethod.pushOnShowNotificationInForeground: - return _pushNotificationEvents - .showNotificationInForeground(call.arguments as RemoteMessage); + return _pushNotificationEvents.showNotificationInForeground( + call.arguments as RemoteMessage, + ); case PlatformMethod.pushOnNotificationTap: return _onNotificationTap(call.arguments as RemoteMessage); case PlatformMethod.pushOpenSettingsFor: return _onOpenSettingsFor(); default: throw PlatformException( - code: 'Received invalid method channel call from Platform side', - message: 'No such method ${call.method}'); + code: 'Received invalid method channel call from Platform side', + message: 'No such method ${call.method}', + ); } }); } @@ -47,7 +49,8 @@ class AblyMethodCallHandler { final rest = restInstances[message.handle]; if (rest == null) { throw AblyException( - message: "AblyMethodCallHandler#onAuthCallback's " + message: + "AblyMethodCallHandler#onAuthCallback's " 'rest handle is ${message.handle}, and rest is $rest', ); } @@ -61,7 +64,8 @@ class AblyMethodCallHandler { final realtime = realtimeInstances[message.handle]; if (realtime == null) { throw AblyException( - message: "AblyMethodCallHandler#onRealtimeAuthCallback's " + message: + "AblyMethodCallHandler#onRealtimeAuthCallback's " 'realtime handle is ${message.handle}, and realtime is $realtime', ); } @@ -99,8 +103,9 @@ class AblyMethodCallHandler { } Future _onNotificationTap(RemoteMessage remoteMessage) async { - _pushNotificationEvents.onNotificationTapStreamController - .add(remoteMessage); + _pushNotificationEvents.onNotificationTapStreamController.add( + remoteMessage, + ); return null; } diff --git a/lib/src/platform/src/paginated_result.dart b/lib/src/platform/src/paginated_result.dart index 37b7d49b4..b9c88ce10 100644 --- a/lib/src/platform/src/paginated_result.dart +++ b/lib/src/platform/src/paginated_result.dart @@ -32,8 +32,8 @@ class PaginatedResult extends PlatformObject { /// Creates a PaginatedResult instance from items and a boolean indicating /// whether there is a next page PaginatedResult(this._items, {required bool hasNext}) - : _hasNext = hasNext, - super(fetchHandle: false); + : _hasNext = hasNext, + super(fetchHandle: false); /// @nodoc /// Instantiates by extracting result from [AblyMessage] returned from @@ -42,10 +42,10 @@ class PaginatedResult extends PlatformObject { /// Sets appropriate [_pageHandle] for identifying platform side of this /// result object so that [next] and [first] can be executed PaginatedResult.fromAblyMessage(AblyMessage> message) - : _hasNext = message.message.hasNext(), - _items = message.message.items.map((e) => e as T).toList(), - _pageHandle = message.handle, - super(fetchHandle: false); + : _hasNext = message.message.hasNext(), + _items = message.message.items.map((e) => e as T).toList(), + _pageHandle = message.handle, + super(fetchHandle: false); /// @nodoc @override @@ -57,8 +57,9 @@ class PaginatedResult extends PlatformObject { /// /// If there are no further pages, then null is returned. Future> next() async { - final message = - await invokeRequest>(PlatformMethod.nextPage); + final message = await invokeRequest>( + PlatformMethod.nextPage, + ); return PaginatedResult.fromAblyMessage( AblyMessage.castFrom>(message), ); @@ -68,8 +69,9 @@ class PaginatedResult extends PlatformObject { /// and presence history, stats, and REST presence requests, for the first /// page of results. Future> first() async { - final message = - await invokeRequest>(PlatformMethod.firstPage); + final message = await invokeRequest>( + PlatformMethod.firstPage, + ); return PaginatedResult.fromAblyMessage( AblyMessage.castFrom>(message), ); diff --git a/lib/src/platform/src/platform.dart b/lib/src/platform/src/platform.dart index 4f30f8d87..51df109d8 100644 --- a/lib/src/platform/src/platform.dart +++ b/lib/src/platform/src/platform.dart @@ -18,7 +18,8 @@ class Platform { AblyMethodCallHandler(_methodChannel!); BackgroundIsolateAndroidPlatform().setupCallHandler(); _ablyClientsResetFuture = _invokePlatformMethodWithoutResetCheck( - PlatformMethod.resetAblyClients); + PlatformMethod.resetAblyClients, + ); } static Platform? _platform; @@ -47,8 +48,10 @@ class Platform { /// @nodoc /// Call a platform method which may return null/void as a result and /// check that ably clients have successfully reset - Future invokePlatformMethod(String method, - [AblyMessage>? arguments]) async { + Future invokePlatformMethod( + String method, [ + AblyMessage>? arguments, + ]) async { // Check if ably clients have successfully reset // (to ensure platform method calls won't interfere // with each other after Platform singleton is reinitialized) @@ -58,13 +61,17 @@ class Platform { /// @nodoc /// Call a platform method which always provides a non-null result - Future invokePlatformMethodNonNull(String method, - [AblyMessage>? arguments]) async { + Future invokePlatformMethodNonNull( + String method, [ + AblyMessage>? arguments, + ]) async { final result = await invokePlatformMethod(method, arguments); if (result == null) { throw AblyException( - message: 'invokePlatformMethodNonNull("$method") platform ' - 'method unexpectedly returned a null value.'); + message: + 'invokePlatformMethodNonNull("$method") platform ' + 'method unexpectedly returned a null value.', + ); } else { return result; } @@ -72,8 +79,10 @@ class Platform { /// @nodoc /// Call a platform method which may return null/void as a result - Future _invokePlatformMethodWithoutResetCheck(String method, - [AblyMessage>? arguments]) async { + Future _invokePlatformMethodWithoutResetCheck( + String method, [ + AblyMessage>? arguments, + ]) async { try { // If argument is null, pass an empty [AblyMessage], because codec fails // if argument value is null @@ -92,15 +101,14 @@ class Platform { /// @nodoc /// Call a platform method which always provides an observable stream /// of data as a result - Stream receiveBroadcastStream(String methodName, int handle, - [final Object? payload]) => - _streamsChannel!.receiveBroadcastStream( - AblyMessage( - message: AblyEventMessage( - eventName: methodName, - message: payload, - ), - handle: handle, - ), - ); + Stream receiveBroadcastStream( + String methodName, + int handle, [ + final Object? payload, + ]) => _streamsChannel!.receiveBroadcastStream( + AblyMessage( + message: AblyEventMessage(eventName: methodName, message: payload), + handle: handle, + ), + ); } diff --git a/lib/src/platform/src/platform_object.dart b/lib/src/platform/src/platform_object.dart index 881f7be32..96d410582 100644 --- a/lib/src/platform/src/platform_object.dart +++ b/lib/src/platform/src/platform_object.dart @@ -44,20 +44,22 @@ abstract class PlatformObject { /// This method should be protected since it's only used to cover edge /// case for creating rest and realtime instances. @protected - Future invokeWithoutHandle(final String method, - [final Map? argument]) async { - final message = AblyMessage( - message: argument ?? {}, - ); + Future invokeWithoutHandle( + final String method, [ + final Map? argument, + ]) async { + final message = AblyMessage(message: argument ?? {}); return _platform.invokePlatformMethod(method, message); } /// @nodoc /// Invoke platform method channel with provided handle, or /// current handle if [externalHandle] is not provided. - Future invoke(final String method, - [final Map? arguments, - final int? externalHandle]) async { + Future invoke( + final String method, [ + final Map? arguments, + final int? externalHandle, + ]) async { final message = AblyMessage( message: arguments ?? {}, handle: externalHandle ?? await handle, @@ -69,8 +71,10 @@ abstract class PlatformObject { /// Invoke platform method channel with AblyMessage encapsulation. /// /// This is similar to [invoke], but ensures the response is not null. - Future invokeRequest(final String method, - [final Map? arguments]) async { + Future invokeRequest( + final String method, [ + final Map? arguments, + ]) async { final response = await invoke(method, arguments); if (response == null) { throw AblyException( @@ -89,8 +93,10 @@ abstract class PlatformObject { // ignore: close_sinks, will be closed by listener final controller = StreamController(); handle - .then((handle) => - _platform.receiveBroadcastStream(method, handle, payload)) + .then( + (handle) => + _platform.receiveBroadcastStream(method, handle, payload), + ) .then(controller.addStream); return controller.stream; } diff --git a/lib/src/platform/src/push_notification_events_internal.dart b/lib/src/platform/src/push_notification_events_internal.dart index a00e42193..3cbddb821 100644 --- a/lib/src/platform/src/push_notification_events_internal.dart +++ b/lib/src/platform/src/push_notification_events_internal.dart @@ -15,7 +15,7 @@ class PushNotificationEventsInternal implements PushNotificationEvents { /// @nodoc /// Invoked when pushOnShowNotificationInForeground platform method is called. Future Function(RemoteMessage message)? - onShowNotificationInForegroundHandler; + onShowNotificationInForegroundHandler; /// @nodoc /// Exposes stream of received [RemoteMessage] objects. @@ -34,7 +34,8 @@ class PushNotificationEventsInternal implements PushNotificationEvents { @override Future get notificationTapLaunchedAppFromTerminated => Platform().invokePlatformMethod( - PlatformMethod.pushNotificationTapLaunchedAppFromTerminated); + PlatformMethod.pushNotificationTapLaunchedAppFromTerminated, + ); @override Stream get onMessage => onMessageStreamController.stream; @@ -50,7 +51,8 @@ class PushNotificationEventsInternal implements PushNotificationEvents { @override void setOnShowNotificationInForeground( - Future Function(RemoteMessage message) callback) { + Future Function(RemoteMessage message) callback, + ) { onShowNotificationInForegroundHandler = callback; } @@ -91,10 +93,12 @@ class PushNotificationEventsInternal implements PushNotificationEvents { } } else { // ignore:avoid_print - print('Received RemoteMessage but no handler was set. ' - 'RemoteMessage.data: ${remoteMessage.data}. ' - 'RemoteMessage.notification: ${remoteMessage.notification}. ' - 'Set `ably.Push.notificationEvents.setOnBackgroundMessage()`.'); + print( + 'Received RemoteMessage but no handler was set. ' + 'RemoteMessage.data: ${remoteMessage.data}. ' + 'RemoteMessage.notification: ${remoteMessage.notification}. ' + 'Set `ably.Push.notificationEvents.setOnBackgroundMessage()`.', + ); } } diff --git a/lib/src/platform/src/realtime/connection.dart b/lib/src/platform/src/realtime/connection.dart index b1dce0142..0f748d2a3 100644 --- a/lib/src/platform/src/realtime/connection.dart +++ b/lib/src/platform/src/realtime/connection.dart @@ -22,9 +22,7 @@ class Connection extends PlatformObject { /// /// Sets default [state] to [ConnectionState.initialized] and starts listening /// for updates to the connection [state]. - Connection(this.realtime) - : _state = ConnectionState.initialized, - super() { + Connection(this.realtime) : _state = ConnectionState.initialized, super() { _onConnectionStateChange().listen((event) { _state = event.stateChange.current; _errorReason = event.stateChange.reason; @@ -92,10 +90,13 @@ class Connection extends PlatformObject { /// Stream of connection events with specified [ConnectionEvent] type. Stream on([ConnectionEvent? connectionEvent]) => - _onConnectionStateChange().map((event) => event.stateChange).where( - (connectionStateChange) => - connectionEvent == null || - connectionStateChange.event == connectionEvent); + _onConnectionStateChange() + .map((event) => event.stateChange) + .where( + (connectionStateChange) => + connectionEvent == null || + connectionStateChange.event == connectionEvent, + ); /// Causes the connection to close, entering the [ConnectionState.closing] /// state. diff --git a/lib/src/platform/src/realtime/presence.dart b/lib/src/platform/src/realtime/presence.dart index 25bc10cfa..782789d76 100644 --- a/lib/src/platform/src/realtime/presence.dart +++ b/lib/src/platform/src/realtime/presence.dart @@ -17,16 +17,12 @@ class RealtimePresence extends PlatformObject { /// Retrieves the current members present on the channel and the metadata for /// each member, such as their [PresenceAction] and ID, based on provided /// [params]. Returns an array of [PresenceMessage] objects. - Future> get([ - RealtimePresenceParams? params, - ]) async { - final presenceMessages = await invokeRequest>( - PlatformMethod.realtimePresenceGet, - { - TxTransportKeys.channelName: _channel.name, - if (params != null) TxTransportKeys.params: params - }, - ); + Future> get([RealtimePresenceParams? params]) async { + final presenceMessages = + await invokeRequest>(PlatformMethod.realtimePresenceGet, { + TxTransportKeys.channelName: _channel.name, + if (params != null) TxTransportKeys.params: params, + }); return presenceMessages .map((e) => e as PresenceMessage) .toList(); @@ -46,7 +42,7 @@ class RealtimePresence extends PlatformObject { PlatformMethod.realtimePresenceHistory, { TxTransportKeys.channelName: _channel.name, - if (params != null) TxTransportKeys.params: params + if (params != null) TxTransportKeys.params: params, }, ); return PaginatedResult.fromAblyMessage( @@ -144,7 +140,9 @@ class RealtimePresence extends PlatformObject { if (action != null) actions ??= [action]; return listen(PlatformMethod.onRealtimePresenceMessage, { TxTransportKeys.channelName: _channel.name, - }).where((presenceMessage) => - actions == null || actions.contains(presenceMessage.action)); + }).where( + (presenceMessage) => + actions == null || actions.contains(presenceMessage.action), + ); } } diff --git a/lib/src/platform/src/realtime/realtime.dart b/lib/src/platform/src/realtime/realtime.dart index d186dbdc7..2c0815c05 100644 --- a/lib/src/platform/src/realtime/realtime.dart +++ b/lib/src/platform/src/realtime/realtime.dart @@ -11,12 +11,10 @@ import 'package:ably_flutter/src/realtime/src/realtime_auth.dart'; class Realtime extends PlatformObject { /// Constructs a `Realtime` object using an Ably [options] object or /// the Ably API [key] or token string used to validate the client. - Realtime({ - ClientOptions? options, - final String? key, - }) : assert(options != null || key != null), - options = options ?? ClientOptions(key: key), - super() { + Realtime({ClientOptions? options, final String? key}) + : assert(options != null || key != null), + options = options ?? ClientOptions(key: key), + super() { _connection = Connection(this); _channels = RealtimeChannels(this); push = Push(realtime: this); @@ -31,10 +29,10 @@ class Realtime extends PlatformObject { ///@nodoc @override Future createPlatformInstance() async { - final handle = - await invokeWithoutHandle(PlatformMethod.createRealtime, { - TxTransportKeys.options: options, - }); + final handle = await invokeWithoutHandle( + PlatformMethod.createRealtime, + {TxTransportKeys.options: options}, + ); _realtimeInstances[handle] = this; if (io.Platform.isAndroid && options.autoConnect) { @@ -45,11 +43,7 @@ class Realtime extends PlatformObject { // to false, and call connect immediately once we get the handle. // This is also a specific case where it's required to pass the handle // value from external source - await invoke( - PlatformMethod.connectRealtime, - null, - handle, - ); + await invoke(PlatformMethod.connectRealtime, null, handle); } return handle; } diff --git a/lib/src/platform/src/realtime/realtime_channel.dart b/lib/src/platform/src/realtime/realtime_channel.dart index 309a95c9d..01021e88f 100644 --- a/lib/src/platform/src/realtime/realtime_channel.dart +++ b/lib/src/platform/src/realtime/realtime_channel.dart @@ -29,10 +29,10 @@ class RealtimeChannel extends PlatformObject { /// sets default [state] to [ChannelState.initialized] and start listening /// for updates to the channel [state]/ RealtimeChannel(Realtime realtime, String channelName) - : _realtime = realtime, - _channelName = channelName, - state = ChannelState.initialized, - super() { + : _realtime = realtime, + _channelName = channelName, + state = ChannelState.initialized, + super() { _presence = RealtimePresence(this); push = PushChannel(_channelName, realtime: _realtime); on().listen((event) => state = event.current); @@ -55,10 +55,12 @@ class RealtimeChannel extends PlatformObject { RealtimeHistoryParams? params, ]) async { final message = await invokeRequest>( - PlatformMethod.realtimeHistory, { - TxTransportKeys.channelName: _channelName, - if (params != null) TxTransportKeys.params: params, - }); + PlatformMethod.realtimeHistory, + { + TxTransportKeys.channelName: _channelName, + if (params != null) TxTransportKeys.params: params, + }, + ); return PaginatedResult.fromAblyMessage( AblyMessage.castFrom>(message), ); @@ -76,7 +78,7 @@ class RealtimeChannel extends PlatformObject { Object? data, }) async { messages ??= [ - if (message == null) Message(name: name, data: data) else message + if (message == null) Message(name: name, data: data) else message, ]; await invoke(PlatformMethod.publishRealtimeChannelMessage, { TxTransportKeys.channelName: _channelName, @@ -114,8 +116,8 @@ class RealtimeChannel extends PlatformObject { /// [RealtimePresence.subscribe] are called on the [RealtimePresence] object /// for this channel. Future attach() => invoke(PlatformMethod.attachRealtimeChannel, { - TxTransportKeys.channelName: _channelName, - }); + TxTransportKeys.channelName: _channelName, + }); /// Detach from this channel. Any resulting channel state change is emitted to /// any listeners registered using the [RealtimeChannel.on] stream. @@ -123,8 +125,8 @@ class RealtimeChannel extends PlatformObject { /// Once all clients globally have detached from the channel, the channel will /// be released in the Ably service within two minutes. Future detach() => invoke(PlatformMethod.detachRealtimeChannel, { - TxTransportKeys.channelName: _channelName, - }); + TxTransportKeys.channelName: _channelName, + }); /// Sets the [options] for the channel. Future setOptions(RealtimeChannelOptions options) => @@ -135,10 +137,9 @@ class RealtimeChannel extends PlatformObject { /// Stream of channel events with specified [ChannelEvent] type Stream on([ChannelEvent? channelEvent]) => - listen( - PlatformMethod.onRealtimeChannelStateChanged, - {TxTransportKeys.channelName: _channelName}, - ).where( + listen(PlatformMethod.onRealtimeChannelStateChanged, { + TxTransportKeys.channelName: _channelName, + }).where( (stateChange) => channelEvent == null || stateChange.event == channelEvent, ); @@ -156,8 +157,10 @@ class RealtimeChannel extends PlatformObject { final subscribedNames = {name, ...?names}.where((n) => n != null).toList(); return listen(PlatformMethod.onRealtimeChannelMessage, { TxTransportKeys.channelName: _channelName, - }).where((message) => - subscribedNames.isEmpty || - subscribedNames.any((n) => n == message.name)); + }).where( + (message) => + subscribedNames.isEmpty || + subscribedNames.any((n) => n == message.name), + ); } } diff --git a/lib/src/platform/src/rest/rest_channel.dart b/lib/src/platform/src/rest/rest_channel.dart index 906e9bcdf..0dff24415 100644 --- a/lib/src/platform/src/rest/rest_channel.dart +++ b/lib/src/platform/src/rest/rest_channel.dart @@ -40,16 +40,12 @@ class RestChannel extends PlatformObject { /// If the channel is configured to persist messages, then messages can be /// retrieved from history for up to 72 hours in the past. If not, messages /// can only be retrieved from history for up to two minutes in the past. - Future> history([ - RestHistoryParams? params, - ]) async { - final message = await invokeRequest>( - PlatformMethod.restHistory, - { - TxTransportKeys.channelName: name, - if (params != null) TxTransportKeys.params: params - }, - ); + Future> history([RestHistoryParams? params]) async { + final message = + await invokeRequest>(PlatformMethod.restHistory, { + TxTransportKeys.channelName: name, + if (params != null) TxTransportKeys.params: params, + }); return PaginatedResult.fromAblyMessage( AblyMessage.castFrom>(message), ); @@ -64,7 +60,7 @@ class RestChannel extends PlatformObject { Object? data, }) async { messages ??= [ - if (message == null) Message(name: name, data: data) else message + if (message == null) Message(name: name, data: data) else message, ]; await invoke(PlatformMethod.publish, { TxTransportKeys.channelName: this.name, @@ -73,9 +69,8 @@ class RestChannel extends PlatformObject { } /// Sets the [options] for the channel. - Future setOptions(RestChannelOptions options) => - invoke(PlatformMethod.setRestChannelOptions, { - TxTransportKeys.channelName: name, - TxTransportKeys.options: options, - }); + Future setOptions(RestChannelOptions options) => invoke( + PlatformMethod.setRestChannelOptions, + {TxTransportKeys.channelName: name, TxTransportKeys.options: options}, + ); } diff --git a/lib/src/platform/src/rest/rest_presence.dart b/lib/src/platform/src/rest/rest_presence.dart index 84835afbd..cb961d551 100644 --- a/lib/src/platform/src/rest/rest_presence.dart +++ b/lib/src/platform/src/rest/rest_presence.dart @@ -27,7 +27,7 @@ class RestPresence extends PlatformObject { PlatformMethod.restPresenceGet, { TxTransportKeys.channelName: _restChannel.name, - if (params != null) TxTransportKeys.params: params + if (params != null) TxTransportKeys.params: params, }, ); return PaginatedResult.fromAblyMessage( @@ -50,7 +50,7 @@ class RestPresence extends PlatformObject { PlatformMethod.restPresenceHistory, { TxTransportKeys.channelName: _restChannel.name, - if (params != null) TxTransportKeys.params: params + if (params != null) TxTransportKeys.params: params, }, ); return PaginatedResult.fromAblyMessage( diff --git a/lib/src/platform/src/streams_channel.dart b/lib/src/platform/src/streams_channel.dart index 45b156436..853b3725b 100644 --- a/lib/src/platform/src/streams_channel.dart +++ b/lib/src/platform/src/streams_channel.dart @@ -50,57 +50,70 @@ class StreamsChannel { final handlerName = '$name#$id'; late StreamController controller; - controller = StreamController.broadcast(onListen: () async { - // We need to keep this null-asserted for backwards compatibility with - // Flutter versions before 3.0.0 - // ignore: unnecessary_non_null_assertion - ServicesBinding.instance!.defaultBinaryMessenger - .setMessageHandler(handlerName, (reply) async { - if (reply == null) { - await controller.close(); - } else { - try { - controller.add(codec.decodeEnvelope(reply) as T); - } on PlatformException catch (pe) { - if (pe.details is ErrorInfo) { - throw AblyException.fromPlatformException(pe); + controller = StreamController.broadcast( + onListen: () async { + // We need to keep this null-asserted for backwards compatibility with + // Flutter versions before 3.0.0 + // ignore: unnecessary_non_null_assertion + ServicesBinding.instance!.defaultBinaryMessenger.setMessageHandler( + handlerName, + (reply) async { + if (reply == null) { + await controller.close(); } else { - controller.addError(pe); + try { + controller.add(codec.decodeEnvelope(reply) as T); + } on PlatformException catch (pe) { + if (pe.details is ErrorInfo) { + throw AblyException.fromPlatformException(pe); + } else { + controller.addError(pe); + } + } } - } - } - return reply; - }); - try { - await methodChannel.invokeMethod('listen#$id', arguments); - } on Exception catch (exception, stack) { - FlutterError.reportError(FlutterErrorDetails( - exception: exception, - stack: stack, - library: 'streams_channel', - context: DiagnosticsNode.message( - 'while activating platform stream on channel $name'), - )); - } - }, onCancel: () async { - // We need to keep this null-asserted for backwards compatibility with - // Flutter versions before 3.0.0 - // ignore: unnecessary_non_null_assertion - ServicesBinding.instance!.defaultBinaryMessenger - .setMessageHandler(handlerName, null); - try { - await methodChannel.invokeMethod('cancel#$id', arguments); - } on Exception catch (exception, stack) { - FlutterError.reportError(FlutterErrorDetails( - exception: exception, - stack: stack, - library: 'streams_channel', - context: DiagnosticsNode.message( - 'while de-activating platform stream on channel $name'), - )); - } - }); + return reply; + }, + ); + try { + await methodChannel.invokeMethod('listen#$id', arguments); + } on Exception catch (exception, stack) { + FlutterError.reportError( + FlutterErrorDetails( + exception: exception, + stack: stack, + library: 'streams_channel', + context: DiagnosticsNode.message( + 'while activating platform stream on channel $name', + ), + ), + ); + } + }, + onCancel: () async { + // We need to keep this null-asserted for backwards compatibility with + // Flutter versions before 3.0.0 + // ignore: unnecessary_non_null_assertion + ServicesBinding.instance!.defaultBinaryMessenger.setMessageHandler( + handlerName, + null, + ); + try { + await methodChannel.invokeMethod('cancel#$id', arguments); + } on Exception catch (exception, stack) { + FlutterError.reportError( + FlutterErrorDetails( + exception: exception, + stack: stack, + library: 'streams_channel', + context: DiagnosticsNode.message( + 'while de-activating platform stream on channel $name', + ), + ), + ); + } + }, + ); return controller.stream; } } diff --git a/lib/src/push_notifications/src/admin/push_device_registrations.dart b/lib/src/push_notifications/src/admin/push_device_registrations.dart index 3666c7d6a..90ba8bb66 100644 --- a/lib/src/push_notifications/src/admin/push_device_registrations.dart +++ b/lib/src/push_notifications/src/admin/push_device_registrations.dart @@ -5,17 +5,12 @@ abstract class PushDeviceRegistrations { /// Retrieves the [DeviceDetails] of a device registered /// to receive push notifications using the `id` property of a /// [DeviceDetails] object, or by directly using the unique [deviceId]. - Future get({ - DeviceDetails? deviceDetails, - String? deviceId, - }); + Future get({DeviceDetails? deviceDetails, String? deviceId}); /// Retrieves all devices matching the filter [params] provided. /// Returns a [PaginatedResult] object, containing an array of [DeviceDetails] /// objects. - Future> list( - DeviceRegistrationParams params, - ); + Future> list(DeviceRegistrationParams params); /// Registers or updates a [deviceDetails] object with Ably. Returns the new, /// or updated [DeviceDetails] object. @@ -24,10 +19,7 @@ abstract class PushDeviceRegistrations { /// Removes a device registered to receive push notifications from Ably using /// the id property of a [deviceDetails] object, or by directly using the /// unique [deviceId]. - Future remove({ - DeviceDetails? deviceDetails, - String? deviceId, - }); + Future remove({DeviceDetails? deviceDetails, String? deviceId}); /// Removes all devices registered to receive push notifications from Ably /// matching the filter [params] provided. diff --git a/lib/src/push_notifications/src/device_push_details.dart b/lib/src/push_notifications/src/device_push_details.dart index 761b8f1fb..f3ee57f7d 100644 --- a/lib/src/push_notifications/src/device_push_details.dart +++ b/lib/src/push_notifications/src/device_push_details.dart @@ -17,9 +17,5 @@ class DevicePushDetails { /// @nodoc /// Initializes an instance without any defaults - const DevicePushDetails({ - this.errorReason, - this.recipient, - this.state, - }); + const DevicePushDetails({this.errorReason, this.recipient, this.state}); } diff --git a/lib/src/push_notifications/src/ios_notification_settings.dart b/lib/src/push_notifications/src/ios_notification_settings.dart index a054ed0a2..cf5d1eb82 100644 --- a/lib/src/push_notifications/src/ios_notification_settings.dart +++ b/lib/src/push_notifications/src/ios_notification_settings.dart @@ -26,31 +26,19 @@ enum UNAuthorizationStatus { /// Constants indicating the presentation styles for alerts. /// /// [Apple docs](https://developer.apple.com/documentation/usernotifications/unalertstyle) -enum UNAlertStyle { - none, - banner, - alert, -} +enum UNAlertStyle { none, banner, alert } /// @nodoc /// Constants that indicate the current status of a notification setting. /// /// [Apple docs](https://developer.apple.com/documentation/usernotifications/unnotificationsetting) -enum UNNotificationSetting { - notSupported, - disabled, - enabled, -} +enum UNNotificationSetting { notSupported, disabled, enabled } /// @nodoc /// Constants indicating the style previewing a notification's content. /// /// [Apple docs](https://developer.apple.com/documentation/usernotifications/unshowpreviewssetting) -enum UNShowPreviewsSetting { - always, - whenAuthenticated, - never, -} +enum UNShowPreviewsSetting { always, whenAuthenticated, never } /// @nodoc /// The object for managing notification-related settings and the authorization diff --git a/lib/src/push_notifications/src/local_device.dart b/lib/src/push_notifications/src/local_device.dart index 8853ab13e..d48886072 100644 --- a/lib/src/push_notifications/src/local_device.dart +++ b/lib/src/push_notifications/src/local_device.dart @@ -19,11 +19,11 @@ class LocalDevice extends DeviceDetails { this.deviceIdentityToken, this.deviceSecret, }) : super( - clientId: deviceDetails.clientId, - formFactor: deviceDetails.formFactor, - id: deviceDetails.id, - metadata: deviceDetails.metadata, - platform: deviceDetails.platform, - push: deviceDetails.push, - ); + clientId: deviceDetails.clientId, + formFactor: deviceDetails.formFactor, + id: deviceDetails.id, + metadata: deviceDetails.metadata, + platform: deviceDetails.platform, + push: deviceDetails.push, + ); } diff --git a/lib/src/push_notifications/src/notification.dart b/lib/src/push_notifications/src/notification.dart index cfe0acfb2..88b2dfc99 100644 --- a/lib/src/push_notifications/src/notification.dart +++ b/lib/src/push_notifications/src/notification.dart @@ -17,15 +17,12 @@ class Notification { /// @nodoc /// Initializes an instance without any defaults. - const Notification({ - required this.title, - this.body, - }); + const Notification({required this.title, this.body}); /// @nodoc /// Creates an instance from the map. factory Notification.fromMap(Map map) => Notification( - body: map[TxNotification.body] as String?, - title: map[TxNotification.title] as String? ?? '', - ); + body: map[TxNotification.body] as String?, + title: map[TxNotification.title] as String? ?? '', + ); } diff --git a/lib/src/push_notifications/src/push.dart b/lib/src/push_notifications/src/push.dart index bd1db2d87..a9a5c6dc6 100644 --- a/lib/src/push_notifications/src/push.dart +++ b/lib/src/push_notifications/src/push.dart @@ -25,15 +25,13 @@ class Push extends PlatformObject { /// @nodoc /// Pass an Ably realtime or rest client. - Push({ - this.realtime, - this.rest, - }) : super() { + Push({this.realtime, this.rest}) : super() { final ablyClientNotPresent = rest == null && realtime == null; final moreThanOneAblyClientPresent = rest != null && realtime != null; if (ablyClientNotPresent || moreThanOneAblyClientPresent) { throw Exception( - 'Specify one Ably client when creating ${(Push).toString()}.'); + 'Specify one Ably client when creating ${(Push).toString()}.', + ); } } @@ -105,7 +103,8 @@ class Push extends PlatformObject { Future getNotificationSettings() async { if (io.Platform.isIOS) { return invokeRequest( - PlatformMethod.pushGetNotificationSettings); + PlatformMethod.pushGetNotificationSettings, + ); } else { throw UnsupportedError('getNotificationSettings is only valid on iOS.'); } diff --git a/lib/src/push_notifications/src/push_channel.dart b/lib/src/push_notifications/src/push_channel.dart index 2d134620d..5afe8641c 100644 --- a/lib/src/push_notifications/src/push_channel.dart +++ b/lib/src/push_notifications/src/push_channel.dart @@ -20,7 +20,8 @@ class PushChannel extends PlatformObject { final moreThanOneAblyClientPresent = rest != null && realtime != null; if (ablyClientNotPresent || moreThanOneAblyClientPresent) { throw Exception( - 'Specify one Ably client when creating ${(Push).toString()}.'); + 'Specify one Ably client when creating ${(Push).toString()}.', + ); } } @@ -31,24 +32,28 @@ class PushChannel extends PlatformObject { : (rest as Rest).handle; /// Subscribes the device to push notifications for the channel. - Future subscribeDevice() => invoke( - PlatformMethod.pushSubscribeDevice, {TxTransportKeys.channelName: _name}); + Future subscribeDevice() => invoke(PlatformMethod.pushSubscribeDevice, { + TxTransportKeys.channelName: _name, + }); /// Unsubscribes the device from receiving push notifications for the channel. Future unsubscribeDevice() => invoke( - PlatformMethod.pushUnsubscribeDevice, - {TxTransportKeys.channelName: _name}); + PlatformMethod.pushUnsubscribeDevice, + {TxTransportKeys.channelName: _name}, + ); /// Subscribes all devices associated with the current device's `clientId` to /// push notifications for the channel. - Future subscribeClient() => invoke( - PlatformMethod.pushSubscribeClient, {TxTransportKeys.channelName: _name}); + Future subscribeClient() => invoke(PlatformMethod.pushSubscribeClient, { + TxTransportKeys.channelName: _name, + }); /// Unsubscribes all devices associated with the current device's `clientId` /// from receiving push notifications for the channel. Future unsubscribeClient() => invoke( - PlatformMethod.pushUnsubscribeClient, - {TxTransportKeys.channelName: _name}); + PlatformMethod.pushUnsubscribeClient, + {TxTransportKeys.channelName: _name}, + ); /// Retrieves all push subscriptions for the channel. /// @@ -60,7 +65,8 @@ class PushChannel extends PlatformObject { /// Returns a [PaginatedResult] object containing a list of /// [PushChannelSubscription] objects. Future> listSubscriptions( - Map params) async { + Map params, + ) async { if (!params.containsKey('deviceId') && !params.containsKey('clientId') && !params.containsKey('deviceClientId') && @@ -68,7 +74,8 @@ class PushChannel extends PlatformObject { // This error only happen on Androids. They are thrown here // for both platforms (iOS/ Android) to make the API more consistent. throw AblyException( - message: "expected parameter 'deviceId', 'clientId', " + message: + "expected parameter 'deviceId', 'clientId', " "'deviceClientId', and/or 'channel'", ); } @@ -79,6 +86,7 @@ class PushChannel extends PlatformObject { ); return PaginatedResult.fromAblyMessage( - AblyMessage.castFrom>(message)); + AblyMessage.castFrom>(message), + ); } } diff --git a/lib/src/push_notifications/src/push_channel_subscriptions.dart b/lib/src/push_notifications/src/push_channel_subscriptions.dart index 0d1b3e8d3..bfea3dd85 100644 --- a/lib/src/push_notifications/src/push_channel_subscriptions.dart +++ b/lib/src/push_notifications/src/push_channel_subscriptions.dart @@ -13,9 +13,7 @@ abstract class PushChannelSubscriptions { /// notifications using a [params] object. /// /// Returns a [PaginatedResult] object, containing an array of channel names. - Future> listChannels( - PushChannelsParams params, - ); + Future> listChannels(PushChannelsParams params); /// Subscribes a device, or a group of devices sharing the same `clientId` to /// push notifications on a channel, using the [subscription] object. diff --git a/lib/src/push_notifications/src/push_notification_events.dart b/lib/src/push_notifications/src/push_notification_events.dart index f36ff76ea..db3ec5f39 100644 --- a/lib/src/push_notifications/src/push_notification_events.dart +++ b/lib/src/push_notifications/src/push_notification_events.dart @@ -21,7 +21,8 @@ abstract class PushNotificationEvents { /// notifications while the app is in the foreground, manually create one /// when a [onMessage] or [BackgroundMessageHandler] is called. void setOnShowNotificationInForeground( - Future Function(RemoteMessage message) callback); + Future Function(RemoteMessage message) callback, + ); /// A stream that emmits messages while the app is in the foreground. Stream get onMessage; diff --git a/lib/src/push_notifications/src/remote_message.dart b/lib/src/push_notifications/src/remote_message.dart index cb7e95f76..1b393b7cd 100644 --- a/lib/src/push_notifications/src/remote_message.dart +++ b/lib/src/push_notifications/src/remote_message.dart @@ -19,24 +19,23 @@ class RemoteMessage { /// @nodoc /// Initializes an instance with [data] set to empty map - RemoteMessage({ - Map? data, - this.notification, - }) : data = data ??= {}; + RemoteMessage({Map? data, this.notification}) + : data = data ??= {}; /// @nodoc /// Create instance from a map. factory RemoteMessage.fromMap(Map map) => RemoteMessage( - data: (map[TxRemoteMessage.data] == null) - ? {} - : Map.from( - map[TxRemoteMessage.data] as Map, - ), - notification: (map[TxRemoteMessage.notification] == null) - ? null - : Notification.fromMap( - Map.from( - map[TxRemoteMessage.notification] as Map), - ), - ); + data: (map[TxRemoteMessage.data] == null) + ? {} + : Map.from( + map[TxRemoteMessage.data] as Map, + ), + notification: (map[TxRemoteMessage.notification] == null) + ? null + : Notification.fromMap( + Map.from( + map[TxRemoteMessage.notification] as Map, + ), + ), + ); } diff --git a/lib/src/realtime/src/connection_state_change.dart b/lib/src/realtime/src/connection_state_change.dart index 06efd7b00..91a63ae5d 100644 --- a/lib/src/realtime/src/connection_state_change.dart +++ b/lib/src/realtime/src/connection_state_change.dart @@ -49,6 +49,9 @@ class EnrichedConnectionStateChange { final String? connectionKey; /// @nodoc - const EnrichedConnectionStateChange( - {required this.stateChange, this.connectionId, this.connectionKey}); + const EnrichedConnectionStateChange({ + required this.stateChange, + this.connectionId, + this.connectionKey, + }); } diff --git a/lib/src/realtime/src/realtime_auth.dart b/lib/src/realtime/src/realtime_auth.dart index c6366d27e..04fc5c5c9 100644 --- a/lib/src/realtime/src/realtime_auth.dart +++ b/lib/src/realtime/src/realtime_auth.dart @@ -9,33 +9,33 @@ class RealtimeAuth extends Auth { RealtimeAuth(this._realtime); @override - Future authorize( - {AuthOptions? authOptions, TokenParams? tokenParams}) => - _realtime.invokeRequest( - PlatformMethod.realtimeAuthAuthorize, { - TxTransportKeys.options: authOptions, - TxTransportKeys.params: tokenParams - }); + Future authorize({ + AuthOptions? authOptions, + TokenParams? tokenParams, + }) => _realtime.invokeRequest( + PlatformMethod.realtimeAuthAuthorize, + {TxTransportKeys.options: authOptions, TxTransportKeys.params: tokenParams}, + ); @override Future get clientId async => _realtime.invokeRequest(PlatformMethod.realtimeAuthGetClientId); @override - Future createTokenRequest( - {AuthOptions? authOptions, TokenParams? tokenParams}) => - _realtime.invokeRequest( - PlatformMethod.realtimeAuthCreateTokenRequest, { - TxTransportKeys.options: authOptions, - TxTransportKeys.params: tokenParams - }); + Future createTokenRequest({ + AuthOptions? authOptions, + TokenParams? tokenParams, + }) => _realtime.invokeRequest( + PlatformMethod.realtimeAuthCreateTokenRequest, + {TxTransportKeys.options: authOptions, TxTransportKeys.params: tokenParams}, + ); @override - Future requestToken( - {AuthOptions? authOptions, TokenParams? tokenParams}) => - _realtime.invokeRequest( - PlatformMethod.realtimeAuthRequestToken, { - TxTransportKeys.options: authOptions, - TxTransportKeys.params: tokenParams - }); + Future requestToken({ + AuthOptions? authOptions, + TokenParams? tokenParams, + }) => _realtime.invokeRequest( + PlatformMethod.realtimeAuthRequestToken, + {TxTransportKeys.options: authOptions, TxTransportKeys.params: tokenParams}, + ); } diff --git a/lib/src/realtime/src/realtime_channel_options.dart b/lib/src/realtime/src/realtime_channel_options.dart index db525c3aa..4848172c7 100644 --- a/lib/src/realtime/src/realtime_channel_options.dart +++ b/lib/src/realtime/src/realtime_channel_options.dart @@ -28,9 +28,5 @@ class RealtimeChannelOptions { /// If a [cipherParams] is set, messages will be encrypted with the cipher. /// /// https://docs.ably.com/client-lib-development-guide/features/#TB2 - const RealtimeChannelOptions({ - this.cipherParams, - this.modes, - this.params, - }); + const RealtimeChannelOptions({this.cipherParams, this.modes, this.params}); } diff --git a/lib/src/realtime/src/realtime_history_params.dart b/lib/src/realtime/src/realtime_history_params.dart index 7435e20c9..e8e743588 100644 --- a/lib/src/realtime/src/realtime_history_params.dart +++ b/lib/src/realtime/src/realtime_history_params.dart @@ -41,12 +41,13 @@ class RealtimeHistoryParams { this.limit = 100, DateTime? start, this.untilAttach, - }) : assert(direction == 'backwards' || direction == 'forwards'), - end = end ?? DateTime.now(), - start = start ?? DateTime.fromMillisecondsSinceEpoch(0); + }) : assert(direction == 'backwards' || direction == 'forwards'), + end = end ?? DateTime.now(), + start = start ?? DateTime.fromMillisecondsSinceEpoch(0); @override - String toString() => 'RealtimeHistoryParams:' + String toString() => + 'RealtimeHistoryParams:' ' start=$start' ' end=$end' ' direction=$direction' diff --git a/lib/src/rest/src/rest_auth.dart b/lib/src/rest/src/rest_auth.dart index d9d2897d1..88aae41ad 100644 --- a/lib/src/rest/src/rest_auth.dart +++ b/lib/src/rest/src/rest_auth.dart @@ -9,31 +9,33 @@ class RestAuth extends Auth { RestAuth(this._rest); @override - Future authorize( - {AuthOptions? authOptions, TokenParams? tokenParams}) => - _rest.invokeRequest(PlatformMethod.restAuthAuthorize, { - TxTransportKeys.options: authOptions, - TxTransportKeys.params: tokenParams - }); + Future authorize({ + AuthOptions? authOptions, + TokenParams? tokenParams, + }) => _rest.invokeRequest(PlatformMethod.restAuthAuthorize, { + TxTransportKeys.options: authOptions, + TxTransportKeys.params: tokenParams, + }); @override Future get clientId async => _rest.invoke(PlatformMethod.restAuthGetClientId); @override - Future createTokenRequest( - {AuthOptions? authOptions, TokenParams? tokenParams}) => - _rest.invokeRequest( - PlatformMethod.restAuthCreateTokenRequest, { - TxTransportKeys.options: authOptions, - TxTransportKeys.params: tokenParams - }); + Future createTokenRequest({ + AuthOptions? authOptions, + TokenParams? tokenParams, + }) => _rest.invokeRequest( + PlatformMethod.restAuthCreateTokenRequest, + {TxTransportKeys.options: authOptions, TxTransportKeys.params: tokenParams}, + ); @override - Future requestToken( - {AuthOptions? authOptions, TokenParams? tokenParams}) => - _rest.invokeRequest(PlatformMethod.restAuthRequestToken, { - TxTransportKeys.options: authOptions, - TxTransportKeys.params: tokenParams - }); + Future requestToken({ + AuthOptions? authOptions, + TokenParams? tokenParams, + }) => _rest.invokeRequest(PlatformMethod.restAuthRequestToken, { + TxTransportKeys.options: authOptions, + TxTransportKeys.params: tokenParams, + }); } diff --git a/lib/src/rest/src/rest_history_params.dart b/lib/src/rest/src/rest_history_params.dart index 51575895f..ecae09cf4 100644 --- a/lib/src/rest/src/rest_history_params.dart +++ b/lib/src/rest/src/rest_history_params.dart @@ -30,12 +30,13 @@ class RestHistoryParams { DateTime? end, this.limit = 100, DateTime? start, - }) : assert(direction == 'backwards' || direction == 'forwards'), - end = end ?? DateTime.now(), - start = start ?? DateTime.fromMillisecondsSinceEpoch(0); + }) : assert(direction == 'backwards' || direction == 'forwards'), + end = end ?? DateTime.now(), + start = start ?? DateTime.fromMillisecondsSinceEpoch(0); @override - String toString() => 'RestHistoryParams:' + String toString() => + 'RestHistoryParams:' ' start=$start' ' end=$end' ' direction=$direction' diff --git a/lib/src/rest/src/rest_presence_params.dart b/lib/src/rest/src/rest_presence_params.dart index 3c082ef0e..48bec7ab3 100644 --- a/lib/src/rest/src/rest_presence_params.dart +++ b/lib/src/rest/src/rest_presence_params.dart @@ -17,9 +17,5 @@ class RestPresenceParams { /// @nodoc /// initializes with default [limit] set to 100 - RestPresenceParams({ - this.clientId, - this.connectionId, - this.limit = 100, - }); + RestPresenceParams({this.clientId, this.connectionId, this.limit = 100}); } diff --git a/test/ably_event_listener_test.dart b/test/ably_event_listener_test.dart index 3f1fb0f25..b99898292 100644 --- a/test/ably_event_listener_test.dart +++ b/test/ably_event_listener_test.dart @@ -69,8 +69,9 @@ void main() { //Checking if data received by stream is same as expected expect( - const ListEquality().equals(resultsDefault, emitter.injectables), - true); + const ListEquality().equals(resultsDefault, emitter.injectables), + true, + ); expect(const ListEquality().equals(resultsNestedPre, [1, 2]), true); expect(const ListEquality().equals(resultsNestedPost, [1]), true); }); diff --git a/test/ably_flutter_plugin_test.dart b/test/ably_flutter_plugin_test.dart index 9fd9cc46d..3b9775469 100644 --- a/test/ably_flutter_plugin_test.dart +++ b/test/ably_flutter_plugin_test.dart @@ -4,8 +4,10 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - final channel = - MethodChannel('io.ably.flutter.plugin', StandardMethodCodec(Codec())); + final channel = MethodChannel( + 'io.ably.flutter.plugin', + StandardMethodCodec(Codec()), + ); TestWidgetsFlutterBinding.ensureInitialized(); var counter = 0; @@ -17,25 +19,25 @@ void main() { setUp(() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (methodCall) async { - switch (methodCall.method) { - case PlatformMethod.resetAblyClients: - return true; + switch (methodCall.method) { + case PlatformMethod.resetAblyClients: + return true; - case PlatformMethod.getPlatformVersion: - return _platformVersion; - case PlatformMethod.getVersion: - return _nativeLibraryVersion; + case PlatformMethod.getPlatformVersion: + return _platformVersion; + case PlatformMethod.getVersion: + return _nativeLibraryVersion; - case PlatformMethod.createRest: - case PlatformMethod.createRealtime: - return ++counter; + case PlatformMethod.createRest: + case PlatformMethod.createRealtime: + return ++counter; - case PlatformMethod.publish: - case PlatformMethod.connectRealtime: - default: - return null; - } - }); + case PlatformMethod.publish: + case PlatformMethod.connectRealtime: + default: + return null; + } + }); Platform(methodChannel: channel); }); @@ -54,9 +56,7 @@ void main() { test(PlatformMethod.createRest, () async { const host = 'http://rest.ably.io/'; - final o = ClientOptions( - restHost: host, - ); + final o = ClientOptions(restHost: host); final rest = Rest(options: o); expect(await rest.handle, counter); expect(rest.options.restHost, host); diff --git a/test/mock_method_call_manager.dart b/test/mock_method_call_manager.dart index 57860137b..f9165b4f2 100644 --- a/test/mock_method_call_manager.dart +++ b/test/mock_method_call_manager.dart @@ -12,8 +12,10 @@ class MockMethodCallManager { final publishedMessages = >[]; MockMethodCallManager() { - final channel = - MethodChannel('io.ably.flutter.plugin', StandardMethodCodec(Codec())); + final channel = MethodChannel( + 'io.ably.flutter.plugin', + StandardMethodCodec(Codec()), + ); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, handler); Platform(methodChannel: channel); @@ -23,8 +25,10 @@ class MockMethodCallManager { channels.clear(); publishedMessages.clear(); handleCounter = 0; - final channel = - MethodChannel('io.ably.flutter.plugin', StandardMethodCodec(Codec())); + final channel = MethodChannel( + 'io.ably.flutter.plugin', + StandardMethodCodec(Codec()), + ); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, handler); Platform(methodChannel: channel); @@ -54,7 +58,9 @@ class MockMethodCallManager { // PlatformChannel. if (!isAuthenticated && clientOptions.authUrl == 'hasAuthCallback') { final channel = MethodChannel( - 'io.ably.flutter.plugin', StandardMethodCodec(Codec())); + 'io.ably.flutter.plugin', + StandardMethodCodec(Codec()), + ); await AblyMethodCallHandler(channel).onAuthCallback( AblyMessage( message: TokenParams(timestamp: DateTime.now()), @@ -75,12 +81,12 @@ class MockMethodCallManager { // PlatformChannel. if (!isAuthenticated && clientOptions.authUrl == 'hasAuthCallback') { final channel = MethodChannel( - 'io.ably.flutter.plugin', StandardMethodCodec(Codec())); + 'io.ably.flutter.plugin', + StandardMethodCodec(Codec()), + ); await AblyMethodCallHandler(channel).onRealtimeAuthCallback( AblyMessage( - message: TokenParams( - timestamp: DateTime.now(), - ), + message: TokenParams(timestamp: DateTime.now()), handle: ablyMessage.handle, ), ); @@ -95,8 +101,10 @@ class MockMethodCallManager { return null; default: - return throw Exception('Unexpected method call: ${methodCall.method}' - ' args: ${methodCall.arguments}'); + return throw Exception( + 'Unexpected method call: ${methodCall.method}' + ' args: ${methodCall.arguments}', + ); } } } diff --git a/test/models/message_test.dart b/test/models/message_test.dart index 2e683e911..9b9b54ff3 100644 --- a/test/models/message_test.dart +++ b/test/models/message_test.dart @@ -8,12 +8,12 @@ void main() { const connectionId = 'connection-id'; const data = { 'a': 'b', - 'c': [1, 2, 3] + 'c': [1, 2, 3], }; const encoding = 'msgpack'; const extras = { 'a': 'b', - 'c': [1, 2, 3] + 'c': [1, 2, 3], }; final timestamp = DateTime.now(); @@ -77,21 +77,23 @@ void main() { expect(message.hashCode == message2.hashCode, true); }); - test("#== is false and hashes don't match when attributes are not same", - () { - final message2 = Message( - id: messageId, - name: 'other-name', - clientId: clientId, - connectionId: connectionId, - data: data, - encoding: encoding, - extras: const MessageExtras(extras), - timestamp: timestamp, - ); - expect(message == message2, false); - expect(message.hashCode == message2.hashCode, false); - }); + test( + "#== is false and hashes don't match when attributes are not same", + () { + final message2 = Message( + id: messageId, + name: 'other-name', + clientId: clientId, + connectionId: connectionId, + data: data, + encoding: encoding, + extras: const MessageExtras(extras), + timestamp: timestamp, + ); + expect(message == message2, false); + expect(message.hashCode == message2.hashCode, false); + }, + ); test("#== is false and hashes don't match for different classes", () { final object = Object(); @@ -139,7 +141,7 @@ void main() { 'encoding': encoding, 'extras': extras, 'timestamp': timestamp.millisecondsSinceEpoch, - } + }, ]); final message = messages[0]; expect(message.id, messageId); @@ -167,8 +169,9 @@ void main() { expect(message.extras, null); }); test('a map of extras is allowed', () { - final message = - Message(extras: const MessageExtras({'key': 'value'})); + final message = Message( + extras: const MessageExtras({'key': 'value'}), + ); expect(message.extras!.map, const {'key': 'value'}); }); }); diff --git a/test/models/presence_message_test.dart b/test/models/presence_message_test.dart index 9c1fccf76..db4a0fa7d 100644 --- a/test/models/presence_message_test.dart +++ b/test/models/presence_message_test.dart @@ -9,12 +9,12 @@ void main() { const connectionId = 'connection-id'; const data = { 'a': 'b', - 'c': [1, 2, 3] + 'c': [1, 2, 3], }; const encoding = 'msgpack'; const extras = { 'a': 'b', - 'c': [1, 2, 3] + 'c': [1, 2, 3], }; final timestamp = DateTime.now(); group('Behaves like a model', () { @@ -68,21 +68,23 @@ void main() { expect(presenceMessage.hashCode == presenceMessage2.hashCode, true); }); - test("#== is false and hashes don't match when attributes are not same", - () { - final presenceMessage2 = PresenceMessage( - id: '123', - action: action, - clientId: clientId, - connectionId: connectionId, - data: data, - encoding: encoding, - extras: const MessageExtras(extras), - timestamp: timestamp, - ); - expect(presenceMessage == presenceMessage2, false); - expect(presenceMessage.hashCode == presenceMessage2.hashCode, false); - }); + test( + "#== is false and hashes don't match when attributes are not same", + () { + final presenceMessage2 = PresenceMessage( + id: '123', + action: action, + clientId: clientId, + connectionId: connectionId, + data: data, + encoding: encoding, + extras: const MessageExtras(extras), + timestamp: timestamp, + ); + expect(presenceMessage == presenceMessage2, false); + expect(presenceMessage.hashCode == presenceMessage2.hashCode, false); + }, + ); test("#== is false and hashes don't match for different classes", () { final object = Object(); @@ -93,22 +95,32 @@ void main() { group('memberKey attribute', () { test('is connectionId:clientId', () { - final presenceMessage = - PresenceMessage(clientId: clientId, connectionId: connectionId); + final presenceMessage = PresenceMessage( + clientId: clientId, + connectionId: connectionId, + ); expect(presenceMessage.memberKey, '$connectionId:$clientId'); }); test('is unique with the same client id across multiple connections', () { - final presenceMessage = - PresenceMessage(clientId: clientId, connectionId: connectionId); - final presenceMessage2 = - PresenceMessage(clientId: clientId, connectionId: 'different'); + final presenceMessage = PresenceMessage( + clientId: clientId, + connectionId: connectionId, + ); + final presenceMessage2 = PresenceMessage( + clientId: clientId, + connectionId: 'different', + ); expect(presenceMessage.memberKey == presenceMessage2.memberKey, false); }); test('is unique with a single connection and different client_ids', () { - final presenceMessage = - PresenceMessage(clientId: clientId, connectionId: connectionId); - final presenceMessage2 = - PresenceMessage(clientId: 'different', connectionId: connectionId); + final presenceMessage = PresenceMessage( + clientId: clientId, + connectionId: connectionId, + ); + final presenceMessage2 = PresenceMessage( + clientId: 'different', + connectionId: connectionId, + ); expect(presenceMessage.memberKey == presenceMessage2.memberKey, false); }); }); @@ -123,7 +135,7 @@ void main() { 'data': data, 'encoding': encoding, 'extras': extras, - 'timestamp': timestamp.millisecondsSinceEpoch + 'timestamp': timestamp.millisecondsSinceEpoch, }); expect(presenceMessage.id, messageId); expect(presenceMessage.action, action); @@ -151,7 +163,7 @@ void main() { 'encoding': encoding, 'extras': extras, 'timestamp': timestamp.millisecondsSinceEpoch, - } + }, ]); final presenceMessage = presenceMessages[0]; expect(presenceMessage.id, messageId); diff --git a/test/realtime/channel_test.dart b/test/realtime/channel_test.dart index 23c1844e8..08c3da772 100644 --- a/test/realtime/channel_test.dart +++ b/test/realtime/channel_test.dart @@ -25,8 +25,12 @@ void main() { // exercise await channel.publish(name: 'name', data: 'data1'); - await channel.publish(message: Message(name: 'name', data: 'data')); - await channel.publish(messages: [Message(name: 'name', data: 'data')]); + await channel.publish( + message: Message(name: 'name', data: 'data'), + ); + await channel.publish( + messages: [Message(name: 'name', data: 'data')], + ); // verification expect(manager.publishedMessages.length, 3); @@ -34,8 +38,9 @@ void main() { final messageData = firstMessage.message as Map; expect(messageData[TxTransportKeys.channelName], 'test'); expect(messageData[TxTransportKeys.messages], isA>()); - final messages = - List.from(messageData[TxTransportKeys.messages] as List); + final messages = List.from( + messageData[TxTransportKeys.messages] as List, + ); expect(messages[0].name, 'name'); expect(messages[0].data, 'data1'); }); @@ -62,8 +67,9 @@ void main() { final messageData = firstMessage.message as Map; expect(messageData[TxTransportKeys.channelName], 'test'); expect(messageData[TxTransportKeys.messages], isA>()); - final messages = - List.from(messageData[TxTransportKeys.messages] as List); + final messages = List.from( + messageData[TxTransportKeys.messages] as List, + ); expect(messages[0].name, 'name'); expect(messages[0].data, 'data2'); }); @@ -97,8 +103,9 @@ void main() { final messageData = firstMessage.message as Map; expect(messageData[TxTransportKeys.channelName], 'test'); expect(messageData[TxTransportKeys.messages], isA>()); - final messages = - List.from(messageData[TxTransportKeys.messages] as List); + final messages = List.from( + messageData[TxTransportKeys.messages] as List, + ); expect(messages[0].name, 'name'); expect(messages[0].data, 'data3-1'); }); @@ -124,8 +131,9 @@ void main() { final messageData0 = message0.message as Map; expect(messageData0[TxTransportKeys.channelName], 'test'); expect(messageData0[TxTransportKeys.messages], isA>()); - final messages = - List.from(messageData0[TxTransportKeys.messages] as List); + final messages = List.from( + messageData0[TxTransportKeys.messages] as List, + ); expect(messages[0].name, 'name'); expect(messages[0].data, 'data4'); @@ -133,8 +141,9 @@ void main() { final messageData1 = message1.message as Map; expect(messageData1[TxTransportKeys.channelName], 'test'); expect(messageData1[TxTransportKeys.messages], isA>()); - final messages1 = - List.from(messageData1[TxTransportKeys.messages] as List); + final messages1 = List.from( + messageData1[TxTransportKeys.messages] as List, + ); expect(messages1[0].name, 'name'); expect(messages1[0].data, 'data5'); }, timeout: Timeout.none); diff --git a/test/rest/channel_test.dart b/test/rest/channel_test.dart index 01a00ead1..a6b5f76be 100644 --- a/test/rest/channel_test.dart +++ b/test/rest/channel_test.dart @@ -32,8 +32,9 @@ void main() { final messageData = firstMessage.message as Map; expect(messageData[TxTransportKeys.channelName], 'test'); expect(messageData[TxTransportKeys.messages], isA>()); - final messages = - List.from(messageData[TxTransportKeys.messages] as List); + final messages = List.from( + messageData[TxTransportKeys.messages] as List, + ); expect(messages[0].name, 'name'); expect(messages[0].data, 'data1'); }); @@ -59,8 +60,9 @@ void main() { final messageData = firstMessage.message as Map; expect(messageData[TxTransportKeys.channelName], 'test'); expect(messageData[TxTransportKeys.messages], isA>()); - final messages = - List.from(messageData[TxTransportKeys.messages] as List); + final messages = List.from( + messageData[TxTransportKeys.messages] as List, + ); expect(messages[0].name, 'name'); expect(messages[0].data, 'data2'); }); @@ -95,8 +97,9 @@ void main() { final messageData = firstMessage.message as Map; expect(messageData[TxTransportKeys.channelName], 'test'); expect(messageData[TxTransportKeys.messages], isA>()); - final messages = - List.from(messageData[TxTransportKeys.messages] as List); + final messages = List.from( + messageData[TxTransportKeys.messages] as List, + ); expect(messages[0].name, 'name'); expect(messages[0].data, 'data3-1'); }); @@ -122,8 +125,9 @@ void main() { final messageData0 = message0.message as Map; expect(messageData0[TxTransportKeys.channelName], 'test'); expect(messageData0[TxTransportKeys.messages], isA>()); - final messages = - List.from(messageData0[TxTransportKeys.messages] as List); + final messages = List.from( + messageData0[TxTransportKeys.messages] as List, + ); expect(messages[0].name, 'name'); expect(messages[0].data, 'data4'); @@ -131,8 +135,9 @@ void main() { final messageData1 = message1.message as Map; expect(messageData1[TxTransportKeys.channelName], 'test'); expect(messageData1[TxTransportKeys.messages], isA>()); - final messages2 = - List.from(messageData1[TxTransportKeys.messages] as List); + final messages2 = List.from( + messageData1[TxTransportKeys.messages] as List, + ); expect(messages2[0].name, 'name'); expect(messages2[0].data, 'data5'); }, timeout: Timeout.none); diff --git a/test/rest/channels_test.dart b/test/rest/channels_test.dart index fa3c16d1d..e1a15bdf2 100644 --- a/test/rest/channels_test.dart +++ b/test/rest/channels_test.dart @@ -64,10 +64,7 @@ void main() { expect( channels.where((e) => e.name.endsWith('3')).map((e) => e.name).toList(), - orderedEquals(const [ - 'channel-3', - 'channel-33', - ]), + orderedEquals(const ['channel-3', 'channel-33']), ); }); @@ -86,8 +83,7 @@ void main() { }); group('#release', () { - test( - '(RSN4a) Takes one argument, the channel name,' + test('(RSN4a) Takes one argument, the channel name,' ' and releases the corresponding channel entity', () { channels ..get('channel-1') @@ -98,8 +94,7 @@ void main() { expect(channels.exists('channel-1'), false); }); - test( - '(RSN4b) Calling release() with a channel name' + test('(RSN4b) Calling release() with a channel name' ' that does not correspond to an extant channel' ' entity must return without error', () { channels diff --git a/test_integration/lib/app_provisioning.dart b/test_integration/lib/app_provisioning.dart index 652ccfb12..f47e0712c 100644 --- a/test_integration/lib/app_provisioning.dart +++ b/test_integration/lib/app_provisioning.dart @@ -66,30 +66,27 @@ class AppProvisioning { /// A set of base headers for HTTP requests Map get _requestHeaders => { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - }; + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; /// App spec used to provision the app /// /// See: https://docs.ably.com/client-lib-development-guide/test-api Map> get _appSpec => { - 'namespaces': [ - { - 'id': 'pushenabled', - 'pushEnabled': pushEnabled, - } - ], - 'keys': [ - { - // The need to use jsonEncode here is a requirement of the - // Sandbox Test API. The capability map has to be JSON encoded - // as a string and then appropriately escaped in order for - // presentation within a string value. - 'capability': jsonEncode(keyCapabilities), - }, - ], - }; + 'namespaces': [ + {'id': 'pushenabled', 'pushEnabled': pushEnabled}, + ], + 'keys': [ + { + // The need to use jsonEncode here is a requirement of the + // Sandbox Test API. The capability map has to be JSON encoded + // as a string and then appropriately escaped in order for + // presentation within a string value. + 'capability': jsonEncode(keyCapabilities), + }, + ], + }; /// Makes request to configured Ably provisioning URL and returns a /// new key for test application instance @@ -102,8 +99,10 @@ class AppProvisioning { if (response.statusCode != HttpStatus.created) { log("Server didn't return success. ${response.body}"); - throw HttpException("Server didn't return success." - ' Status: ${response.statusCode} : ${response.body}'); + throw HttpException( + "Server didn't return success." + ' Status: ${response.statusCode} : ${response.body}', + ); } final responseBody = jsonDecode(response.body) as Map; @@ -121,8 +120,10 @@ class AppProvisioning { if (response.statusCode != HttpStatus.ok) { log("Server didn't return success. ${response.body}"); - throw HttpException("Server didn't return success." - ' Status: ${response.statusCode} : ${response.body}'); + throw HttpException( + "Server didn't return success." + ' Status: ${response.statusCode} : ${response.body}', + ); } return Map.castFrom( diff --git a/test_integration/lib/config/test_factory.dart b/test_integration/lib/config/test_factory.dart index d86dc8bba..a38b1e2a5 100644 --- a/test_integration/lib/config/test_factory.dart +++ b/test_integration/lib/config/test_factory.dart @@ -36,10 +36,11 @@ import 'package:ably_flutter_integration_test/test/rest/rest_publish_with_auth_c import 'package:ably_flutter_integration_test/test/rest/rest_request_token_test.dart'; import 'package:ably_flutter_integration_test/test/rest/rest_time_test.dart'; -typedef TestFactory = Future> Function({ - required Reporter reporter, - Map? payload, -}); +typedef TestFactory = + Future> Function({ + required Reporter reporter, + Map? payload, + }); final testFactory = { // platform and app key tests diff --git a/test_integration/lib/driver_data_handler.dart b/test_integration/lib/driver_data_handler.dart index 6f4d14830..0943c8e6d 100644 --- a/test_integration/lib/driver_data_handler.dart +++ b/test_integration/lib/driver_data_handler.dart @@ -17,10 +17,7 @@ Future requestDataForTest( /// Used to encode and decode messages between driver test and test widget. class TestControlMessage { - const TestControlMessage( - this.testName, { - this.payload, - }); + const TestControlMessage(this.testName, {this.payload}); static const testNameKey = 'testName'; static const payloadKey = 'payload'; @@ -39,10 +36,7 @@ class TestControlMessage { payload: jsonValue[payloadKey] as Map?, ); - Map toJson() => { - testNameKey: testName, - payloadKey: payload, - }; + Map toJson() => {testNameKey: testName, payloadKey: payload}; String toJsonEncoded() => json.encode(toJson()); @@ -79,10 +73,10 @@ class TestControlResponseMessage { ); Map toJson() => { - testNameKey: testName, - payloadKey: payload, - logKey: log, - }; + testNameKey: testName, + payloadKey: payload, + logKey: log, + }; String toJsonEncoded() => json.encode(toJson()); diff --git a/test_integration/lib/factory/error_handler.dart b/test_integration/lib/factory/error_handler.dart index 73494efe1..b39a7dfe8 100644 --- a/test_integration/lib/factory/error_handler.dart +++ b/test_integration/lib/factory/error_handler.dart @@ -4,9 +4,11 @@ import 'package:flutter/foundation.dart'; /// to the test driver. class ErrorHandler { static Map encodeFlutterError(FlutterErrorDetails details) { - print('Caught FlutterError::\n' - 'exception: ${details.exception}\n' - 'stack: ${details.stack}'); + print( + 'Caught FlutterError::\n' + 'exception: ${details.exception}\n' + 'stack: ${details.stack}', + ); return { 'exceptionType': '${details.exception.runtimeType}', @@ -20,9 +22,11 @@ class ErrorHandler { static Map encodeException(Object error, StackTrace stack) { print(error); print(stack); - print('Caught Exception::\n' - 'error: $error\n' - 'stack: $stack'); + print( + 'Caught Exception::\n' + 'error: $error\n' + 'stack: $stack', + ); return { 'exceptionType': '${error.runtimeType}', diff --git a/test_integration/lib/factory/reporter.dart b/test_integration/lib/factory/reporter.dart index 112eb513d..469ff12ef 100644 --- a/test_integration/lib/factory/reporter.dart +++ b/test_integration/lib/factory/reporter.dart @@ -8,10 +8,8 @@ class Reporter { final DispatcherController controller; final Completer response; - Reporter( - this.message, - this.controller, - ) : response = Completer(); + Reporter(this.message, this.controller) + : response = Completer(); String get testName => message.testName; diff --git a/test_integration/lib/test/basic_test.dart b/test_integration/lib/test/basic_test.dart index e34593744..22c4a69a8 100644 --- a/test_integration/lib/test/basic_test.dart +++ b/test_integration/lib/test/basic_test.dart @@ -21,8 +21,5 @@ Future> testPlatformAndAblyVersion({ final _platformVersion = await platformVersion(); final _ablyVersion = await version(); - return { - 'platformVersion': _platformVersion, - 'ablyVersion': _ablyVersion, - }; + return {'platformVersion': _platformVersion, 'ablyVersion': _ablyVersion}; } diff --git a/test_integration/lib/test/crypto/crypto_ensure_supported_key_length_test.dart b/test_integration/lib/test/crypto/crypto_ensure_supported_key_length_test.dart index df168a881..1309871ea 100644 --- a/test_integration/lib/test/crypto/crypto_ensure_supported_key_length_test.dart +++ b/test_integration/lib/test/crypto/crypto_ensure_supported_key_length_test.dart @@ -36,8 +36,9 @@ Future> testCryptoEnsureSupportedKeyLength({ } try { - final keyWith127BitLength = - Uint8List.fromList(List.generate(127, (index) => index)); + final keyWith127BitLength = Uint8List.fromList( + List.generate(127, (index) => index), + ); Crypto.ensureSupportedKeyLength(keyWith127BitLength); } on AblyException catch (exception) { keyWith127BitLengthException = encodeAblyException(exception); diff --git a/test_integration/lib/test/crypto/crypto_get_default_params.dart b/test_integration/lib/test/crypto/crypto_get_default_params.dart index 8f116537c..e582646a0 100644 --- a/test_integration/lib/test/crypto/crypto_get_default_params.dart +++ b/test_integration/lib/test/crypto/crypto_get_default_params.dart @@ -13,8 +13,9 @@ Future> testCryptoGetDefaultParams({ final keyWithDefaultLength = await Crypto.generateRandomKey(); - final keyWith127BitLength = - Uint8List.fromList(List.generate(127, (index) => index)); + final keyWith127BitLength = Uint8List.fromList( + List.generate(127, (index) => index), + ); try { await Crypto.getDefaultParams(key: keyWith127BitLength); diff --git a/test_integration/lib/test/realtime/realtime_auth_client_id_test.dart b/test_integration/lib/test/realtime/realtime_auth_client_id_test.dart index 9575bc6d4..4e23a235b 100644 --- a/test_integration/lib/test/realtime/realtime_auth_client_id_test.dart +++ b/test_integration/lib/test/realtime/realtime_auth_client_id_test.dart @@ -16,19 +16,18 @@ Future> testRealtimeAuthClientId({ logLevel: LogLevel.error, ); - final ablyForToken = Rest( - options: clientOptionsForToken, - ); + final ablyForToken = Rest(options: clientOptionsForToken); /* get first token */ final firstToken = await ablyForToken.auth.requestToken(); final clientOptions = ClientOptions( - key: appKey, - environment: 'sandbox', - useTokenAuth: true, - autoConnect: false, - clientId: 'testClientId', - tokenDetails: firstToken); + key: appKey, + environment: 'sandbox', + useTokenAuth: true, + autoConnect: false, + clientId: 'testClientId', + tokenDetails: firstToken, + ); final realtime = Realtime(options: clientOptions); await realtime.connect(); diff --git a/test_integration/lib/test/realtime/realtime_auth_url_test.dart b/test_integration/lib/test/realtime/realtime_auth_url_test.dart index cea621364..2c55515ce 100644 --- a/test_integration/lib/test/realtime/realtime_auth_url_test.dart +++ b/test_integration/lib/test/realtime/realtime_auth_url_test.dart @@ -20,19 +20,18 @@ Future> testCreateRealtimeWithAuthUrl({ fallbackHosts: ['a.ably-realtime.com', 'b.ably-realtime.com'], ); - final ablyForToken = Rest( - options: clientOptionsForToken, - ); + final ablyForToken = Rest(options: clientOptionsForToken); final tokenDetails = await ablyForToken.auth.requestToken(); final authUrl = 'https://echo.ably.io/?body=${Uri.encodeComponent(tokenDetails.token!)}'; final options = ClientOptions( - authUrl: authUrl, - environment: 'sandbox', - useTokenAuth: true, - autoConnect: false, - logLevel: LogLevel.error); + authUrl: authUrl, + environment: 'sandbox', + useTokenAuth: true, + autoConnect: false, + logLevel: LogLevel.error, + ); final realtime = Realtime(options: options); final completer = Completer(); realtime.connection.on().listen((stateChange) { @@ -45,8 +44,10 @@ Future> testCreateRealtimeWithAuthUrl({ throw Error(); } - await completer.future - .timeout(const Duration(seconds: 30), onTimeout: _onTimeout); + await completer.future.timeout( + const Duration(seconds: 30), + onTimeout: _onTimeout, + ); return {'handle': await realtime.handle}; } diff --git a/test_integration/lib/test/realtime/realtime_authorize_test.dart b/test_integration/lib/test/realtime/realtime_authorize_test.dart index c7497c16c..f152833e7 100644 --- a/test_integration/lib/test/realtime/realtime_authorize_test.dart +++ b/test_integration/lib/test/realtime/realtime_authorize_test.dart @@ -16,32 +16,33 @@ Future> testRealtimeAuthroize({ logLevel: LogLevel.error, ); - final ablyForToken = Rest( - options: clientOptionsForToken, - ); + final ablyForToken = Rest(options: clientOptionsForToken); /* get first token */ final firstToken = await ablyForToken.auth.requestToken(); final clientOptions = ClientOptions( - key: appKey, - environment: 'sandbox', - useTokenAuth: true, - autoConnect: false, - tokenDetails: firstToken); + key: appKey, + environment: 'sandbox', + useTokenAuth: true, + autoConnect: false, + tokenDetails: firstToken, + ); final realtime = Realtime(options: clientOptions); await realtime.connect(); const tokenParams = TokenParams(ttl: 20000); - Future authCallback(params) async => TokenRequest.fromMap( - await AppProvisioning().getTokenRequest(), - ); + Future authCallback(params) async => + TokenRequest.fromMap(await AppProvisioning().getTokenRequest()); final authOptions = AuthOptions( - key: appKey, - useTokenAuth: true, - authCallback: authCallback, - authMethod: 'GET'); - final refreshedToken = await realtime.auth - .authorize(authOptions: authOptions, tokenParams: tokenParams); + key: appKey, + useTokenAuth: true, + authCallback: authCallback, + authMethod: 'GET', + ); + final refreshedToken = await realtime.auth.authorize( + authOptions: authOptions, + tokenParams: tokenParams, + ); //tokens must be different if (refreshedToken == firstToken) { throw Error(); diff --git a/test_integration/lib/test/realtime/realtime_encrypted_publish_test.dart b/test_integration/lib/test/realtime/realtime_encrypted_publish_test.dart index dee384131..d8c800414 100644 --- a/test_integration/lib/test/realtime/realtime_encrypted_publish_test.dart +++ b/test_integration/lib/test/realtime/realtime_encrypted_publish_test.dart @@ -12,8 +12,9 @@ Future> testRealtimeEncryptedPublish({ reporter.reportLog('init start'); final appKey = await AppProvisioning().provisionApp(); - final cipherParams = - await Crypto.getDefaultParams(key: TestConstants.encryptedChannelKey); + final cipherParams = await Crypto.getDefaultParams( + key: TestConstants.encryptedChannelKey, + ); final channelOptions = RealtimeChannelOptions(cipherParams: cipherParams); @@ -29,9 +30,7 @@ Future> testRealtimeEncryptedPublish({ await channel.setOptions(channelOptions); await publishMessages(channel); - return { - 'handle': await realtime.handle, - }; + return {'handle': await realtime.handle}; } Future> testRealtimeEncryptedPublishSpec({ @@ -41,8 +40,9 @@ Future> testRealtimeEncryptedPublishSpec({ const clientId = 'clientId'; final appKey = await AppProvisioning().provisionApp(); - final cipherParams = - await Crypto.getDefaultParams(key: TestConstants.encryptedChannelKey); + final cipherParams = await Crypto.getDefaultParams( + key: TestConstants.encryptedChannelKey, + ); final channelOptions = RealtimeChannelOptions(cipherParams: cipherParams); @@ -69,18 +69,17 @@ Future> testRealtimeEncryptedPublishSpec({ // Send single message object await encryptedChannel.publish( - message: Message( - name: 'single-message-name', - data: 'single-message-data', - ), + message: Message(name: 'single-message-name', data: 'single-message-data'), ); await Future.delayed(TestConstants.publishToHistoryDelay); // Send multiple message objects at once - await encryptedChannel.publish(messages: [ - Message(name: 'multi-message-name-1', data: 'multi-message-data-1'), - Message(name: 'multi-message-name-2', data: 'multi-message-data-2'), - ]); + await encryptedChannel.publish( + messages: [ + Message(name: 'multi-message-name-1', data: 'multi-message-data-1'), + Message(name: 'multi-message-name-2', data: 'multi-message-data-2'), + ], + ); await Future.delayed(TestConstants.publishToHistoryDelay); // Send message with [clientId] defined @@ -100,8 +99,9 @@ Future> testRealtimeEncryptedPublishSpec({ ); // Create encrypted channel with push capability - final encryptedPushEnabledChannel = - realtimeWithClientId.channels.get('pushenabled:test:extras'); + final encryptedPushEnabledChannel = realtimeWithClientId.channels.get( + 'pushenabled:test:extras', + ); await encryptedPushEnabledChannel.setOptions(channelOptions); // Send message with extras to encrypted push-enabled channel @@ -114,8 +114,9 @@ Future> testRealtimeEncryptedPublishSpec({ ); // Retrieve history of push-enabled channels - final historyOfEncryptedPushEnabledChannel = - await getHistory(encryptedPushEnabledChannel); + final historyOfEncryptedPushEnabledChannel = await getHistory( + encryptedPushEnabledChannel, + ); // Retreive plaintext history of encrypted channel await encryptedChannel.setOptions(const RealtimeChannelOptions()); @@ -124,8 +125,9 @@ Future> testRealtimeEncryptedPublishSpec({ RealtimeHistoryParams(direction: 'forwards'), ); await encryptedPushEnabledChannel.setOptions(const RealtimeChannelOptions()); - final historyOfPlaintextPushEnabledChannel = - await getHistory(encryptedPushEnabledChannel); + final historyOfPlaintextPushEnabledChannel = await getHistory( + encryptedPushEnabledChannel, + ); return { 'handle': await realtimeWithClientId.handle, diff --git a/test_integration/lib/test/realtime/realtime_events_test.dart b/test_integration/lib/test/realtime/realtime_events_test.dart index c98921adb..f596c46f8 100644 --- a/test_integration/lib/test/realtime/realtime_events_test.dart +++ b/test_integration/lib/test/realtime/realtime_events_test.dart @@ -31,11 +31,14 @@ Future> testRealtimeEvents({ connectionStates.add(enumValueToString(realtime.connection.state)); recordConnectionState(); //connection: initialized + realtime.connection.on().listen( + (e) => connectionStateChanges.add(encodeConnectionEvent(e)), + ); realtime.connection - .on() - .listen((e) => connectionStateChanges.add(encodeConnectionEvent(e))); - realtime.connection.on(ConnectionEvent.connected).listen( - (e) => filteredConnectionStateChanges.add(encodeConnectionEvent(e))); + .on(ConnectionEvent.connected) + .listen( + (e) => filteredConnectionStateChanges.add(encodeConnectionEvent(e)), + ); reporter.reportLog({'before realtime.connect': ''}); recordConnectionState(); //connection: initialized diff --git a/test_integration/lib/test/realtime/realtime_history_with_auth_callback_test.dart b/test_integration/lib/test/realtime/realtime_history_with_auth_callback_test.dart index 4bfe35013..c2af805f8 100644 --- a/test_integration/lib/test/realtime/realtime_history_with_auth_callback_test.dart +++ b/test_integration/lib/test/realtime/realtime_history_with_auth_callback_test.dart @@ -16,9 +16,7 @@ Future> testRealtimeHistoryWithAuthCallback({ logLevel: LogLevel.error, authCallback: (params) async { authCallbackInvoked = true; - return TokenRequest.fromMap( - await AppProvisioning().getTokenRequest(), - ); + return TokenRequest.fromMap(await AppProvisioning().getTokenRequest()); }, ), ); diff --git a/test_integration/lib/test/realtime/realtime_presence_enter_update_leave.dart b/test_integration/lib/test/realtime/realtime_presence_enter_update_leave.dart index 94b8699cf..4034f24a4 100644 --- a/test_integration/lib/test/realtime/realtime_presence_enter_update_leave.dart +++ b/test_integration/lib/test/realtime/realtime_presence_enter_update_leave.dart @@ -9,13 +9,12 @@ final logMessages = >[]; ClientOptions getClientOptions( String appKey, [ String? clientId = 'someClientId', -]) => - ClientOptions( - key: appKey, - environment: 'sandbox', - clientId: clientId, - logLevel: LogLevel.error, - ); +]) => ClientOptions( + key: appKey, + environment: 'sandbox', + clientId: clientId, + logLevel: LogLevel.error, +); Future> testRealtimePresenceEnterUpdateLeave({ required Reporter reporter, @@ -27,10 +26,9 @@ Future> testRealtimePresenceEnterUpdateLeave({ final clientIds = [null, 'client-1', 'client-2']; final clientIDClashMatrix = >[]; for (final clientId in clientIds) { - final presence = Realtime(options: getClientOptions(appKey, clientId)) - .channels - .get('test') - .presence; + final presence = Realtime( + options: getClientOptions(appKey, clientId), + ).channels.get('test').presence; for (final clientId2 in clientIds) { final result = { 'realtimeClientId': clientId, @@ -102,11 +100,9 @@ Future> testRealtimePresenceEnterUpdateLeave({ // Interact with different types of data. final actionMatrix = >[]; - final realtimePresence = - Realtime(options: getClientOptions(appKey, 'test-client')) - .channels - .get('test') - .presence; + final realtimePresence = Realtime( + options: getClientOptions(appKey, 'test-client'), + ).channels.get('test').presence; for (final message in messagesToPublish) { final action = {'data': message}; try { diff --git a/test_integration/lib/test/realtime/realtime_presence_get.dart b/test_integration/lib/test/realtime/realtime_presence_get.dart index 95adb8cd7..2dba0b88f 100644 --- a/test_integration/lib/test/realtime/realtime_presence_get.dart +++ b/test_integration/lib/test/realtime/realtime_presence_get.dart @@ -10,13 +10,12 @@ final logMessages = >[]; ClientOptions getClientOptions( String appKey, [ String clientId = 'someClientId', -]) => - ClientOptions( - key: appKey, - environment: 'sandbox', - clientId: clientId, - logLevel: LogLevel.error, - ); +]) => ClientOptions( + key: appKey, + environment: 'sandbox', + clientId: clientId, + logLevel: LogLevel.error, +); Future> testRealtimePresenceGet({ required Reporter reporter, diff --git a/test_integration/lib/test/realtime/realtime_presence_subscribe.dart b/test_integration/lib/test/realtime/realtime_presence_subscribe.dart index c8842bffa..b5a4e1c03 100644 --- a/test_integration/lib/test/realtime/realtime_presence_subscribe.dart +++ b/test_integration/lib/test/realtime/realtime_presence_subscribe.dart @@ -36,14 +36,14 @@ Future> testRealtimePresenceSubscribe({ .listen(enterMessages.add); final enterUpdateMessages = []; - final enterUpdateMessagesSubscription = presence.subscribe(actions: [ - PresenceAction.enter, - PresenceAction.update - ]).listen(enterUpdateMessages.add); + final enterUpdateMessagesSubscription = presence + .subscribe(actions: [PresenceAction.enter, PresenceAction.update]) + .listen(enterUpdateMessages.add); final partialMessages = []; - final partialMessagesSubscription = - presence.subscribe().listen(partialMessages.add); + final partialMessagesSubscription = presence.subscribe().listen( + partialMessages.add, + ); // enter-update-leave sequence with different data types to check if // data received by listeners is intact diff --git a/test_integration/lib/test/realtime/realtime_publish_test.dart b/test_integration/lib/test/realtime/realtime_publish_test.dart index 14ed51ea7..a9ca7f873 100644 --- a/test_integration/lib/test/realtime/realtime_publish_test.dart +++ b/test_integration/lib/test/realtime/realtime_publish_test.dart @@ -23,10 +23,7 @@ Future> testRealtimePublish({ ); await publishMessages(realtime.channels.get('test')); await realtime.close(); - return { - 'handle': await realtime.handle, - 'log': logMessages, - }; + return {'handle': await realtime.handle, 'log': logMessages}; } Future> testRealtimePublishSpec({ @@ -53,10 +50,12 @@ Future> testRealtimePublishSpec({ message: Message(name: 'message-name1', data: 'message-data1'), ); await Future.delayed(TestConstants.publishToHistoryDelay); - await channel.publish(messages: [ - Message(name: 'messages-name1', data: 'messages-data1'), - Message(name: 'messages-name2', data: 'messages-data2'), - ]); + await channel.publish( + messages: [ + Message(name: 'messages-name1', data: 'messages-data1'), + Message(name: 'messages-name2', data: 'messages-data2'), + ], + ); await Future.delayed(TestConstants.publishToHistoryDelay); await channel.publish( message: Message( @@ -71,7 +70,8 @@ Future> testRealtimePublishSpec({ Map? exception; try { await channel.publish( - message: Message(name: 'name', clientId: 'client-id')); + message: Message(name: 'name', clientId: 'client-id'), + ); } on AblyException catch (e) { exception = encodeAblyException(e); } @@ -82,10 +82,7 @@ Future> testRealtimePublishSpec({ // client options - no client id, message has client id final realtime2 = Realtime( - options: ClientOptions( - key: appKey, - environment: 'sandbox', - ), + options: ClientOptions(key: appKey, environment: 'sandbox'), ); final channel2 = realtime2.channels.get('test2'); diff --git a/test_integration/lib/test/realtime/realtime_publish_with_auth_callback_test.dart b/test_integration/lib/test/realtime/realtime_publish_with_auth_callback_test.dart index 669994bbe..5020f1906 100644 --- a/test_integration/lib/test/realtime/realtime_publish_with_auth_callback_test.dart +++ b/test_integration/lib/test/realtime/realtime_publish_with_auth_callback_test.dart @@ -13,9 +13,7 @@ Future> testRealtimePublishWithAuthCallback({ logLevel: LogLevel.error, authCallback: (params) async { authCallbackInvoked = true; - return TokenRequest.fromMap( - await AppProvisioning().getTokenRequest(), - ); + return TokenRequest.fromMap(await AppProvisioning().getTokenRequest()); }, ), ); diff --git a/test_integration/lib/test/realtime/realtime_subscribe.dart b/test_integration/lib/test/realtime/realtime_subscribe.dart index d81f7d1e4..b6a6e5ce8 100644 --- a/test_integration/lib/test/realtime/realtime_subscribe.dart +++ b/test_integration/lib/test/realtime/realtime_subscribe.dart @@ -31,8 +31,8 @@ Future>> _getAllMessages( final subscription = channel .subscribe(name: messageName, names: messageNames) .listen((message) { - messages.add(encodeMessage(message)); - }); + messages.add(encodeMessage(message)); + }); await publishMessages(channel); await subscription.cancel(); return messages; diff --git a/test_integration/lib/test/rest/rest_auth_client_id_test.dart b/test_integration/lib/test/rest/rest_auth_client_id_test.dart index 3cfcafea8..1d00ff5d9 100644 --- a/test_integration/lib/test/rest/rest_auth_client_id_test.dart +++ b/test_integration/lib/test/rest/rest_auth_client_id_test.dart @@ -16,19 +16,18 @@ Future> testRestAuthClientId({ logLevel: LogLevel.error, ); - final ablyForToken = Rest( - options: clientOptionsForToken, - ); + final ablyForToken = Rest(options: clientOptionsForToken); /* get first token */ final firstToken = await ablyForToken.auth.requestToken(); final clientOptions = ClientOptions( - key: appKey, - environment: 'sandbox', - useTokenAuth: true, - autoConnect: false, - clientId: 'testClientId', - tokenDetails: firstToken); + key: appKey, + environment: 'sandbox', + useTokenAuth: true, + autoConnect: false, + clientId: 'testClientId', + tokenDetails: firstToken, + ); final rest = Rest(options: clientOptions); final clientId = await rest.auth.clientId; diff --git a/test_integration/lib/test/rest/rest_authorize_test.dart b/test_integration/lib/test/rest/rest_authorize_test.dart index 44621ff21..7821a51a1 100644 --- a/test_integration/lib/test/rest/rest_authorize_test.dart +++ b/test_integration/lib/test/rest/rest_authorize_test.dart @@ -16,31 +16,32 @@ Future> testRestAuthorize({ logLevel: LogLevel.error, ); - final ablyForToken = Rest( - options: clientOptionsForToken, - ); + final ablyForToken = Rest(options: clientOptionsForToken); /* get first token */ final firstToken = await ablyForToken.auth.requestToken(); final clientOptions = ClientOptions( - key: appKey, - environment: 'sandbox', - useTokenAuth: true, - autoConnect: false, - tokenDetails: firstToken); + key: appKey, + environment: 'sandbox', + useTokenAuth: true, + autoConnect: false, + tokenDetails: firstToken, + ); final rest = Rest(options: clientOptions); const tokenParams = TokenParams(ttl: 20000); - Future authCallback(params) async => TokenRequest.fromMap( - await AppProvisioning().getTokenRequest(), - ); + Future authCallback(params) async => + TokenRequest.fromMap(await AppProvisioning().getTokenRequest()); final authOptions = AuthOptions( - key: appKey, - useTokenAuth: true, - authCallback: authCallback, - authMethod: 'GET'); - final refreshedToken = await rest.auth - .authorize(authOptions: authOptions, tokenParams: tokenParams); + key: appKey, + useTokenAuth: true, + authCallback: authCallback, + authMethod: 'GET', + ); + final refreshedToken = await rest.auth.authorize( + authOptions: authOptions, + tokenParams: tokenParams, + ); //tokens must be different if (refreshedToken == firstToken) { throw Error(); diff --git a/test_integration/lib/test/rest/rest_capability_test.dart b/test_integration/lib/test/rest/rest_capability_test.dart index cb4a49097..4d8de76e1 100644 --- a/test_integration/lib/test/rest/rest_capability_test.dart +++ b/test_integration/lib/test/rest/rest_capability_test.dart @@ -9,15 +9,18 @@ Future> testRestCapabilities({ Map? payload, }) async { final capabilitySpec = >{}; - final combinations = getAllSubsets(['publish', 'history', 'subscribe']) - .where((spec) => spec.isNotEmpty) - .toList(); + final combinations = getAllSubsets([ + 'publish', + 'history', + 'subscribe', + ]).where((spec) => spec.isNotEmpty).toList(); for (var i = 0; i < combinations.length; i++) { capabilitySpec['channel-$i'] = combinations[i]; } - final appKey = - await AppProvisioning(keyCapabilities: capabilitySpec).provisionApp(); + final appKey = await AppProvisioning( + keyCapabilities: capabilitySpec, + ).provisionApp(); final rest = Rest( options: ClientOptions( diff --git a/test_integration/lib/test/rest/rest_create_token_request_test.dart b/test_integration/lib/test/rest/rest_create_token_request_test.dart index 38d106b8d..31bd8ecd1 100644 --- a/test_integration/lib/test/rest/rest_create_token_request_test.dart +++ b/test_integration/lib/test/rest/rest_create_token_request_test.dart @@ -15,30 +15,30 @@ Future> testRestCreateTokenRequest({ logLevel: LogLevel.error, ); - final rest = Rest( - options: clientOptionsForToken, - ); + final rest = Rest(options: clientOptionsForToken); const tokenParams = TokenParams( - ttl: 20000, - capability: '{"testchannel":["publish"]}', - clientId: 'testclient'); + ttl: 20000, + capability: '{"testchannel":["publish"]}', + clientId: 'testclient', + ); final authOptions = AuthOptions( - key: appKey, - useTokenAuth: true, - authMethod: 'GET', - authHeaders: {'heardkey': 'headervalue'}, - authUrl: 'bogus', - authParams: {'paramkey': 'paramvalue'}); - final request = await rest.auth - .createTokenRequest(authOptions: authOptions, tokenParams: tokenParams); + key: appKey, + useTokenAuth: true, + authMethod: 'GET', + authHeaders: {'heardkey': 'headervalue'}, + authUrl: 'bogus', + authParams: {'paramkey': 'paramvalue'}, + ); + final request = await rest.auth.createTokenRequest( + authOptions: authOptions, + tokenParams: tokenParams, + ); if (request.ttl != tokenParams.ttl || request.clientId != tokenParams.clientId || request.capability != tokenParams.capability) { throw Error(); } - return { - 'handle': await rest.handle, - }; + return {'handle': await rest.handle}; } diff --git a/test_integration/lib/test/rest/rest_encrypted_publish_test.dart b/test_integration/lib/test/rest/rest_encrypted_publish_test.dart index 44500d32e..96c0f109d 100644 --- a/test_integration/lib/test/rest/rest_encrypted_publish_test.dart +++ b/test_integration/lib/test/rest/rest_encrypted_publish_test.dart @@ -12,8 +12,9 @@ Future> testRestEncryptedPublish({ reporter.reportLog('init start'); final appKey = await AppProvisioning().provisionApp(); - final cipherParams = - await Crypto.getDefaultParams(key: TestConstants.encryptedChannelKey); + final cipherParams = await Crypto.getDefaultParams( + key: TestConstants.encryptedChannelKey, + ); final channelOptions = RestChannelOptions(cipherParams: cipherParams); @@ -30,9 +31,7 @@ Future> testRestEncryptedPublish({ await channel.setOptions(channelOptions); await publishMessages(channel); - return { - 'handle': await rest.handle, - }; + return {'handle': await rest.handle}; } Future> testRestEncryptedPublishSpec({ @@ -42,8 +41,9 @@ Future> testRestEncryptedPublishSpec({ const clientId = 'clientId'; final appKey = await AppProvisioning().provisionApp(); - final cipherParams = - await Crypto.getDefaultParams(key: TestConstants.encryptedChannelKey); + final cipherParams = await Crypto.getDefaultParams( + key: TestConstants.encryptedChannelKey, + ); final channelOptions = RestChannelOptions(cipherParams: cipherParams); @@ -70,18 +70,17 @@ Future> testRestEncryptedPublishSpec({ // Send single message object await encryptedChannel.publish( - message: Message( - name: 'single-message-name', - data: 'single-message-data', - ), + message: Message(name: 'single-message-name', data: 'single-message-data'), ); await Future.delayed(TestConstants.publishToHistoryDelay); // Send multiple message objects at once - await encryptedChannel.publish(messages: [ - Message(name: 'multi-message-name-1', data: 'multi-message-data-1'), - Message(name: 'multi-message-name-2', data: 'multi-message-data-2'), - ]); + await encryptedChannel.publish( + messages: [ + Message(name: 'multi-message-name-1', data: 'multi-message-data-1'), + Message(name: 'multi-message-name-2', data: 'multi-message-data-2'), + ], + ); await Future.delayed(TestConstants.publishToHistoryDelay); // Send message with [clientId] defined @@ -101,8 +100,9 @@ Future> testRestEncryptedPublishSpec({ ); // Create encrypted channel with push capability - final encryptedPushEnabledChannel = - restWithClientId.channels.get('pushenabled:test:extras'); + final encryptedPushEnabledChannel = restWithClientId.channels.get( + 'pushenabled:test:extras', + ); await encryptedPushEnabledChannel.setOptions(channelOptions); // Send message with extras to encrypted push-enabled channel @@ -115,8 +115,9 @@ Future> testRestEncryptedPublishSpec({ ); // Retrieve history of push-enabled channels - final historyOfEncryptedPushEnabledChannel = - await getHistory(encryptedPushEnabledChannel); + final historyOfEncryptedPushEnabledChannel = await getHistory( + encryptedPushEnabledChannel, + ); // Retreive plaintext history of encrypted channel await encryptedChannel.setOptions(RestChannelOptions()); @@ -125,8 +126,9 @@ Future> testRestEncryptedPublishSpec({ RestHistoryParams(direction: 'forwards'), ); await encryptedPushEnabledChannel.setOptions(RestChannelOptions()); - final historyOfPlaintextPushEnabledChannel = - await getHistory(encryptedPushEnabledChannel); + final historyOfPlaintextPushEnabledChannel = await getHistory( + encryptedPushEnabledChannel, + ); return { 'handle': await restWithClientId.handle, diff --git a/test_integration/lib/test/rest/rest_history_test.dart b/test_integration/lib/test/rest/rest_history_test.dart index b84c0511c..41295e1c7 100644 --- a/test_integration/lib/test/rest/rest_history_test.dart +++ b/test_integration/lib/test/rest/rest_history_test.dart @@ -34,7 +34,9 @@ Future> testRestHistory({ await Future.delayed(TestConstants.publishToHistoryDelay); final historyForwardLimit4 = await getHistory( - channel, RestHistoryParams(direction: 'forwards', limit: 4)); + channel, + RestHistoryParams(direction: 'forwards', limit: 4), + ); await Future.delayed(TestConstants.publishToHistoryDelay); final time1 = DateTime.now(); @@ -51,10 +53,14 @@ Future> testRestHistory({ await channel.publish(name: 'history', data: 'test2'); await Future.delayed(TestConstants.publishToHistoryDelay); - final historyWithStart = - await getHistory(channel, RestHistoryParams(start: time1)); - final historyWithStartAndEnd = - await getHistory(channel, RestHistoryParams(start: time1, end: time2)); + final historyWithStart = await getHistory( + channel, + RestHistoryParams(start: time1), + ); + final historyWithStartAndEnd = await getHistory( + channel, + RestHistoryParams(start: time1, end: time2), + ); final historyAll = await getHistory(channel); return { 'handle': await rest.handle, diff --git a/test_integration/lib/test/rest/rest_history_with_auth_callback_test.dart b/test_integration/lib/test/rest/rest_history_with_auth_callback_test.dart index c5bed7103..1235c34d3 100644 --- a/test_integration/lib/test/rest/rest_history_with_auth_callback_test.dart +++ b/test_integration/lib/test/rest/rest_history_with_auth_callback_test.dart @@ -16,9 +16,7 @@ Future> testRestHistoryWithAuthCallback({ logLevel: LogLevel.error, authCallback: (params) async { authCallbackInvoked = true; - return TokenRequest.fromMap( - await AppProvisioning().getTokenRequest(), - ); + return TokenRequest.fromMap(await AppProvisioning().getTokenRequest()); }, ), ); @@ -31,6 +29,6 @@ Future> testRestHistoryWithAuthCallback({ return { 'handle': await rest.handle, - 'authCallbackInvoked': authCallbackInvoked + 'authCallbackInvoked': authCallbackInvoked, }; } diff --git a/test_integration/lib/test/rest/rest_presence_get_test.dart b/test_integration/lib/test/rest/rest_presence_get_test.dart index f9ce698fe..43d60b97f 100644 --- a/test_integration/lib/test/rest/rest_presence_get_test.dart +++ b/test_integration/lib/test/rest/rest_presence_get_test.dart @@ -10,13 +10,12 @@ final logMessages = >[]; ClientOptions getClientOptions( String appKey, [ String clientId = 'someClientId', -]) => - ClientOptions( - key: appKey, - environment: 'sandbox', - clientId: clientId, - logLevel: LogLevel.error, - ); +]) => ClientOptions( + key: appKey, + environment: 'sandbox', + clientId: clientId, + logLevel: LogLevel.error, +); Future> testRestPresenceGet({ required Reporter reporter, diff --git a/test_integration/lib/test/rest/rest_presence_history_test.dart b/test_integration/lib/test/rest/rest_presence_history_test.dart index 41b8895c3..b40bbcecb 100644 --- a/test_integration/lib/test/rest/rest_presence_history_test.dart +++ b/test_integration/lib/test/rest/rest_presence_history_test.dart @@ -26,8 +26,9 @@ Future> testRestPresenceHistory({ final historyInitial = await getPresenceHistory(channel); // creating presence history on channel - final realtimePresence = - Realtime(options: options).channels.get('test').presence; + final realtimePresence = Realtime( + options: options, + ).channels.get('test').presence; // single client enters channel await realtimePresence.enter(messagesToPublish.first[1]); // updates, multiple times with different messages diff --git a/test_integration/lib/test/rest/rest_publish_test.dart b/test_integration/lib/test/rest/rest_publish_test.dart index ef2cb78c9..77c6bfc98 100644 --- a/test_integration/lib/test/rest/rest_publish_test.dart +++ b/test_integration/lib/test/rest/rest_publish_test.dart @@ -23,10 +23,7 @@ Future> testRestPublish({ ), ); await publishMessages(rest.channels.get('test')); - return { - 'handle': await rest.handle, - 'log': logMessages, - }; + return {'handle': await rest.handle, 'log': logMessages}; } Future> testRestPublishSpec({ @@ -53,10 +50,12 @@ Future> testRestPublishSpec({ message: Message(name: 'message-name1', data: 'message-data1'), ); await Future.delayed(TestConstants.publishToHistoryDelay); - await channel.publish(messages: [ - Message(name: 'messages-name1', data: 'messages-data1'), - Message(name: 'messages-name2', data: 'messages-data2'), - ]); + await channel.publish( + messages: [ + Message(name: 'messages-name1', data: 'messages-data1'), + Message(name: 'messages-name2', data: 'messages-data2'), + ], + ); await Future.delayed(TestConstants.publishToHistoryDelay); await channel.publish( message: Message( @@ -71,7 +70,8 @@ Future> testRestPublishSpec({ Map? exception; try { await channel.publish( - message: Message(name: 'name', clientId: 'client-id')); + message: Message(name: 'name', clientId: 'client-id'), + ); } on AblyException catch (e) { exception = encodeAblyException(e); } @@ -82,10 +82,7 @@ Future> testRestPublishSpec({ // client options - no client id, message has client id final rest2 = Rest( - options: ClientOptions( - key: appKey, - environment: 'sandbox', - ), + options: ClientOptions(key: appKey, environment: 'sandbox'), ); final channel2 = rest2.channels.get('test2'); diff --git a/test_integration/lib/test/rest/rest_publish_with_auth_callback_test.dart b/test_integration/lib/test/rest/rest_publish_with_auth_callback_test.dart index 5ad52f173..3ae80896b 100644 --- a/test_integration/lib/test/rest/rest_publish_with_auth_callback_test.dart +++ b/test_integration/lib/test/rest/rest_publish_with_auth_callback_test.dart @@ -15,15 +15,13 @@ Future> testRestPublishWithAuthCallback({ logLevel: LogLevel.error, authCallback: (params) async { authCallbackInvoked = true; - return TokenRequest.fromMap( - await AppProvisioning().getTokenRequest(), - ); + return TokenRequest.fromMap(await AppProvisioning().getTokenRequest()); }, ), ); await publishMessages(rest.channels.get('test')); return { 'handle': await rest.handle, - 'authCallbackInvoked': authCallbackInvoked + 'authCallbackInvoked': authCallbackInvoked, }; } diff --git a/test_integration/lib/test/rest/rest_request_token_test.dart b/test_integration/lib/test/rest/rest_request_token_test.dart index b6c804efd..deb0592fc 100644 --- a/test_integration/lib/test/rest/rest_request_token_test.dart +++ b/test_integration/lib/test/rest/rest_request_token_test.dart @@ -17,14 +17,15 @@ Future> testRestRequestToken({ logLevel: LogLevel.error, ); - final restForToken = Rest( - options: clientOptionsForToken, - ); + final restForToken = Rest(options: clientOptionsForToken); final token = await restForToken.auth.requestToken(); final clientOptions = ClientOptions( - tokenDetails: token, environment: 'sandbox', logLevel: LogLevel.error); + tokenDetails: token, + environment: 'sandbox', + logLevel: LogLevel.error, + ); final tokenedRest = Rest(options: clientOptions); await publishMessages(tokenedRest.channels.get('test')); diff --git a/test_integration/lib/test/rest/rest_time_test.dart b/test_integration/lib/test/rest/rest_time_test.dart index 4d840dddb..b033fbc02 100644 --- a/test_integration/lib/test/rest/rest_time_test.dart +++ b/test_integration/lib/test/rest/rest_time_test.dart @@ -20,8 +20,5 @@ Future> testRestTime({ final restTime = await rest.time(); - return { - 'handle': await rest.handle, - 'time': restTime.toIso8601String(), - }; + return {'handle': await rest.handle, 'time': restTime.toIso8601String()}; } diff --git a/test_integration/lib/test_dispatcher.dart b/test_integration/lib/test_dispatcher.dart index c7f6f6c0b..a1b9e3bfe 100644 --- a/test_integration/lib/test_dispatcher.dart +++ b/test_integration/lib/test_dispatcher.dart @@ -66,14 +66,18 @@ class _TestDispatcherState extends State { }); final testFunction = widget.testFactory[reporter.testName]!; await testFunction( - reporter: reporter, - payload: reporter.message.payload, - ).then(reporter.reportTestCompletion).catchError( + reporter: reporter, + payload: reporter.message.payload, + ) + .then(reporter.reportTestCompletion) + .catchError( (Object error, StackTrace stack) => reporter.reportTestCompletion({ - TestControlMessage.errorKey: - ErrorHandler.encodeException(error, stack), - }), + TestControlMessage.errorKey: ErrorHandler.encodeException( + error, + stack, + ), + }), ); } } else if (reporter.testName == TestName.getFlutterErrors) { @@ -83,7 +87,7 @@ class _TestDispatcherState extends State { // report error otherwise reporter.reportTestCompletion({ TestControlMessage.errorKey: - 'Test ${reporter.testName} is not implemented' + 'Test ${reporter.testName} is not implemented', }); } setState(() {}); @@ -151,67 +155,65 @@ class _TestDispatcherState extends State { } Widget getTestRow(BuildContext context, String testName) => Row( - children: [ - Expanded( - child: Text( - testName, - style: TextStyle(color: _getColor(testName), fontSize: 16), + children: [ + Expanded( + child: Text( + testName, + style: TextStyle(color: _getColor(testName), fontSize: 16), + ), + ), + _getAction(testName), + _getStatus(testName), + IconButton( + icon: const Icon(Icons.remove_red_eye), + color: Colors.white, + onPressed: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + contentPadding: const EdgeInsets.all(4), + insetPadding: const EdgeInsets.symmetric(vertical: 24), + content: SingleChildScrollView( + child: Text(_testResults[testName] ?? 'No result yet'), + ), ), - ), - _getAction(testName), - _getStatus(testName), - IconButton( - icon: const Icon(Icons.remove_red_eye), - color: Colors.white, - onPressed: () { - showDialog( - context: context, - builder: (context) => AlertDialog( - contentPadding: const EdgeInsets.all(4), - insetPadding: const EdgeInsets.symmetric(vertical: 24), - content: SingleChildScrollView( - child: Text( - _testResults[testName] ?? 'No result yet', - ), - ), - ), - ); - }, - ), - ], - ); + ); + }, + ), + ], + ); @override Widget build(BuildContext context) => MaterialApp( - theme: ThemeData(scaffoldBackgroundColor: Colors.black), - home: Scaffold( - appBar: AppBar( - title: const Text('Test dispatcher'), - ), - body: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Center( - child: Text( - _reporters.isEmpty - ? '-' - : 'running ${_reporters.length}' - ' (${_reporters.keys.toList().toString()}) tests', - style: const TextStyle(color: Colors.white)), + theme: ThemeData(scaffoldBackgroundColor: Colors.black), + home: Scaffold( + appBar: AppBar(title: const Text('Test dispatcher')), + body: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Center( + child: Text( + _reporters.isEmpty + ? '-' + : 'running ${_reporters.length}' + ' (${_reporters.keys.toList().toString()}) tests', + style: const TextStyle(color: Colors.white), ), - Expanded( - child: ListView.builder( - itemCount: _testResults.keys.length, - itemBuilder: (context, idx) { - final testName = _testResults.keys.toList()[idx]; - return ListTile(subtitle: getTestRow(context, testName)); - }, - ), + ), + Expanded( + child: ListView.builder( + itemCount: _testResults.keys.length, + itemBuilder: (context, idx) { + final testName = _testResults.keys.toList()[idx]; + return ListTile(subtitle: getTestRow(context, testName)); + }, ), - ], - ), - )); + ), + ], + ), + ), + ); void renderResponse(TestControlResponseMessage message) { final testName = message.testName; @@ -220,8 +222,8 @@ class _TestDispatcherState extends State { _reporters.remove(testName); _testStatuses[testName] = message.payload.containsKey(TestControlMessage.errorKey) - ? _TestStatus.error - : _TestStatus.success; + ? _TestStatus.error + : _TestStatus.success; }); } } diff --git a/test_integration/lib/utils/data.dart b/test_integration/lib/utils/data.dart index 62b44b6fa..4f2b1fdd5 100644 --- a/test_integration/lib/utils/data.dart +++ b/test_integration/lib/utils/data.dart @@ -7,27 +7,27 @@ final messagesToPublish = [ ['name1', 'Ably'], //message is a string [ 'name2', - [1, 2, 3] + [1, 2, 3], ], //message is a numeric list [ 'name2', - ['hello', 'ably'] + ['hello', 'ably'], ], //message is a string list [ 'name3', { 'hello': 'ably', - 'items': ['1', 2.2, true] - } + 'items': ['1', 2.2, true], + }, ], //message is a map [ 'name3', [ {'hello': 'ably'}, 'ably', - 'realtime' - ] - ] //message is a complex list + 'realtime', + ], + ], //message is a complex list ]; const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; @@ -35,21 +35,23 @@ Random _rnd = Random(); /// get random alpha numeric string of given length String getRandomString(int length) => String.fromCharCodes( - Iterable.generate( - length, - (_) => _chars.codeUnitAt(_rnd.nextInt(_chars.length)), - ), - ); + Iterable.generate( + length, + (_) => _chars.codeUnitAt(_rnd.nextInt(_chars.length)), + ), +); /// returns subsets of all entries in a list List> getAllSubsets(List l) => l.fold>>( [[]], (subLists, element) => subLists - .map((subList) => [ - subList, - subList + [element] - ]) + .map( + (subList) => [ + subList, + subList + [element], + ], + ) .expand((element) => element) .toList(), ); @@ -58,8 +60,8 @@ const pushPayload = { 'push': { 'notification': { 'title': 'Hello from Ably!', - 'body': 'Test push notification from Ably' + 'body': 'Test push notification from Ably', }, - 'data': {'foo': 'bar'} - } + 'data': {'foo': 'bar'}, + }, }; diff --git a/test_integration/lib/utils/encoders.dart b/test_integration/lib/utils/encoders.dart index 1cd7baddf..78f1ec5fc 100644 --- a/test_integration/lib/utils/encoders.dart +++ b/test_integration/lib/utils/encoders.dart @@ -2,83 +2,78 @@ import 'package:ably_flutter/ably_flutter.dart'; Map? encodeMessageExtras(MessageExtras? extras) => extras == null - ? null - : { - 'extras': extras.map, - 'delta': (extras.delta == null) - ? null - : { - 'from': extras.delta!.from, - 'format': extras.delta!.format, - }, - }; + ? null + : { + 'extras': extras.map, + 'delta': (extras.delta == null) + ? null + : {'from': extras.delta!.from, 'format': extras.delta!.format}, + }; Map encodeMessage(Message message) => { - 'id': message.id, - 'timestamp': message.timestamp?.toIso8601String(), - 'clientId': message.clientId, - 'connectionId': message.connectionId, - 'encoding': message.encoding, - 'data': message.data, - 'name': message.name, - 'extras': encodeMessageExtras(message.extras), - }; + 'id': message.id, + 'timestamp': message.timestamp?.toIso8601String(), + 'clientId': message.clientId, + 'connectionId': message.connectionId, + 'encoding': message.encoding, + 'data': message.data, + 'name': message.name, + 'extras': encodeMessageExtras(message.extras), +}; Map encodePresenceMessage(PresenceMessage message) => { - 'id': message.id, - 'action': enumValueToString(message.action!), - 'clientId': message.clientId, - 'connectionId': message.connectionId, - 'data': message.data, - 'encoding': message.encoding, - 'extras': encodeMessageExtras(message.extras), - 'timestamp': message.timestamp?.toIso8601String(), - }; + 'id': message.id, + 'action': enumValueToString(message.action!), + 'clientId': message.clientId, + 'connectionId': message.connectionId, + 'data': message.data, + 'encoding': message.encoding, + 'extras': encodeMessageExtras(message.extras), + 'timestamp': message.timestamp?.toIso8601String(), +}; String enumValueToString(Object value) => value.toString().substring(value.toString().indexOf('.') + 1); Map encodeChannelEvent(ChannelStateChange e) => { - 'event': enumValueToString(e.event), - 'current': enumValueToString(e.current), - 'previous': enumValueToString(e.previous), - 'reason': e.reason.toString(), - 'resumed': e.resumed, - }; + 'event': enumValueToString(e.event), + 'current': enumValueToString(e.current), + 'previous': enumValueToString(e.previous), + 'reason': e.reason.toString(), + 'resumed': e.resumed, +}; Map encodeConnectionEvent(ConnectionStateChange e) => { - 'event': enumValueToString(e.event), - 'current': enumValueToString(e.current), - 'previous': enumValueToString(e.previous), - 'reason': e.reason.toString(), - 'retryIn': e.retryIn, - }; + 'event': enumValueToString(e.event), + 'current': enumValueToString(e.current), + 'previous': enumValueToString(e.previous), + 'reason': e.reason.toString(), + 'retryIn': e.retryIn, +}; List> encodeList( List items, Map Function(T) typeEncoder, -) => - List.from(items).map>(typeEncoder).toList(); +) => List.from(items).map>(typeEncoder).toList(); Map encodePaginatedResult( PaginatedResult paginatedResult, Map Function(T) typeEncoder, -) => - { - 'items': encodeList(paginatedResult.items, typeEncoder), - 'hasNext': paginatedResult.hasNext(), - 'isLast': paginatedResult.isLast(), - }; +) => { + 'items': encodeList(paginatedResult.items, typeEncoder), + 'hasNext': paginatedResult.hasNext(), + 'isLast': paginatedResult.isLast(), +}; Map encodeAblyException(AblyException exception) => { - 'code': exception.code, - 'message': exception.message, - 'errorInfo': { - 'code': exception.errorInfo?.code, - 'href': exception.errorInfo?.href, - 'message': exception.errorInfo?.message, - 'cause': exception.errorInfo?.cause, - 'statusCode': exception.errorInfo?.statusCode, - 'requestId': exception.errorInfo?.requestId, - } - }; + 'code': exception.code, + 'message': exception.message, + 'errorInfo': { + 'code': exception.errorInfo?.code, + 'href': exception.errorInfo?.href, + 'message': exception.errorInfo?.message, + 'cause': exception.errorInfo?.cause, + 'statusCode': exception.errorInfo?.statusCode, + 'requestId': exception.errorInfo?.requestId, + }, +}; diff --git a/test_integration/lib/utils/realtime.dart b/test_integration/lib/utils/realtime.dart index 5d591c595..b1505714c 100644 --- a/test_integration/lib/utils/realtime.dart +++ b/test_integration/lib/utils/realtime.dart @@ -24,19 +24,20 @@ Future>> getHistory( Future>> getPresenceMembers( RealtimeChannel channel, [ RealtimePresenceParams? params, -]) async => - encodeList( - await channel.presence.get(params), - encodePresenceMessage, - ); +]) async => encodeList( + await channel.presence.get(params), + encodePresenceMessage, +); Future>> getPresenceHistory( RealtimeChannel channel, [ RealtimeHistoryParams? params, ]) async { var results = await channel.presence.history(params); - final messages = - encodeList(results.items, encodePresenceMessage); + final messages = encodeList( + results.items, + encodePresenceMessage, + ); while (results.hasNext()) { results = await results.next(); messages.addAll( diff --git a/test_integration/lib/utils/rest.dart b/test_integration/lib/utils/rest.dart index 0c14335fb..6f5d5b7e6 100644 --- a/test_integration/lib/utils/rest.dart +++ b/test_integration/lib/utils/rest.dart @@ -26,12 +26,15 @@ Future>> getPresenceHistory( RestHistoryParams? params, ]) async { var results = await channel.presence.history(params); - final messages = - encodeList(results.items, encodePresenceMessage); + final messages = encodeList( + results.items, + encodePresenceMessage, + ); while (results.hasNext()) { results = await results.next(); messages.addAll( - encodeList(results.items, encodePresenceMessage)); + encodeList(results.items, encodePresenceMessage), + ); } return messages; } @@ -41,12 +44,15 @@ Future>> getPresenceMembers( RestPresenceParams? params, ]) async { var results = await channel.presence.get(params); - final messages = - encodeList(results.items, encodePresenceMessage); + final messages = encodeList( + results.items, + encodePresenceMessage, + ); while (results.hasNext()) { results = await results.next(); messages.addAll( - encodeList(results.items, encodePresenceMessage)); + encodeList(results.items, encodePresenceMessage), + ); } return messages; } diff --git a/test_integration/test_driver/runner.dart b/test_integration/test_driver/runner.dart index 5a113d2bd..050e3ae61 100644 --- a/test_integration/test_driver/runner.dart +++ b/test_integration/test_driver/runner.dart @@ -25,8 +25,9 @@ void main(List args) { return; } - final selectedModules = - _parseModulesStringIntoTestModules(argv['modules'] as List); + final selectedModules = _parseModulesStringIntoTestModules( + argv['modules'] as List, + ); if (selectedModules.isEmpty) { runTests(all: true); @@ -36,7 +37,8 @@ void main(List args) { } Iterable _parseModulesStringIntoTestModules( - List modulesStrings) { + List modulesStrings, +) { final modules = modulesStrings .map((module) => EnumToString.fromString(TestModules.values, module)) .whereType() diff --git a/test_integration/test_driver/test_implementation/basic_platform_tests.dart b/test_integration/test_driver/test_implementation/basic_platform_tests.dart index 3eda6ae9d..51f603a47 100644 --- a/test_integration/test_driver/test_implementation/basic_platform_tests.dart +++ b/test_integration/test_driver/test_implementation/basic_platform_tests.dart @@ -6,7 +6,8 @@ void testPlatformAndAblyVersion(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.platformAndAblyVersion); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); test('platformVersion is a string', () { expect(response.payload['platformVersion'], isA()); @@ -29,7 +30,8 @@ void testDemoDependencies(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.appKeyProvisioning); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); test('appKey is a string', () { expect(response.payload['appKey'], isA()); diff --git a/test_integration/test_driver/test_implementation/crypto_tests.dart b/test_integration/test_driver/test_implementation/crypto_tests.dart index 201c6fd5a..c53282bb4 100644 --- a/test_integration/test_driver/test_implementation/crypto_tests.dart +++ b/test_integration/test_driver/test_implementation/crypto_tests.dart @@ -45,14 +45,18 @@ void testCryptoEnsureSupportedKeyLength(FlutterDriver Function() getDriver) { setUpAll(() async { response = await requestDataForTest(getDriver(), message); - keyWithDefaultLengthException = response - .payload['keyWithDefaultLengthException'] as Map?; - keyWith128BitLengthException = response - .payload['keyWith128BitLengthException'] as Map?; - keyWith256BitLengthException = response - .payload['keyWith256BitLengthException'] as Map?; - keyWith127BitLengthException = response - .payload['keyWith127BitLengthException'] as Map?; + keyWithDefaultLengthException = + response.payload['keyWithDefaultLengthException'] + as Map?; + keyWith128BitLengthException = + response.payload['keyWith128BitLengthException'] + as Map?; + keyWith256BitLengthException = + response.payload['keyWith256BitLengthException'] + as Map?; + keyWith127BitLengthException = + response.payload['keyWith127BitLengthException'] + as Map?; }); group('crypto#ensureSupportedKeyLength', () { @@ -86,8 +90,9 @@ void testCryptoGetDefaultParams(FlutterDriver Function() getDriver) { setUpAll(() async { response = await requestDataForTest(getDriver(), message); - keyWith127BitLengthException = response - .payload['keyWith127BitLengthException'] as Map?; + keyWith127BitLengthException = + response.payload['keyWith127BitLengthException'] + as Map?; didFetchDefaultParams = response.payload['didFetchDefaultParams'] as bool?; }); diff --git a/test_integration/test_driver/test_implementation/helper_tests.dart b/test_integration/test_driver/test_implementation/helper_tests.dart index 287b71770..948639a78 100644 --- a/test_integration/test_driver/test_implementation/helper_tests.dart +++ b/test_integration/test_driver/test_implementation/helper_tests.dart @@ -6,7 +6,8 @@ void testShouldReportUnhandledException(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.testHelperUnhandledExceptionTest); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); test('returns appropriate error message', () { expect(response.payload['error']['exceptionType'], 'String'); diff --git a/test_integration/test_driver/test_implementation/realtime_tests.dart b/test_integration/test_driver/test_implementation/realtime_tests.dart index 1a9646a15..bcd309df3 100644 --- a/test_integration/test_driver/test_implementation/realtime_tests.dart +++ b/test_integration/test_driver/test_implementation/realtime_tests.dart @@ -53,8 +53,9 @@ void testRealtimePublishSpec(FlutterDriver Function() getDriver) { messages = transformListResponse(response.payload['publishedMessages']); messages2 = transformListResponse(response.payload['publishedMessages2']); messages3 = transformListResponse(response.payload['publishedMessages3']); - messagesWithExtras = - transformListResponse(response.payload['publishedExtras']); + messagesWithExtras = transformListResponse( + response.payload['publishedExtras'], + ); exception = response.payload['exception'] as Map?; }); @@ -96,15 +97,13 @@ void testRealtimePublishSpec(FlutterDriver Function() getDriver) { expect(messages[5]['timestamp'] != messages[4]['timestamp'], true); }); - test( - '(RSL1m1) Publishing a Message with no clientId when the clientId' + test('(RSL1m1) Publishing a Message with no clientId when the clientId' ' is set to some value in the client options should result in a message' ' received with the clientId property set to that value', () { expect(messages[0]['clientId'], 'someClientId'); }); - test( - '(RSL1m2) Publishing a Message with a clientId set to the same' + test('(RSL1m2) Publishing a Message with a clientId set to the same' ' value as the clientId in the client options should result in' ' a message received with the clientId property set to that value', () { expect(messages[7]['clientId'], 'someClientId'); @@ -132,13 +131,10 @@ void testRealtimePublishSpec(FlutterDriver Function() getDriver) { () => expect(messages2[0]['clientId'], 'client-id'), ); - test( - 'publishes non-ascii characters', - () { - expect(messages3[0]['name'], 'Ωπ'); - expect(messages3[0]['data'], 'ΨΔ'); - }, - ); + test('publishes non-ascii characters', () { + expect(messages3[0]['name'], 'Ωπ'); + expect(messages3[0]['data'], 'ΨΔ'); + }); }); test('(RSL6a2) publishes message extras', () { @@ -173,21 +169,27 @@ void testRealtimeEncryptedPublishSpec(FlutterDriver Function() getDriver) { setUpAll(() async { response = await requestDataForTest(getDriver(), message); - historyOfEncryptedChannel = - transformListResponse(response.payload['historyOfEncryptedChannel']); - historyOfPlaintextChannel = - transformListResponse(response.payload['historyOfPlaintextChannel']); + historyOfEncryptedChannel = transformListResponse( + response.payload['historyOfEncryptedChannel'], + ); + historyOfPlaintextChannel = transformListResponse( + response.payload['historyOfPlaintextChannel'], + ); historyOfEncryptedPushEnabledChannel = transformListResponse( - response.payload['historyOfEncryptedPushEnabledChannel']); + response.payload['historyOfEncryptedPushEnabledChannel'], + ); historyOfPlaintextPushEnabledChannel = transformListResponse( - response.payload['historyOfPlaintextPushEnabledChannel']); + response.payload['historyOfPlaintextPushEnabledChannel'], + ); }); group('RSL5', () { test('does not encrypt name', () { for (var i = 0; i < historyOfEncryptedPushEnabledChannel.length; i++) { - expect(historyOfEncryptedChannel[i]['name'], - equals(historyOfPlaintextChannel[i]['name'])); + expect( + historyOfEncryptedChannel[i]['name'], + equals(historyOfPlaintextChannel[i]['name']), + ); } }); @@ -205,8 +207,10 @@ void testRealtimeEncryptedPublishSpec(FlutterDriver Function() getDriver) { test('does not encrypt extras', () { for (var i = 0; i < historyOfEncryptedPushEnabledChannel.length; i++) { - expect(historyOfEncryptedPushEnabledChannel[i]['name'], - equals(historyOfPlaintextPushEnabledChannel[i]['name'])); + expect( + historyOfEncryptedPushEnabledChannel[i]['name'], + equals(historyOfPlaintextPushEnabledChannel[i]['name']), + ); } }); }); @@ -246,70 +250,63 @@ void testRealtimeEvents(FlutterDriver Function() getDriver) { group('realtime#channel#connection', () { test('#state', () { expect( - connectionStates, - orderedEquals(const [ - 'initialized', - 'initialized', - 'connected', - 'connected', - 'closed', - ])); + connectionStates, + orderedEquals(const [ + 'initialized', + 'initialized', + 'connected', + 'connected', + 'closed', + ]), + ); }); test( '#on returns a stream which can be subscribed for connectionStateChanges', () { expect( - connectionStateChanges.map((e) => e['event']), - orderedEquals(const [ - 'connecting', - 'connected', - 'closing', - 'closed', - ])); + connectionStateChanges.map((e) => e['event']), + orderedEquals(const ['connecting', 'connected', 'closing', 'closed']), + ); expect( - connectionStateChanges.map((e) => e['previous']), - orderedEquals(const [ - 'initialized', - 'connecting', - 'connected', - 'closing', - ])); + connectionStateChanges.map((e) => e['previous']), + orderedEquals(const [ + 'initialized', + 'connecting', + 'connected', + 'closing', + ]), + ); }, ); - test( - '#on returns a stream which can be subscribed' - ' for connection state changes with filter', - () { - expect(filteredConnectionStateChanges.map((e) => e['event']), const [ - 'connected', - ]); - expect(filteredConnectionStateChanges.map((e) => e['current']), const [ - 'connected', - ]); - expect(filteredConnectionStateChanges.map((e) => e['previous']), const [ - 'connecting', - ]); - }, - ); + test('#on returns a stream which can be subscribed' + ' for connection state changes with filter', () { + expect(filteredConnectionStateChanges.map((e) => e['event']), const [ + 'connected', + ]); + expect(filteredConnectionStateChanges.map((e) => e['current']), const [ + 'connected', + ]); + expect(filteredConnectionStateChanges.map((e) => e['previous']), const [ + 'connecting', + ]); + }); }); group('realtime#channel#chanenls#channel', () { - test( - '#state', - () { - expect( - channelStates, - orderedEquals(const [ - 'initialized', - 'initialized', - 'attached', - 'attached', - 'detached', - 'detached', - ])); - }, - ); + test('#state', () { + expect( + channelStates, + orderedEquals(const [ + 'initialized', + 'initialized', + 'attached', + 'attached', + 'detached', + 'detached', + ]), + ); + }); test( '#on returns a stream which can be subscribed for channel state changes', () { @@ -359,55 +356,54 @@ void testRealtimeEvents(FlutterDriver Function() getDriver) { ]; } - expect(channelStateChanges.map((e) => e['event']), - orderedEquals(_stateChangeEvents)); + expect( + channelStateChanges.map((e) => e['event']), + orderedEquals(_stateChangeEvents), + ); - expect(channelStateChanges.map((e) => e['current']), - orderedEquals(_stateChangeCurrent)); + expect( + channelStateChanges.map((e) => e['current']), + orderedEquals(_stateChangeCurrent), + ); - expect(channelStateChanges.map((e) => e['previous']), - orderedEquals(_stateChangePrevious)); + expect( + channelStateChanges.map((e) => e['previous']), + orderedEquals(_stateChangePrevious), + ); }, ); - test( - '#on returns a stream which can be subscribed' - ' for channel state changes with filter', - () { - List _stateChangeCurrent; - List _stateChangePrevious; - List _stateChangeEvents; - if (channelStateChanges.length == 4) { - // iOS - _stateChangeCurrent = const [ - 'attaching', - ]; - _stateChangePrevious = const [ - 'initialized', - ]; - } else { - // Android - _stateChangeCurrent = const [ - 'attaching', - 'attaching', - ]; - _stateChangePrevious = const [ - 'initialized', - 'attaching', - ]; - } - _stateChangeEvents = _stateChangeCurrent; - // filteredChannelStateChanges - expect(filteredChannelStateChanges.map((e) => e['event']), - orderedEquals(_stateChangeEvents)); + test('#on returns a stream which can be subscribed' + ' for channel state changes with filter', () { + List _stateChangeCurrent; + List _stateChangePrevious; + List _stateChangeEvents; + if (channelStateChanges.length == 4) { + // iOS + _stateChangeCurrent = const ['attaching']; + _stateChangePrevious = const ['initialized']; + } else { + // Android + _stateChangeCurrent = const ['attaching', 'attaching']; + _stateChangePrevious = const ['initialized', 'attaching']; + } + _stateChangeEvents = _stateChangeCurrent; + // filteredChannelStateChanges + expect( + filteredChannelStateChanges.map((e) => e['event']), + orderedEquals(_stateChangeEvents), + ); - expect(filteredChannelStateChanges.map((e) => e['current']), - orderedEquals(_stateChangeCurrent)); + expect( + filteredChannelStateChanges.map((e) => e['current']), + orderedEquals(_stateChangeCurrent), + ); - expect(filteredChannelStateChanges.map((e) => e['previous']), - orderedEquals(_stateChangePrevious)); - }, - ); + expect( + filteredChannelStateChanges.map((e) => e['previous']), + orderedEquals(_stateChangePrevious), + ); + }); }); } @@ -422,55 +418,47 @@ void testRealtimeSubscribe(FlutterDriver Function() getDriver) { setUpAll(() async { response = await requestDataForTest(getDriver(), message); all = transformListResponse(response.payload['all']); - filteredWithName = - transformListResponse(response.payload['filteredWithName']); + filteredWithName = transformListResponse( + response.payload['filteredWithName'], + ); filteredWithNames = transformListResponse( response.payload['filteredWithNames'], ); extrasMessages = transformListResponse(response.payload['extrasMessages']); }); - test( - 'realtime#channels#channel#subscribe should subscribe to' - ' all message on channel', - () { - testAllPublishedMessages(all); - }, - ); + test('realtime#channels#channel#subscribe should subscribe to' + ' all message on channel', () { + testAllPublishedMessages(all); + }); - test( - 'realtime#channels#channel#subscribe(name: string)' - ' should subscribe to messages with specified name', - () { - expect(filteredWithName.length, equals(2)); + test('realtime#channels#channel#subscribe(name: string)' + ' should subscribe to messages with specified name', () { + expect(filteredWithName.length, equals(2)); - expect(filteredWithName[0]['name'], 'name1'); - expect(filteredWithName[0]['data'], isNull); + expect(filteredWithName[0]['name'], 'name1'); + expect(filteredWithName[0]['data'], isNull); - expect(filteredWithName[1]['name'], 'name1'); - expect(filteredWithName[1]['data'], equals('Ably')); - }, - ); + expect(filteredWithName[1]['name'], 'name1'); + expect(filteredWithName[1]['data'], equals('Ably')); + }); - test( - 'realtime#channels#channel#subscribe(names: List)' - ' should subscribe to messages with specified names', - () { - expect(filteredWithNames.length, equals(4)); + test('realtime#channels#channel#subscribe(names: List)' + ' should subscribe to messages with specified names', () { + expect(filteredWithNames.length, equals(4)); - expect(filteredWithNames[0]['name'], 'name1'); - expect(filteredWithNames[0]['data'], isNull); + expect(filteredWithNames[0]['name'], 'name1'); + expect(filteredWithNames[0]['data'], isNull); - expect(filteredWithNames[1]['name'], 'name1'); - expect(filteredWithNames[1]['data'], equals('Ably')); + expect(filteredWithNames[1]['name'], 'name1'); + expect(filteredWithNames[1]['data'], equals('Ably')); - expect(filteredWithNames[2]['name'], 'name2'); - expect(filteredWithNames[2]['data'], equals([1, 2, 3])); + expect(filteredWithNames[2]['name'], 'name2'); + expect(filteredWithNames[2]['data'], equals([1, 2, 3])); - expect(filteredWithNames[3]['name'], 'name2'); - expect(filteredWithNames[3]['data'], equals(['hello', 'ably'])); - }, - ); + expect(filteredWithNames[3]['name'], 'name2'); + expect(filteredWithNames[3]['data'], equals(['hello', 'ably'])); + }); test('retrieves extras posted in message', () { expect(extrasMessages[0]['name'], 'name'); @@ -499,10 +487,12 @@ void testRealtimeHistory(FlutterDriver Function() getDriver) { historyDefault = transformListResponse(response.payload['historyDefault']); historyLimit4 = transformListResponse(response.payload['historyLimit4']); historyLimit2 = transformListResponse(response.payload['historyLimit2']); - historyForwardLimit4 = - transformListResponse(response.payload['historyForwardLimit4']); - historyWithStart = - transformListResponse(response.payload['historyWithStart']); + historyForwardLimit4 = transformListResponse( + response.payload['historyForwardLimit4'], + ); + historyWithStart = transformListResponse( + response.payload['historyWithStart'], + ); historyWithStartAndEnd = transformListResponse( response.payload['historyWithStartAndEnd'], ); @@ -531,11 +521,13 @@ void testRealtimeHistory(FlutterDriver Function() getDriver) { testAllPublishedMessages(historyLimit4.reversed.toList()); testAllPublishedMessages(historyLimit2.reversed.toList()); }); - test('queries entries in reverse order with direction set to "forward"', - () { - expect(historyForwardLimit4.length, equals(8)); - testAllPublishedMessages(historyForwardLimit4); - }); + test( + 'queries entries in reverse order with direction set to "forward"', + () { + expect(historyForwardLimit4.length, equals(8)); + testAllPublishedMessages(historyForwardLimit4); + }, + ); test('returns entries created after specified time', () { expect(historyWithStart.length, equals(2)); expect(historyWithStart[0]['name'], equals('history')); @@ -555,7 +547,8 @@ void testRealtimeHistoryWithAuthCallback(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.realtimeHistoryWithAuthCallback); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); test('auth callback is invoked', () { expect(response.payload['authCallbackInvoked'], isTrue); @@ -592,10 +585,12 @@ void testRealtimePresenceGet(FlutterDriver Function() getDriver) { response = await requestDataForTest(getDriver(), message); membersInitial = transformListResponse(response.payload['membersInitial']); membersDefault = transformListResponse(response.payload['membersDefault']); - membersClientId = - transformListResponse(response.payload['membersClientId']); - membersConnectionId = - transformListResponse(response.payload['membersConnectionId']); + membersClientId = transformListResponse( + response.payload['membersClientId'], + ); + membersConnectionId = transformListResponse( + response.payload['membersConnectionId'], + ); }); group('realtime#channels#channel#presence#get', () { @@ -639,8 +634,9 @@ void testRealtimePresenceHistory(FlutterDriver Function() getDriver) { historyDefault = transformListResponse(response.payload['historyDefault']); historyLimit4 = transformListResponse(response.payload['historyLimit4']); historyLimit2 = transformListResponse(response.payload['historyLimit2']); - historyForwards = - transformListResponse(response.payload['historyForwards']); + historyForwards = transformListResponse( + response.payload['historyForwards'], + ); historyWithStart = transformListResponse( response.payload['historyWithStart'], ).reversed.toList(); @@ -663,13 +659,10 @@ void testRealtimePresenceHistory(FlutterDriver Function() getDriver) { testAllPresenceMessagesHistory(historyLimit4.reversed.toList()); testAllPresenceMessagesHistory(historyLimit2.reversed.toList()); }); - test( - 'queries entries in reverse order with direction set to "forward"', - () { - expect(historyForwards.length, equals(8)); - testAllPresenceMessagesHistory(historyForwards.toList()); - }, - ); + test('queries entries in reverse order with direction set to "forward"', () { + expect(historyForwards.length, equals(8)); + testAllPresenceMessagesHistory(historyForwards.toList()); + }); test('returns entries created after specified time', () { expect(historyWithStart.length, equals(2)); expect(historyWithStart[0]['clientId'], equals('someClientId')); @@ -693,8 +686,9 @@ void testRealtimeEnterUpdateLeave(FlutterDriver Function() getDriver) { setUpAll(() async { response = await requestDataForTest(getDriver(), message); - clientIDClashMatrix = - transformListResponse(response.payload['clientIDClashMatrix']); + clientIDClashMatrix = transformListResponse( + response.payload['clientIDClashMatrix'], + ); actionMatrix = transformListResponse(response.payload['actionMatrix']); }); @@ -739,8 +733,7 @@ void testRealtimeEnterUpdateLeave(FlutterDriver Function() getDriver) { ); } - test( - 'clientID should be same in both realtime ClientOptions as well as' + test('clientID should be same in both realtime ClientOptions as well as' ' the one passed to presence enter/update/leave APIs.' ' If unequal, throw error.', () { for (final clashEntry in clientIDClashMatrix) { @@ -758,20 +751,10 @@ void testRealtimeEnterUpdateLeave(FlutterDriver Function() getDriver) { ); } else if (presenceClientID == null) { // only realtimeClientID is present - testMatrixEntry( - clashEntry, - enter: true, - update: true, - leave: true, - ); + testMatrixEntry(clashEntry, enter: true, update: true, leave: true); } else { // both clientIDs are present and are unequal - testMatrixEntry( - clashEntry, - enter: true, - update: true, - leave: true, - ); + testMatrixEntry(clashEntry, enter: true, update: true, leave: true); } } else { if (presenceClientID == null) { @@ -820,10 +803,12 @@ void testRealtimePresenceSubscription(FlutterDriver Function() getDriver) { response = await requestDataForTest(getDriver(), message); allMessages = transformListResponse(response.payload['allMessages']); enterMessages = transformListResponse(response.payload['enterMessages']); - enterUpdateMessages = - transformListResponse(response.payload['enterUpdateMessages']); - partialMessages = - transformListResponse(response.payload['partialMessages']); + enterUpdateMessages = transformListResponse( + response.payload['enterUpdateMessages'], + ); + partialMessages = transformListResponse( + response.payload['partialMessages'], + ); }); void _test(List> messages) { @@ -838,31 +823,43 @@ void testRealtimePresenceSubscription(FlutterDriver Function() getDriver) { } } - test('listens to messages', () { - expect(allMessages.length, equals(8)); - _test(allMessages); - }, - skip: - 'One message in allMessages gets `present` action, but should have been `enter`. See https://github.com/ably/ably-flutter/issues/150'); - - test('filters messages with single action', () { - expect(enterMessages.length, equals(1)); - _test(enterMessages); - }, - skip: - 'expected 1 but got 0. See https://github.com/ably/ably-flutter/issues/150'); - - test('filters messages with multiple actions', () { - expect(enterUpdateMessages.length, equals(7)); - _test(enterUpdateMessages); - }, - skip: - 'Got a length of 6 but expected 7. See https://github.com/ably/ably-flutter/issues/150'); - - test('listens to messages only until subscription is active', () { - expect(partialMessages.length, equals(7)); - expect(partialMessages, equals(enterUpdateMessages)); - }, - skip: - 'Expected a set of messages, but got the same set but with 1 unexpected extra message at the start, with `present` action. See https://github.com/ably/ably-flutter/issues/150'); + test( + 'listens to messages', + () { + expect(allMessages.length, equals(8)); + _test(allMessages); + }, + skip: + 'One message in allMessages gets `present` action, but should have been `enter`. See https://github.com/ably/ably-flutter/issues/150', + ); + + test( + 'filters messages with single action', + () { + expect(enterMessages.length, equals(1)); + _test(enterMessages); + }, + skip: + 'expected 1 but got 0. See https://github.com/ably/ably-flutter/issues/150', + ); + + test( + 'filters messages with multiple actions', + () { + expect(enterUpdateMessages.length, equals(7)); + _test(enterUpdateMessages); + }, + skip: + 'Got a length of 6 but expected 7. See https://github.com/ably/ably-flutter/issues/150', + ); + + test( + 'listens to messages only until subscription is active', + () { + expect(partialMessages.length, equals(7)); + expect(partialMessages, equals(enterUpdateMessages)); + }, + skip: + 'Expected a set of messages, but got the same set but with 1 unexpected extra message at the start, with `present` action. See https://github.com/ably/ably-flutter/issues/150', + ); } diff --git a/test_integration/test_driver/test_implementation/rest_tests.dart b/test_integration/test_driver/test_implementation/rest_tests.dart index 0e740c30e..c92cc1190 100644 --- a/test_integration/test_driver/test_implementation/rest_tests.dart +++ b/test_integration/test_driver/test_implementation/rest_tests.dart @@ -10,7 +10,8 @@ void testRestPublish(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.restPublish); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); test('rest instance has a valid handle on publish', () { expect(response.payload['handle'], isA()); @@ -22,10 +23,10 @@ void testRestRequestTokenPublish(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.restRequestToken); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); - test( - 'rest instance with token has a valid handle and successfully' + test('rest instance with token has a valid handle and successfully' ' publishes messages', () { expect(response.payload['handle'], isA()); expect(response.payload['handle'], greaterThan(0)); @@ -36,10 +37,10 @@ void testRestCreateTokenRequestPublish(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.restCreateTokenRequest); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); - test( - 'rest instance with token has a valid handle and successfully ' + test('rest instance with token has a valid handle and successfully ' 'publishes messages', () { expect(response.payload['handle'], isA()); expect(response.payload['log'], greaterThan(0)); @@ -50,7 +51,8 @@ void testRestEncryptedPublish(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.restEncryptedPublish); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); test('rest instance has a valid handle on encrypted publish', () { expect(response.payload['handle'], isA()); @@ -75,8 +77,9 @@ void testRestPublishSpec(FlutterDriver Function() getDriver) { messages = transformListResponse(response.payload['publishedMessages']); messages2 = transformListResponse(response.payload['publishedMessages2']); messages3 = transformListResponse(response.payload['publishedMessages3']); - messagesWithExtras = - transformListResponse(response.payload['publishedExtras']); + messagesWithExtras = transformListResponse( + response.payload['publishedExtras'], + ); exception = response.payload['exception'] as Map?; exception2 = response.payload['exception2'] as Map?; exception3 = response.payload['exception3'] as Map?; @@ -115,16 +118,17 @@ void testRestPublishSpec(FlutterDriver Function() getDriver) { }); test( - '(RSL1m1) Publishing a Message with no clientId when the clientId' - ' is set to some value in the client options should result in a message' - ' received with the clientId property set to that value', () { - expect(messages[0]['clientId'], 'someClientId'); - }, - skip: - 'Failing on Android, the clientId is null`. See https://github.com/ably/ably-flutter/issues/150'); + '(RSL1m1) Publishing a Message with no clientId when the clientId' + ' is set to some value in the client options should result in a message' + ' received with the clientId property set to that value', + () { + expect(messages[0]['clientId'], 'someClientId'); + }, + skip: + 'Failing on Android, the clientId is null`. See https://github.com/ably/ably-flutter/issues/150', + ); - test( - '(RSL1m2) Publishing a Message with a clientId set to the same' + test('(RSL1m2) Publishing a Message with a clientId set to the same' ' value as the clientId in the client options should result in' ' a message received with the clientId property set to that value', () { expect(messages[7]['clientId'], 'someClientId'); @@ -165,26 +169,20 @@ void testRestPublishSpec(FlutterDriver Function() getDriver) { () => expect(messages2[0]['clientId'], 'client-id'), ); - test( - '(RSL1i) If the total size of the message or (if publishing an array)' - ' messages, calculated per TO3l8, exceeds the maxMessageSize, then the' - ' client library should reject the publish and indicate an error' - ' with code 40009', - () { - // allows publishing messages length <= max allowed limit - expect(exception2 == null, true); - // errors out publishing messages length > max allowed limit - expect(exception3 == null, false); - }, - ); + test('(RSL1i) If the total size of the message or (if publishing an array)' + ' messages, calculated per TO3l8, exceeds the maxMessageSize, then the' + ' client library should reject the publish and indicate an error' + ' with code 40009', () { + // allows publishing messages length <= max allowed limit + expect(exception2 == null, true); + // errors out publishing messages length > max allowed limit + expect(exception3 == null, false); + }); - test( - 'publishes non-ascii characters', - () { - expect(messages3[0]['name'], 'Ωπ'); - expect(messages3[0]['data'], 'ΨΔ'); - }, - ); + test('publishes non-ascii characters', () { + expect(messages3[0]['name'], 'Ωπ'); + expect(messages3[0]['data'], 'ΨΔ'); + }); }); test('RSL6a2 publishes message extras', () { @@ -206,21 +204,27 @@ void testRestEncryptedPublishSpec(FlutterDriver Function() getDriver) { setUpAll(() async { response = await requestDataForTest(getDriver(), message); - historyOfEncryptedChannel = - transformListResponse(response.payload['historyOfEncryptedChannel']); - historyOfPlaintextChannel = - transformListResponse(response.payload['historyOfPlaintextChannel']); + historyOfEncryptedChannel = transformListResponse( + response.payload['historyOfEncryptedChannel'], + ); + historyOfPlaintextChannel = transformListResponse( + response.payload['historyOfPlaintextChannel'], + ); historyOfEncryptedPushEnabledChannel = transformListResponse( - response.payload['historyOfEncryptedPushEnabledChannel']); + response.payload['historyOfEncryptedPushEnabledChannel'], + ); historyOfPlaintextPushEnabledChannel = transformListResponse( - response.payload['historyOfPlaintextPushEnabledChannel']); + response.payload['historyOfPlaintextPushEnabledChannel'], + ); }); group('RSL5', () { test('does not encrypt name', () { for (var i = 0; i < historyOfEncryptedPushEnabledChannel.length; i++) { - expect(historyOfEncryptedChannel[i]['name'], - equals(historyOfPlaintextChannel[i]['name'])); + expect( + historyOfEncryptedChannel[i]['name'], + equals(historyOfPlaintextChannel[i]['name']), + ); } }); @@ -238,8 +242,10 @@ void testRestEncryptedPublishSpec(FlutterDriver Function() getDriver) { test('does not encrypt extras', () { for (var i = 0; i < historyOfEncryptedPushEnabledChannel.length; i++) { - expect(historyOfEncryptedPushEnabledChannel[i]['name'], - equals(historyOfPlaintextPushEnabledChannel[i]['name'])); + expect( + historyOfEncryptedPushEnabledChannel[i]['name'], + equals(historyOfPlaintextPushEnabledChannel[i]['name']), + ); } }); }); @@ -249,7 +255,8 @@ void testRestPublishWithAuthCallback(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.restPublishWithAuthCallback); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); test('auth callback is invoked', () { expect(response.payload['authCallbackInvoked'], isTrue); @@ -275,10 +282,12 @@ void testRestHistory(FlutterDriver Function() getDriver) { historyDefault = transformListResponse(response.payload['historyDefault']); historyLimit4 = transformListResponse(response.payload['historyLimit4']); historyLimit2 = transformListResponse(response.payload['historyLimit2']); - historyForwardLimit4 = - transformListResponse(response.payload['historyForwardLimit4']); - historyWithStart = - transformListResponse(response.payload['historyWithStart']); + historyForwardLimit4 = transformListResponse( + response.payload['historyForwardLimit4'], + ); + historyWithStart = transformListResponse( + response.payload['historyWithStart'], + ); historyWithStartAndEnd = transformListResponse( response.payload['historyWithStartAndEnd'], ); @@ -307,11 +316,13 @@ void testRestHistory(FlutterDriver Function() getDriver) { testAllPublishedMessages(historyLimit4.reversed.toList()); testAllPublishedMessages(historyLimit2.reversed.toList()); }); - test('queries entries in reverse order with direction set to "forward"', - () { - expect(historyForwardLimit4.length, equals(8)); - testAllPublishedMessages(historyForwardLimit4); - }); + test( + 'queries entries in reverse order with direction set to "forward"', + () { + expect(historyForwardLimit4.length, equals(8)); + testAllPublishedMessages(historyForwardLimit4); + }, + ); test('returns entries created after specified time', () { expect(historyWithStart.length, equals(2)); expect(historyWithStart[0]['name'], equals('history')); @@ -331,7 +342,8 @@ void testRestHistoryWithAuthCallback(FlutterDriver Function() getDriver) { const message = TestControlMessage(TestName.restHistoryWithAuthCallback); late TestControlResponseMessage response; setUpAll( - () async => response = await requestDataForTest(getDriver(), message)); + () async => response = await requestDataForTest(getDriver(), message), + ); test('auth callback is invoked', () { expect(response.payload['authCallbackInvoked'], isTrue); @@ -372,10 +384,12 @@ void testRestPresenceGet(FlutterDriver Function() getDriver) { membersDefault = transformListResponse(response.payload['membersDefault']); membersLimit4 = transformListResponse(response.payload['membersLimit4']); membersLimit2 = transformListResponse(response.payload['membersLimit2']); - membersClientId = - transformListResponse(response.payload['membersClientId']); - membersConnectionId = - transformListResponse(response.payload['membersConnectionId']); + membersClientId = transformListResponse( + response.payload['membersClientId'], + ); + membersConnectionId = transformListResponse( + response.payload['membersConnectionId'], + ); }); group('rest#channels#channel#presence#get', () { @@ -426,8 +440,9 @@ void testRestPresenceHistory(FlutterDriver Function() getDriver) { historyDefault = transformListResponse(response.payload['historyDefault']); historyLimit4 = transformListResponse(response.payload['historyLimit4']); historyLimit2 = transformListResponse(response.payload['historyLimit2']); - historyForwards = - transformListResponse(response.payload['historyForwards']); + historyForwards = transformListResponse( + response.payload['historyForwards'], + ); historyWithStart = transformListResponse( response.payload['historyWithStart'], ).reversed.toList(); diff --git a/test_integration/test_driver/test_implementation/utils.dart b/test_integration/test_driver/test_implementation/utils.dart index 26297d222..ed0ee7d8e 100644 --- a/test_integration/test_driver/test_implementation/utils.dart +++ b/test_integration/test_driver/test_implementation/utils.dart @@ -23,24 +23,20 @@ void checkMessageData(int index, Object? data) { case 6: expect( data, - equals( - { - 'hello': 'ably', - 'items': ['1', 2.2, true] - }, - ), + equals({ + 'hello': 'ably', + 'items': ['1', 2.2, true], + }), ); break; case 7: expect( data, - equals( - [ - {'hello': 'ably'}, - 'ably', - 'realtime' - ], - ), + equals([ + {'hello': 'ably'}, + 'ably', + 'realtime', + ]), ); } } @@ -113,6 +109,6 @@ void checkMessageExtras(Map messageExtras) { } List> transformListResponse(dynamic items) => - List.from(items as List) - .map((t) => t as Map) - .toList(); + List.from( + items as List, + ).map((t) => t as Map).toList(); diff --git a/test_integration/test_driver/tests_abstract.dart b/test_integration/test_driver/tests_abstract.dart index e93ceb773..64417bb4c 100644 --- a/test_integration/test_driver/tests_abstract.dart +++ b/test_integration/test_driver/tests_abstract.dart @@ -5,14 +5,8 @@ import 'package:test/test.dart'; import 'tests_config.dart'; -void runTests({ - bool all = false, - Iterable? testModules, -}) { - final tests = getTestsFor( - all: all, - testModules: testModules, - ); +void runTests({bool all = false, Iterable? testModules}) { + final tests = getTestsFor(all: all, testModules: testModules); late FlutterDriver driver; @@ -32,10 +26,7 @@ void runTests({ for (final testModule in tests.keys) { final testModuleName = EnumToString.convertToString(testModule); - tests[testModule]!.forEach(( - testGroupName, - testFunction, - ) { + tests[testModule]!.forEach((testGroupName, testFunction) { group( 'Module: $testModuleName. Group: $testGroupName. Test: ', () => testFunction(getDriver), diff --git a/test_integration/test_driver/tests_config.dart b/test_integration/test_driver/tests_config.dart index ecf9a293a..ce62f9c82 100644 --- a/test_integration/test_driver/tests_config.dart +++ b/test_integration/test_driver/tests_config.dart @@ -9,56 +9,57 @@ enum TestModules { basicTests, helperTests, rest, realtime, crypto } final _tests = >{ - TestModules.basicTests: { - 'should return Platform and Ably version': testPlatformAndAblyVersion, - 'should provision AppKey': testDemoDependencies, - }, - TestModules.helperTests: { - 'should report unhandled exception': testShouldReportUnhandledException, - }, - TestModules.rest: { - 'should publish': testRestPublish, - 'should publish with tokenRequest': testRestRequestTokenPublish, - 'should publish encrypted': testRestEncryptedPublish, - 'should retrieve history': testRestHistory, - 'should retrieve history with auth callback': - testRestHistoryWithAuthCallback, - 'should retrieve time': testRestTime, - 'conforms to publish spec': testRestPublishSpec, - 'conforms to publish spec when encrypted': testRestEncryptedPublishSpec, - 'should publish with AuthCallback': testRestPublishWithAuthCallback, - 'should get Presence Members': testRestPresenceGet, - 'should get Presence History': testRestPresenceHistory, - 'conforms to capabilitySpec': testCapabilityMatrix, - }, - TestModules.realtime: { - 'should publish': testRealtimePublish, - 'should publish encrypted': testRealtimeEncryptedPublish, - 'conforms to publish spec': testRealtimePublishSpec, - 'conforms to publish spec when encrypted': testRealtimeEncryptedPublishSpec, - 'should subscribe to connection and channel': testRealtimeEvents, - 'should subscribe to messages': testRealtimeSubscribe, - 'should retrieve history': testRealtimeHistory, - 'should retrieve history with auth callback': - testRealtimeHistoryWithAuthCallback, - 'should retrieve time': testRealtimeTime, - 'realtime#channels#channel#presence#get': testRealtimePresenceGet, - 'realtime#channels#channel#presence#history': testRealtimePresenceHistory, - 'should enter, update and leave Presence': testRealtimeEnterUpdateLeave, - 'should subscribe to channel presence': testRealtimePresenceSubscription, - }, - TestModules.crypto: { - 'should generate random crypto key': testCryptoGenerateRandomKey, - 'should validate supported key lengths': testCryptoEnsureSupportedKeyLength, - 'should get default params': testCryptoGetDefaultParams, - } -}; + TestModules.basicTests: { + 'should return Platform and Ably version': testPlatformAndAblyVersion, + 'should provision AppKey': testDemoDependencies, + }, + TestModules.helperTests: { + 'should report unhandled exception': testShouldReportUnhandledException, + }, + TestModules.rest: { + 'should publish': testRestPublish, + 'should publish with tokenRequest': testRestRequestTokenPublish, + 'should publish encrypted': testRestEncryptedPublish, + 'should retrieve history': testRestHistory, + 'should retrieve history with auth callback': + testRestHistoryWithAuthCallback, + 'should retrieve time': testRestTime, + 'conforms to publish spec': testRestPublishSpec, + 'conforms to publish spec when encrypted': testRestEncryptedPublishSpec, + 'should publish with AuthCallback': testRestPublishWithAuthCallback, + 'should get Presence Members': testRestPresenceGet, + 'should get Presence History': testRestPresenceHistory, + 'conforms to capabilitySpec': testCapabilityMatrix, + }, + TestModules.realtime: { + 'should publish': testRealtimePublish, + 'should publish encrypted': testRealtimeEncryptedPublish, + 'conforms to publish spec': testRealtimePublishSpec, + 'conforms to publish spec when encrypted': + testRealtimeEncryptedPublishSpec, + 'should subscribe to connection and channel': testRealtimeEvents, + 'should subscribe to messages': testRealtimeSubscribe, + 'should retrieve history': testRealtimeHistory, + 'should retrieve history with auth callback': + testRealtimeHistoryWithAuthCallback, + 'should retrieve time': testRealtimeTime, + 'realtime#channels#channel#presence#get': testRealtimePresenceGet, + 'realtime#channels#channel#presence#history': + testRealtimePresenceHistory, + 'should enter, update and leave Presence': testRealtimeEnterUpdateLeave, + 'should subscribe to channel presence': + testRealtimePresenceSubscription, + }, + TestModules.crypto: { + 'should generate random crypto key': testCryptoGenerateRandomKey, + 'should validate supported key lengths': + testCryptoEnsureSupportedKeyLength, + 'should get default params': testCryptoGetDefaultParams, + }, + }; Map> - getTestsFor({ - bool all = false, - Iterable? testModules, -}) { +getTestsFor({bool all = false, Iterable? testModules}) { assert(testModules != null || all != false); late Iterable _testModules; if (all) {