diff --git a/.github/actions/setup_build/action.yml b/.github/actions/setup_build/action.yml index 816b28ae7..6790df13e 100644 --- a/.github/actions/setup_build/action.yml +++ b/.github/actions/setup_build/action.yml @@ -9,7 +9,7 @@ inputs: default: 'zulu' flutter-version: description: 'Flutter Version' - default: '3.24.4' + default: '3.27.0' ruby-version: description: 'Ruby Version' default: '3.3' diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index e94e04bd9..bac225eba 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -20,7 +20,7 @@ jobs: - name: Run Tests run: flutter test --coverage - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v5.0.7 + uses: codecov/codecov-action@v5.1.2 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage/lcov.info diff --git a/.gitignore b/.gitignore index 6aa9ac0ff..c41f70456 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,7 @@ local.properties .gradle/ dependency_cache.json + +android/app/google-services2.json + +ios/Runner/Assets.xcassets/LaunchImage.imageset/ diff --git a/VERSION b/VERSION index bb83058ed..9256e2880 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.12 +1.0.13 \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index dbb6882ef..36e73c1cf 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -109,8 +109,8 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:2.0.21" testImplementation "junit:junit:4.13.2" // https://developer.android.com/jetpack/androidx/releases/test/#1.2.0 - coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.3" - implementation(platform("com.google.firebase:firebase-bom:33.6.0")) + coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.4" + implementation(platform("com.google.firebase:firebase-bom:33.7.0")) } configurations.configureEach { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6f3bd592b..917800c61 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -101,7 +101,9 @@ android:foregroundServiceType="connectedDevice" android:stopWithTask="true" /> - + diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png index 7fa40868f..33e1f1662 100644 Binary files a/android/app/src/main/ic_launcher-playstore.png and b/android/app/src/main/ic_launcher-playstore.png differ diff --git a/android/app/src/main/res/drawable-hdpi/android12splash.png b/android/app/src/main/res/drawable-hdpi/android12splash.png index 931886a96..d103ec4b5 100644 Binary files a/android/app/src/main/res/drawable-hdpi/android12splash.png and b/android/app/src/main/res/drawable-hdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-hdpi/ic_notification.png b/android/app/src/main/res/drawable-hdpi/ic_notification.png index 240f9d6ab..0df0327f2 100644 Binary files a/android/app/src/main/res/drawable-hdpi/ic_notification.png and b/android/app/src/main/res/drawable-hdpi/ic_notification.png differ diff --git a/android/app/src/main/res/drawable-hdpi/splash.png b/android/app/src/main/res/drawable-hdpi/splash.png index 931886a96..d103ec4b5 100644 Binary files a/android/app/src/main/res/drawable-hdpi/splash.png and b/android/app/src/main/res/drawable-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-mdpi/android12splash.png b/android/app/src/main/res/drawable-mdpi/android12splash.png index 1c950c1dc..063f84471 100644 Binary files a/android/app/src/main/res/drawable-mdpi/android12splash.png and b/android/app/src/main/res/drawable-mdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_notification.png b/android/app/src/main/res/drawable-mdpi/ic_notification.png index a90047022..440c81ead 100644 Binary files a/android/app/src/main/res/drawable-mdpi/ic_notification.png and b/android/app/src/main/res/drawable-mdpi/ic_notification.png differ diff --git a/android/app/src/main/res/drawable-mdpi/splash.png b/android/app/src/main/res/drawable-mdpi/splash.png index 1c950c1dc..063f84471 100644 Binary files a/android/app/src/main/res/drawable-mdpi/splash.png and b/android/app/src/main/res/drawable-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-night-hdpi/android12splash.png b/android/app/src/main/res/drawable-night-hdpi/android12splash.png index cf5a52547..24fe2ac3b 100644 Binary files a/android/app/src/main/res/drawable-night-hdpi/android12splash.png and b/android/app/src/main/res/drawable-night-hdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-night-hdpi/splash.png b/android/app/src/main/res/drawable-night-hdpi/splash.png index cf5a52547..24fe2ac3b 100644 Binary files a/android/app/src/main/res/drawable-night-hdpi/splash.png and b/android/app/src/main/res/drawable-night-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-night-mdpi/android12splash.png b/android/app/src/main/res/drawable-night-mdpi/android12splash.png index d8ad0684b..bc73c97b1 100644 Binary files a/android/app/src/main/res/drawable-night-mdpi/android12splash.png and b/android/app/src/main/res/drawable-night-mdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-night-mdpi/splash.png b/android/app/src/main/res/drawable-night-mdpi/splash.png index d8ad0684b..bc73c97b1 100644 Binary files a/android/app/src/main/res/drawable-night-mdpi/splash.png and b/android/app/src/main/res/drawable-night-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-night-v21/background.png b/android/app/src/main/res/drawable-night-v21/background.png index 4c1cab129..fbce56fe7 100644 Binary files a/android/app/src/main/res/drawable-night-v21/background.png and b/android/app/src/main/res/drawable-night-v21/background.png differ diff --git a/android/app/src/main/res/drawable-night-xhdpi/android12splash.png b/android/app/src/main/res/drawable-night-xhdpi/android12splash.png index 524ef644b..63be6a344 100644 Binary files a/android/app/src/main/res/drawable-night-xhdpi/android12splash.png and b/android/app/src/main/res/drawable-night-xhdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-night-xhdpi/splash.png b/android/app/src/main/res/drawable-night-xhdpi/splash.png index 524ef644b..63be6a344 100644 Binary files a/android/app/src/main/res/drawable-night-xhdpi/splash.png and b/android/app/src/main/res/drawable-night-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png b/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png index baea7652e..a509cfcb4 100644 Binary files a/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png and b/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-night-xxhdpi/splash.png b/android/app/src/main/res/drawable-night-xxhdpi/splash.png index baea7652e..a509cfcb4 100644 Binary files a/android/app/src/main/res/drawable-night-xxhdpi/splash.png and b/android/app/src/main/res/drawable-night-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png b/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png index f4d7fa63e..523e79423 100644 Binary files a/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png and b/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-night-xxxhdpi/splash.png b/android/app/src/main/res/drawable-night-xxxhdpi/splash.png index f4d7fa63e..523e79423 100644 Binary files a/android/app/src/main/res/drawable-night-xxxhdpi/splash.png and b/android/app/src/main/res/drawable-night-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-night/background.png b/android/app/src/main/res/drawable-night/background.png index 4c1cab129..fbce56fe7 100644 Binary files a/android/app/src/main/res/drawable-night/background.png and b/android/app/src/main/res/drawable-night/background.png differ diff --git a/android/app/src/main/res/drawable-v21/background.png b/android/app/src/main/res/drawable-v21/background.png index 3107d37fa..8e2140480 100644 Binary files a/android/app/src/main/res/drawable-v21/background.png and b/android/app/src/main/res/drawable-v21/background.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/android12splash.png b/android/app/src/main/res/drawable-xhdpi/android12splash.png index 3e5026aa4..e048cf89a 100644 Binary files a/android/app/src/main/res/drawable-xhdpi/android12splash.png and b/android/app/src/main/res/drawable-xhdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_notification.png b/android/app/src/main/res/drawable-xhdpi/ic_notification.png index a11449906..0d5cc3c80 100644 Binary files a/android/app/src/main/res/drawable-xhdpi/ic_notification.png and b/android/app/src/main/res/drawable-xhdpi/ic_notification.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/splash.png b/android/app/src/main/res/drawable-xhdpi/splash.png index 3e5026aa4..e048cf89a 100644 Binary files a/android/app/src/main/res/drawable-xhdpi/splash.png and b/android/app/src/main/res/drawable-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/android12splash.png b/android/app/src/main/res/drawable-xxhdpi/android12splash.png index e6cf932b2..3a2767fb6 100644 Binary files a/android/app/src/main/res/drawable-xxhdpi/android12splash.png and b/android/app/src/main/res/drawable-xxhdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_notification.png b/android/app/src/main/res/drawable-xxhdpi/ic_notification.png index 6e1a64770..0a0f66bd7 100644 Binary files a/android/app/src/main/res/drawable-xxhdpi/ic_notification.png and b/android/app/src/main/res/drawable-xxhdpi/ic_notification.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/splash.png b/android/app/src/main/res/drawable-xxhdpi/splash.png index e6cf932b2..3a2767fb6 100644 Binary files a/android/app/src/main/res/drawable-xxhdpi/splash.png and b/android/app/src/main/res/drawable-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/android12splash.png b/android/app/src/main/res/drawable-xxxhdpi/android12splash.png index ff3733b21..be75147b0 100644 Binary files a/android/app/src/main/res/drawable-xxxhdpi/android12splash.png and b/android/app/src/main/res/drawable-xxxhdpi/android12splash.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png b/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png index f81858fa8..0050b0fd4 100644 Binary files a/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png and b/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/splash.png b/android/app/src/main/res/drawable-xxxhdpi/splash.png index ff3733b21..be75147b0 100644 Binary files a/android/app/src/main/res/drawable-xxxhdpi/splash.png and b/android/app/src/main/res/drawable-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png index 3107d37fa..8e2140480 100644 Binary files a/android/app/src/main/res/drawable/background.png and b/android/app/src/main/res/drawable/background.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index d52f4b941..5f088c9ac 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png index fdf309d04..5b1d1a098 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png index df559469c..e647e99da 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index 6d3b7c5c2..f08cdfc64 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 65d9407ec..5fa061aea 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png index 24fca47c1..822e084a5 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png index 9ce7c13ed..92dc1c1ac 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index 39bdd583b..9ff188edf 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 6cd12cb80..3ab5167d2 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png index 4c2390eb6..fb259206e 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png index ed9826902..edeee826f 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index c86855a56..10c5bf6bc 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 923892fdb..6aae00d23 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png index b1f5ca5bd..fc408102f 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png index 552c4ffa2..343ec92c3 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png index d36ac55a3..fe371a411 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index b42e2a69a..5096454bc 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png index 4b281bdd5..94ae429f9 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png index fb7831194..3eab7c8b3 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png index 51da4b236..4691a7a96 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/assets/dynamic_config.json b/assets/dynamic_config.json index ac45d5601..605b10587 100644 --- a/assets/dynamic_config.json +++ b/assets/dynamic_config.json @@ -1,5 +1,5 @@ { - "sentryTraces": 0.1, - "sentryProfiles": 0.01, + "sentryTraces": 0.5, + "sentryProfiles": 0.1, "sentryReplay": 0 } diff --git a/build.yaml b/build.yaml new file mode 100644 index 000000000..7e57e2bf5 --- /dev/null +++ b/build.yaml @@ -0,0 +1,23 @@ +targets: + $default: + builders: + json_serializable: + options: + # Options configure how source code is generated for every + # `@JsonSerializable`-annotated class in the package. + # + # The default value for each is listed. + any_map: false + checked: false + constructor: "" + create_factory: true + create_field_map: false + create_json_keys: false + create_per_field_to_json: false + create_to_json: true + disallow_unrecognized_keys: false + explicit_to_json: true + field_rename: none + generic_argument_factories: false + ignore_unannotated: false + include_if_null: true \ No newline at end of file diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index 22ced1fee..a29778484 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index c86cf99d6..b448eb994 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index e687d2ab2..f7cb05420 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index 2c3a85c6b..362c3b031 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index 4502d305e..913ba0278 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@2x.png index 60d182332..0bf61e57c 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@3x.png index fde1c944e..94a354391 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-38x38@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 328599ded..15979746b 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index ca518f051..bd946ac3a 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index ca518f051..bd946ac3a 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index ebc01b5ba..d971cc0fb 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@2x.png index 582550ae1..1141c3978 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@3x.png index b42e2a69a..5096454bc 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-64x64@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-68x68@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-68x68@2x.png index 41588c965..bdcff2b7a 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-68x68@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-68x68@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 04c7b62e6..7402043e2 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index dad8bdd34..8ccbfa06c 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-1024x1024@1x.png index 0e277b3e0..702a56425 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@2x.png index 69e5dcd2f..405e95c0e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@3x.png index 1b4510da5..1b972cc2a 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@2x.png index 6af7e9eff..495b71035 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@3x.png index 5c1527162..a57473d1d 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@2x.png index 5d2606b90..0d03a3329 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@3x.png index 3b6bc2750..fbf911887 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-38x38@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@2x.png index c6019cd30..dc0cac984 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@3x.png index aebb7fb47..fe2edc5a4 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@2x.png index aebb7fb47..fe2edc5a4 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@3x.png index e2309f22e..9fe4a1f6b 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@2x.png index 4bf368238..bd8a03cde 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@3x.png index b91634521..515a797ea 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-64x64@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-68x68@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-68x68@2x.png index 7d51431ef..575a46327 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-68x68@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-68x68@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-76x76@2x.png index f7e405916..8062a9124 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-83.5x83.5@2x.png index fe9e45d4d..3c454728f 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Dark-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-1024x1024@1x.png index c0ef72f2d..2add639d1 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-20x20@2x.png index a14ce2d57..f91c0eb83 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-20x20@3x.png index 18a239a01..7afcaff07 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-29x29@2x.png index b0c566e98..c3f8b5d61 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-29x29@3x.png index ba531ce60..69f61cf83 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-38x38@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-38x38@2x.png index aa4f5ab56..12e82bc0d 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-38x38@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-38x38@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-38x38@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-38x38@3x.png index 972cd5de4..49fcee080 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-38x38@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-38x38@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-40x40@2x.png index 021cbf66c..0e4c77ac5 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-40x40@3x.png index d5c8c951e..d36c090ce 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-60x60@2x.png index d5c8c951e..d36c090ce 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-60x60@3x.png index 1e2748b01..b8f9d71c3 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-64x64@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-64x64@2x.png index 98c81821b..fa8af245a 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-64x64@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-64x64@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-64x64@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-64x64@3x.png index 4ea7d9fd3..454f56e68 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-64x64@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-64x64@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-68x68@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-68x68@2x.png index 962306bbb..7f1f12a7d 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-68x68@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-68x68@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-76x76@2x.png index 7bfb59cec..92bc204cc 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-83.5x83.5@2x.png index 9ca0ac3d8..740e4f0cf 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-Tinted-83.5x83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png index 3107d37fa..8e2140480 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png and b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png index 4c1cab129..fbce56fe7 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png and b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png index 1c950c1dc..063f84471 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png index 3e5026aa4..e048cf89a 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png index e6cf932b2..3a2767fb6 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png index d8ad0684b..bc73c97b1 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png index 524ef644b..63be6a344 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png index baea7652e..a509cfcb4 100644 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png differ diff --git a/lib/Backend/Bluetooth/bluetooth_manager_plus.dart b/lib/Backend/Bluetooth/bluetooth_manager_plus.dart index 05d6a7c8a..a269fdb1a 100644 --- a/lib/Backend/Bluetooth/bluetooth_manager_plus.dart +++ b/lib/Backend/Bluetooth/bluetooth_manager_plus.dart @@ -28,16 +28,6 @@ import 'bluetooth_utils.dart'; part 'bluetooth_manager_plus.g.dart'; -StreamSubscription? _onConnectionStateChangedStreamSubscription; -StreamSubscription? _onReadRssiStreamSubscription; -StreamSubscription? _onDiscoveredServicesStreamSubscription; -StreamSubscription? _onCharacteristicReceivedStreamSubscription; -StreamSubscription? _onServicesResetStreamSubscription; -StreamSubscription? _adapterStateStreamSubscription; -StreamSubscription>? _onScanResultsStreamSubscription; -StreamSubscription? _onMtuChanged; -StreamSubscription? _keepAliveStreamSubscription; - final _bluetoothPlusLogger = log.Logger('BluetoothPlus'); ValueNotifier isBluetoothEnabled = ValueNotifier(false); @@ -46,39 +36,165 @@ bool _didInitFlutterBluePlus = false; FlutterBluePlusMockable flutterBluePlus = FlutterBluePlusMockable(); @Riverpod(keepAlive: true) -Future initFlutterBluePlus(InitFlutterBluePlusRef ref) async { - if (_didInitFlutterBluePlus) { - return; +class initFlutterBluePlus extends _$initFlutterBluePlus { + StreamSubscription? _onServicesResetStreamSubscription; + StreamSubscription? _adapterStateStreamSubscription; + + @override + Future build() async { + if (!await getBluetoothPermission(bluetoothLog)) { + ref.invalidateSelf(); + _bluetoothPlusLogger.info("Bluetooth permission not granted"); + return; + } + + _didInitFlutterBluePlus = true; + + await flutterBluePlus.setLogLevel(LogLevel.warning, color: true); + // first, check if bluetooth is supported by your hardware + // Note: The platform is initialized on the first call to any FlutterBluePlus method. + if (await flutterBluePlus.isSupported == false) { + _bluetoothPlusLogger.info("Bluetooth not supported by this device"); + return; + } + + _onServicesResetStreamSubscription = flutterBluePlus.events.onServicesReset.listen((event) async { + _bluetoothPlusLogger.info("${event.device.advName} onServicesReset"); + await event.device.discoverServices(); + }); + // handle bluetooth on & off + // note: for iOS the initial state is typically BluetoothAdapterState.unknown + // note: if you have permissions issues you will get stuck at BluetoothAdapterState.unauthorized + _adapterStateStreamSubscription = flutterBluePlus.adapterState.listen((BluetoothAdapterState state) { + _bluetoothPlusLogger.info(state); + isBluetoothEnabled.value = state == BluetoothAdapterState.on; + }); + ref.watch(_keepGearAwakeProvider); + ref.watch(_mTUChangedProvider); + ref.watch(_onCharacteristicReceivedProvider); + ref.watch(_onConnectionStateChangedProvider); + ref.watch(_onDiscoveredServicesProvider); + ref.watch(_rSSIChangedProvider); + ref.watch(_onScanResultsProvider); + // Shut down bluetooth related things + ref.onDispose(() async { + stopScan(); + //Disconnect any gear + for (var element in flutterBluePlus.connectedDevices) { + await disconnect(element.remoteId.str); + } + await _onServicesResetStreamSubscription?.cancel(); + _onServicesResetStreamSubscription = null; + await _adapterStateStreamSubscription?.cancel(); + _adapterStateStreamSubscription = null; + ref.invalidate(_keepGearAwakeProvider); + ref.invalidate(_mTUChangedProvider); + ref.invalidate(_onCharacteristicReceivedProvider); + ref.invalidate(_onConnectionStateChangedProvider); + ref.invalidate(_onDiscoveredServicesProvider); + ref.invalidate(_rSSIChangedProvider); + ref.invalidate(_onScanResultsProvider); + // Mark all gear disconnected; + ref.read(knownDevicesProvider).forEach( + (key, value) => value.deviceConnectionState.value = ConnectivityState.disconnected, + ); + isBluetoothEnabled.value = false; + _didInitFlutterBluePlus = false; // Allow restarting ble stack + }); + ref.read(scanMonitorProvider); } - if (!await getBluetoothPermission(bluetoothLog)) { - ref.invalidateSelf(); - _bluetoothPlusLogger.info("Bluetooth permission not granted"); - return; +} + +@Riverpod(keepAlive: true) +class _MTUChanged extends _$MTUChanged { + StreamSubscription? streamSubscription; + + @override + void build() { + streamSubscription = flutterBluePlus.events.onMtuChanged.listen(listener); + ref.onDispose( + () => streamSubscription?.cancel(), + ); } - _didInitFlutterBluePlus = true; - await flutterBluePlus.setLogLevel(LogLevel.warning, color: true); - // first, check if bluetooth is supported by your hardware - // Note: The platform is initialized on the first call to any FlutterBluePlus method. - if (await flutterBluePlus.isSupported == false) { - _bluetoothPlusLogger.info("Bluetooth not supported by this device"); - return; + void listener(OnMtuChangedEvent event) { + _bluetoothPlusLogger.info('${event.device.advName} MTU:${event.mtu}'); + BaseStatefulDevice? statefulDevice = ref.read(knownDevicesProvider)[event.device.remoteId.str]; + statefulDevice?.mtu.value = event.mtu; + } +} + +@Riverpod(keepAlive: true) +class _OnDiscoveredServices extends _$OnDiscoveredServices { + StreamSubscription? streamSubscription; + + @override + void build() { + streamSubscription = flutterBluePlus.events.onDiscoveredServices.listen(listener, onError: (e, s) => _bluetoothPlusLogger.warning("Unable to discover services: $e", e, s)); + ref.onDispose( + () => streamSubscription?.cancel(), + ); + } + + Future listener(OnDiscoveredServicesEvent event) async { + //_bluetoothPlusLogger.info('${event.device} ${event.services}'); + //Subscribes to all characteristics + for (BluetoothService service in event.services) { + BluetoothUartService? bluetoothUartService = uartServices.firstWhereOrNull( + (element) => element.bleDeviceService == service.serviceUuid.str, + ); + if (bluetoothUartService != null) { + BaseStatefulDevice? statefulDevice = ref.read(knownDevicesProvider)[event.device.remoteId.str]; + statefulDevice?.bluetoothUartService.value = bluetoothUartService; + } + for (BluetoothCharacteristic characteristic in service.characteristics) { + await characteristic.setNotifyValue(true); + } + } + } +} + +@Riverpod(keepAlive: true) +class _RSSIChanged extends _$RSSIChanged { + StreamSubscription? streamSubscription; + + @override + void build() { + streamSubscription = flutterBluePlus.events.onReadRssi.listen(listener, onError: (e, s) => _bluetoothPlusLogger.warning("Unable to read rssi: $e", e, s)); + ref.onDispose( + () => streamSubscription?.cancel(), + ); + } + + void listener(OnReadRssiEvent event) { + _bluetoothPlusLogger.info('${event.device.advName} RSSI:${event.rssi}'); + BaseStatefulDevice? statefulDevice = ref.read(knownDevicesProvider)[event.device.remoteId.str]; + statefulDevice?.rssi.value = event.rssi; + } +} + +@Riverpod(keepAlive: true) +class _OnConnectionStateChanged extends _$OnConnectionStateChanged { + StreamSubscription? streamSubscription; + + @override + void build() { + streamSubscription = flutterBluePlus.events.onConnectionStateChanged.listen(listener); + ref.onDispose( + () => streamSubscription?.cancel(), + ); } - // listen to *any device* connection state changes - _onConnectionStateChangedStreamSubscription = flutterBluePlus.events.onConnectionStateChanged.listen((event) async { + Future listener(OnConnectionStateChangedEvent event) async { _bluetoothPlusLogger.info('${event.device.advName} ${event.connectionState}'); BuiltMap knownDevices = ref.read(knownDevicesProvider); BluetoothDevice bluetoothDevice = event.device; BluetoothConnectionState bluetoothConnectionState = event.connectionState; String deviceID = bluetoothDevice.remoteId.str; - //final ISentrySpan transaction = Sentry.startTransaction('connectToDevice()', 'task'); BaseDeviceDefinition? deviceDefinition = DeviceRegistry.getByName(bluetoothDevice.advName); if (deviceDefinition == null) { bluetoothLog.warning("Unknown device found: ${bluetoothDevice.advName}"); - //transaction.status = const SpanStatus.notFound(); - //transaction.finish(); return; } @@ -93,16 +209,13 @@ Future initFlutterBluePlus(InitFlutterBluePlusRef ref) async { baseStoredDevice.conModePin = code.toString(); Future(() => ref.read(knownDevicesProvider.notifier).add(statefulDevice)); } - //transaction.setTag('Known Device', 'Yes'); } else { baseStoredDevice = BaseStoredDevice(deviceDefinition.uuid, deviceID, deviceDefinition.deviceType.color(ref: ref).value)..name = getNameFromBTName(deviceDefinition.btName); int code = Random().nextInt(899999) + 100000; baseStoredDevice.conModePin = code.toString(); statefulDevice = BaseStatefulDevice(deviceDefinition, baseStoredDevice); - //transaction.setTag('Known Device', 'No'); Future(() => ref.read(knownDevicesProvider.notifier).add(statefulDevice)); } - //transaction.setTag('Device Name', device.name); statefulDevice.deviceConnectionState.value = event.connectionState == BluetoothConnectionState.connected ? ConnectivityState.connected : ConnectivityState.disconnected; if (bluetoothConnectionState == BluetoothConnectionState.connected) { bluetoothDevice.readRssi().catchError((e) => -1).onError( @@ -138,10 +251,8 @@ Future initFlutterBluePlus(InitFlutterBluePlusRef ref) async { FlutterForegroundTask.startService( notificationTitle: "Gear Connected", notificationText: "Gear is connected to The Tail Company app", - notificationIcon: const NotificationIconData( - resType: ResourceType.drawable, - resPrefix: ResourcePrefix.img, - name: 'tc_logo_transparent_notext_small', + notificationIcon: const NotificationIcon( + metaDataName: 'com.codel1417.tailApp.notificationIcon', ), ); FlutterForegroundTask.setOnLockScreenVisibility(true); @@ -159,7 +270,6 @@ Future initFlutterBluePlus(InitFlutterBluePlusRef ref) async { HiveProxy.put(settings, gearDisconnectCount, count); _bluetoothPlusLogger.finer('Setting gearDisconnectCount to $count'); } - //ref.read(snackbarStreamProvider.notifier).add(SnackBar(content: Text("Disconnected from ${baseStatefulDevice.baseStoredDevice.name}"))); // remove foreground service if no devices connected int deviceCount = knownDevices.values.where((element) => element.deviceConnectionState.value == ConnectivityState.connected).length; @@ -182,39 +292,27 @@ Future initFlutterBluePlus(InitFlutterBluePlusRef ref) async { } } // if the forget button was used, remove the device - if (knownDevices[bluetoothDevice.remoteId.str]!.forgetOnDisconnect) { + if (knownDevices[bluetoothDevice.remoteId.str] != null && knownDevices[bluetoothDevice.remoteId.str]!.forgetOnDisconnect) { _bluetoothPlusLogger.finer('forgetting about gear'); ref.read(knownDevicesProvider.notifier).remove(bluetoothDevice.remoteId.str); } } - }); - _onReadRssiStreamSubscription = flutterBluePlus.events.onReadRssi.listen((event) { - _bluetoothPlusLogger.info('${event.device.advName} RSSI:${event.rssi}'); - BaseStatefulDevice? statefulDevice = ref.read(knownDevicesProvider)[event.device.remoteId.str]; - statefulDevice?.rssi.value = event.rssi; - }, onError: (e, s) => _bluetoothPlusLogger.warning("Unable to read rssi: $e", e, s)); - _onMtuChanged = flutterBluePlus.events.onMtuChanged.listen((event) { - _bluetoothPlusLogger.info('${event.device.advName} MTU:${event.mtu}'); - BaseStatefulDevice? statefulDevice = ref.read(knownDevicesProvider)[event.device.remoteId.str]; - statefulDevice?.mtu.value = event.mtu; - }, onError: (e, s) => _bluetoothPlusLogger.warning("Unable to read mtu: $e", e, s)); - _onDiscoveredServicesStreamSubscription = flutterBluePlus.events.onDiscoveredServices.listen((event) async { - //_bluetoothPlusLogger.info('${event.device} ${event.services}'); - //Subscribes to all characteristics - for (BluetoothService service in event.services) { - BluetoothUartService? bluetoothUartService = uartServices.firstWhereOrNull( - (element) => element.bleDeviceService == service.serviceUuid.str, - ); - if (bluetoothUartService != null) { - BaseStatefulDevice? statefulDevice = ref.read(knownDevicesProvider)[event.device.remoteId.str]; - statefulDevice?.bluetoothUartService.value = bluetoothUartService; - } - for (BluetoothCharacteristic characteristic in service.characteristics) { - await characteristic.setNotifyValue(true); - } - } - }, onError: (e, s) => _bluetoothPlusLogger.warning("Unable to discover services: $e", e, s)); - _onCharacteristicReceivedStreamSubscription = flutterBluePlus.events.onCharacteristicReceived.listen((event) async { + } +} + +@Riverpod(keepAlive: true) +class _OnCharacteristicReceived extends _$OnCharacteristicReceived { + StreamSubscription? streamSubscription; + + @override + void build() { + streamSubscription = flutterBluePlus.events.onCharacteristicReceived.listen(listener); + ref.onDispose( + () => streamSubscription?.cancel(), + ); + } + + Future listener(OnCharacteristicReceivedEvent event) async { _bluetoothPlusLogger.info('onCharacteristicReceived ${event.device.advName} ${event.characteristic.uuid.str} ${event.value}'); BluetoothDevice bluetoothDevice = event.device; @@ -233,8 +331,8 @@ Future initFlutterBluePlus(InitFlutterBluePlusRef ref) async { String value = const Utf8Decoder().convert(values); statefulDevice.messageHistory.add(MessageHistoryEntry(type: MessageHistoryType.receive, message: value)); statefulDevice.batteryCharging.value = value == "CHARGE ON"; - } catch (e, s) { - _bluetoothPlusLogger.warning("Unable to read values: $values", e, s); + } catch (e) { + _bluetoothPlusLogger.warning("Unable to read values: $values", e); statefulDevice.messageHistory.add(MessageHistoryEntry(type: MessageHistoryType.receive, message: "Unknown: ${values.toString()}")); return; } @@ -242,8 +340,8 @@ Future initFlutterBluePlus(InitFlutterBluePlusRef ref) async { String value = ""; try { value = const Utf8Decoder().convert(values); - } catch (e, s) { - _bluetoothPlusLogger.warning("Unable to read values: $values $e", e, s); + } catch (e) { + _bluetoothPlusLogger.warning("Unable to read values: $values $e"); statefulDevice.messageHistory.add(MessageHistoryEntry(type: MessageHistoryType.receive, message: "Unknown: ${values.toString()}")); return; } @@ -287,88 +385,66 @@ Future initFlutterBluePlus(InitFlutterBluePlusRef ref) async { statefulDevice.batteryLevel.value = int.parse(value).toDouble(); } } - }); - _onServicesResetStreamSubscription = flutterBluePlus.events.onServicesReset.listen((event) async { - _bluetoothPlusLogger.info("${event.device.advName} onServicesReset"); - await event.device.discoverServices(); - }); - // handle bluetooth on & off - // note: for iOS the initial state is typically BluetoothAdapterState.unknown - // note: if you have permissions issues you will get stuck at BluetoothAdapterState.unauthorized - _adapterStateStreamSubscription = flutterBluePlus.adapterState.listen((BluetoothAdapterState state) { - _bluetoothPlusLogger.info(state); - isBluetoothEnabled.value = state == BluetoothAdapterState.on; - }); - _onScanResultsStreamSubscription = flutterBluePlus.onScanResults.listen( - (results) async { - if (results.isNotEmpty) { - ScanResult r = results.last; // the most recently found device - _bluetoothPlusLogger.info('${r.device.remoteId}: "${r.advertisementData.advName}" found!'); - BuiltMap knownDevices = ref.read(knownDevicesProvider); - if (knownDevices.containsKey(r.device.remoteId.str) && knownDevices[r.device.remoteId.str]?.deviceConnectionState.value == ConnectivityState.disconnected && !knownDevices[r.device.remoteId.str]!.disableAutoConnect) { - knownDevices[r.device.remoteId.str]?.deviceConnectionState.value = ConnectivityState.connecting; - await connect(r.device.remoteId.str); + } +} + +@Riverpod(keepAlive: true, dependencies: [initFlutterBluePlus]) +class _KeepGearAwake extends _$KeepGearAwake { + StreamSubscription? streamSubscription; + + @override + void build() { + ref.onDispose( + () => streamSubscription?.cancel(), + ); + streamSubscription = Stream.periodic(const Duration(seconds: 15)).listen(listener); + } + + void listener(dynamic event) { + BuiltMap knownDevices = ref.read(knownDevicesProvider); + for (var element in flutterBluePlus.connectedDevices) { + BaseStatefulDevice? device = knownDevices[element.remoteId.str]; + if (device != null) { + device.commandQueue.addCommand(BluetoothMessage(message: "PING", device: device, priority: Priority.low, type: CommandType.system, timestamp: DateTime.now())); + device.commandQueue.addCommand(BluetoothMessage(message: "BATT", device: device, priority: Priority.low, type: CommandType.system, timestamp: DateTime.now())); + element.readRssi().catchError((e) => -1).onError( + (error, stackTrace) => -1, + ); + + if (device.baseDeviceDefinition.deviceType != DeviceType.ears && device.hasGlowtip.value == GlowtipStatus.unknown) { + device.commandQueue.addCommand(BluetoothMessage(message: "VER", device: device, priority: Priority.low, type: CommandType.system, timestamp: DateTime.now())); } } - }, - onError: (e, s) => _bluetoothPlusLogger.severe("", e, s), - ); + } + } +} - _keepAliveStreamSubscription = Stream.periodic(const Duration(seconds: 15)).listen( - (event) async { +@Riverpod(keepAlive: true) +class _OnScanResults extends _$OnScanResults { + StreamSubscription? streamSubscription; + + @override + void build() { + ref.onDispose( + () => streamSubscription?.cancel(), + ); + streamSubscription = flutterBluePlus.onScanResults.listen( + listener, + onError: (e, s) => _bluetoothPlusLogger.severe("", e, s), + ); + } + + Future listener(List results) async { + if (results.isNotEmpty) { + ScanResult r = results.last; // the most recently found device + _bluetoothPlusLogger.info('${r.device.remoteId}: "${r.advertisementData.advName}" found!'); BuiltMap knownDevices = ref.read(knownDevicesProvider); - for (var element in flutterBluePlus.connectedDevices) { - BaseStatefulDevice? device = knownDevices[element.remoteId.str]; - if (device != null) { - device.commandQueue.addCommand(BluetoothMessage(message: "PING", device: device, priority: Priority.low, type: CommandType.system, timestamp: DateTime.now())); - device.commandQueue.addCommand(BluetoothMessage(message: "BATT", device: device, priority: Priority.low, type: CommandType.system, timestamp: DateTime.now())); - element.readRssi().catchError((e) => -1).onError( - (error, stackTrace) => -1, - ); - - if (device.baseDeviceDefinition.deviceType != DeviceType.ears && device.hasGlowtip.value == GlowtipStatus.unknown) { - device.commandQueue.addCommand(BluetoothMessage(message: "VER", device: device, priority: Priority.low, type: CommandType.system, timestamp: DateTime.now())); - } - } + if (knownDevices.containsKey(r.device.remoteId.str) && knownDevices[r.device.remoteId.str]?.deviceConnectionState.value == ConnectivityState.disconnected && !knownDevices[r.device.remoteId.str]!.disableAutoConnect) { + knownDevices[r.device.remoteId.str]?.deviceConnectionState.value = ConnectivityState.connecting; + await connect(r.device.remoteId.str); } - }, - cancelOnError: true, - ); - - // Shut down bluetooth related things - ref.onDispose(() async { - stopScan(); - //Disconnect any gear - for (var element in flutterBluePlus.connectedDevices) { - await disconnect(element.remoteId.str); } - //cancel streams - await _keepAliveStreamSubscription?.cancel(); - _keepAliveStreamSubscription = null; - await _onCharacteristicReceivedStreamSubscription?.cancel(); - _onCharacteristicReceivedStreamSubscription = null; - await _onConnectionStateChangedStreamSubscription?.cancel(); - _onConnectionStateChangedStreamSubscription = null; - await _onDiscoveredServicesStreamSubscription?.cancel(); - _onDiscoveredServicesStreamSubscription = null; - await _onMtuChanged?.cancel(); - _onMtuChanged = null; - await _adapterStateStreamSubscription?.cancel(); - _adapterStateStreamSubscription = null; - await _onScanResultsStreamSubscription?.cancel(); - _onScanResultsStreamSubscription = null; - await _onServicesResetStreamSubscription?.cancel(); - _onServicesResetStreamSubscription = null; - await _onReadRssiStreamSubscription?.cancel(); - _onReadRssiStreamSubscription = null; - // Mark all gear disconnected; - ref.read(knownDevicesProvider).forEach( - (key, value) => value.deviceConnectionState.value = ConnectivityState.disconnected, - ); - isBluetoothEnabled.value = false; - _didInitFlutterBluePlus = false; // Allow restarting ble stack - }); - ref.read(scanMonitorProvider); + } } Future disconnect(String id) async { @@ -423,7 +499,7 @@ enum ScanReason { background, addGear, manual, notScanning } ScanReason _scanReason = ScanReason.notScanning; Future beginScan({required ScanReason scanReason, Duration? timeout}) async { - if (_didInitFlutterBluePlus && !flutterBluePlus.isScanningNow) { + if (_didInitFlutterBluePlus && !flutterBluePlus.isScanningNow && isBluetoothEnabled.value) { _bluetoothPlusLogger.info("Starting scan"); _scanReason = scanReason; await flutterBluePlus.startScan(withServices: DeviceRegistry.getAllIds().map(Guid.new).toList(), continuousUpdates: timeout == null, androidScanMode: AndroidScanMode.lowPower, timeout: timeout); diff --git a/lib/Backend/Definitions/Device/device_definition.dart b/lib/Backend/Definitions/Device/device_definition.dart index 57c086313..319b90cf0 100644 --- a/lib/Backend/Definitions/Device/device_definition.dart +++ b/lib/Backend/Definitions/Device/device_definition.dart @@ -123,12 +123,15 @@ enum DeviceState { standby, runAction, busy } enum GlowtipStatus { glowtip, noGlowtip, unknown } +enum TailControlStatus { tailControl, legacy, unknown } + @freezed class BluetoothUartService with _$BluetoothUartService { const factory BluetoothUartService({ required String bleDeviceService, required String bleRxCharacteristic, required String bleTxCharacteristic, + required String label, }) = _BluetoothUartService; } @@ -137,16 +140,20 @@ final List uartServices = const [ bleDeviceService: "3af2108b-d066-42da-a7d4-55648fa0a9b6", bleRxCharacteristic: "c6612b64-0087-4974-939e-68968ef294b0", bleTxCharacteristic: "5bfd6484-ddee-4723-bfe6-b653372bbfd6", + label: "Legacy Gear", ), BluetoothUartService( bleDeviceService: "927dee04-ddd4-4582-8e42-69dc9fbfae66", bleRxCharacteristic: "0b646a19-371e-4327-b169-9632d56c0e84", bleTxCharacteristic: "05e026d8-b395-4416-9f8a-c00d6c3781b9", + label: "Legacy Ears", ), + // TailCoNTROL uuids BluetoothUartService( - bleDeviceService: "19F8ADE2-D0C6-4C0A-912A-30601D9B3060", - bleRxCharacteristic: "5E4D86AC-EF2F-466F-A857-8776D45FFBC2", - bleTxCharacteristic: "567A99D6-A442-4AC0-B676-4993BF95F805", + bleDeviceService: "19f8ade2-d0c6-4c0a-912a-30601d9b3060", + bleRxCharacteristic: "567a99d6-a442-4ac0-b676-4993bf95f805", + bleTxCharacteristic: "5e4d86ac-ef2f-466f-a857-8776d45ffbc2", + label: "TailCoNTROL", ), ]; @@ -181,6 +188,8 @@ class BaseStatefulDevice { final ValueNotifier gearConfigInfo = ValueNotifier(GearConfigInfo()); final ValueNotifier fwInfo = ValueNotifier(null); final ValueNotifier hasUpdate = ValueNotifier(false); + final ValueNotifier isTailCoNTROL = ValueNotifier(TailControlStatus.unknown); + late final Stream rxCharacteristicStream; late final CommandQueue commandQueue; List batlevels = []; @@ -219,6 +228,22 @@ class BaseStatefulDevice { batlevels.add(FlSpot(stopWatch.elapsed.inSeconds.toDouble(), batteryLevel.value)); batteryLow.value = batteryLevel.value < 20; }); + + bluetoothUartService.addListener( + () { + if (bluetoothUartService.value == null) { + isTailCoNTROL.value = TailControlStatus.unknown; + return; + } + + isTailCoNTROL.value = bluetoothUartService.value == + uartServices.firstWhere( + (element) => element.bleDeviceService.toLowerCase() == "19f8ade2-d0c6-4c0a-912a-30601d9b3060", + ) + ? TailControlStatus.tailControl + : TailControlStatus.legacy; + }, + ); } @override @@ -239,6 +264,8 @@ class BaseStatefulDevice { stopWatch.reset(); mtu.value = -1; mandatoryOtaRequired.value = false; + isTailCoNTROL.value = TailControlStatus.unknown; + bluetoothUartService.value = null; } } diff --git a/lib/Backend/action_registry.dart b/lib/Backend/action_registry.dart index c2b8d5a72..f1bf5afc5 100644 --- a/lib/Backend/action_registry.dart +++ b/lib/Backend/action_registry.dart @@ -1,6 +1,7 @@ import 'package:built_collection/built_collection.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'Bluetooth/bluetooth_manager.dart'; @@ -22,7 +23,7 @@ class ActionRegistry { CommandAction( name: "Slow 1", command: "TAILS1", - deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.calm, response: "TAILS1 END", uuid: "c53e980e-899e-4148-a13e-f57a8f9707f4", @@ -33,7 +34,7 @@ class ActionRegistry { CommandAction( name: "Slow 2", command: "TAILS2", - deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.calm, response: "TAILS2 END", uuid: "eb1bdfe7-d374-4e97-943a-13e89f27ddcd", @@ -44,7 +45,7 @@ class ActionRegistry { CommandAction( name: "Slow 3", command: "TAILS3", - deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.calm, response: "TAILS3 END", uuid: "6937b9af-3ff7-43fb-ae62-a403e5dfaf95", @@ -55,7 +56,7 @@ class ActionRegistry { CommandAction( name: "Fast", command: "TAILFA", - deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.fast, response: "TAILFA END", uuid: "a04b558f-0ad5-410f-8e39-8f5c594791d2", @@ -66,7 +67,7 @@ class ActionRegistry { CommandAction( name: "Short", command: "TAILSH", - deviceCategory: [DeviceType.tail, DeviceType.wings], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.ears], actionCategory: ActionCategory.fast, response: "TAILSH END", uuid: "05a4c47b-45ee-4da8-bec2-4a46f4e04a7f", @@ -77,7 +78,7 @@ class ActionRegistry { CommandAction( name: "Happy", command: "TAILHA", - deviceCategory: [DeviceType.tail, DeviceType.wings], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.ears], actionCategory: ActionCategory.fast, response: "TAILHA END", uuid: "86b13d13-b09c-46ba-a887-b40d8118b00a", @@ -88,7 +89,7 @@ class ActionRegistry { CommandAction( name: "Stand Up", command: "TAILER", - deviceCategory: [DeviceType.tail, DeviceType.wings], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.ears], actionCategory: ActionCategory.fast, response: "TAILER END", uuid: "5b04ca3d-a22a-4aff-8f40-99363248fcaa", @@ -99,7 +100,7 @@ class ActionRegistry { CommandAction( name: "Pulse", command: "TAILEP", - deviceCategory: [DeviceType.tail, DeviceType.wings], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.ears], actionCategory: ActionCategory.tense, response: "TAILEP END", uuid: "39bbe39d-aa92-4189-ac90-4bb821a59f5e", @@ -110,7 +111,7 @@ class ActionRegistry { CommandAction( name: "Tremble 1", command: "TAILT1", - deviceCategory: [DeviceType.tail, DeviceType.wings], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.ears], actionCategory: ActionCategory.tense, response: "TAILT1 END", uuid: "8cc3fc60-b8d2-4f22-810a-1e042d3984f7", @@ -121,7 +122,7 @@ class ActionRegistry { CommandAction( name: "Tremble 2", command: "TAILT2", - deviceCategory: [DeviceType.tail, DeviceType.wings], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.ears], actionCategory: ActionCategory.tense, response: "TAILT2 END", uuid: "123557a2-5489-43da-99e2-da37a36f055a", @@ -132,7 +133,7 @@ class ActionRegistry { CommandAction( name: "Tremble 3", command: "TAILET", - deviceCategory: [DeviceType.tail, DeviceType.wings], + deviceCategory: [DeviceType.tail, DeviceType.wings, DeviceType.ears], actionCategory: ActionCategory.tense, response: "TAILET END", uuid: "4909d4c2-0054-4f16-9589-6273ef6bf6c9", @@ -143,49 +144,49 @@ class ActionRegistry { CommandAction( name: "LEDs off", command: "LEDOFF", - deviceCategory: [DeviceType.tail, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.glowtip, uuid: "6b2a7fae-b58c-43f3-81bf-070aa21c2242", ), CommandAction( name: "Rectangle wave", command: "LEDREC", - deviceCategory: [DeviceType.tail, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.glowtip, uuid: "34269c91-90bd-4a34-851d-d49daa6ac863", ), CommandAction( name: "Triangle wave", command: "LEDTRI", - deviceCategory: [DeviceType.tail, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.glowtip, uuid: "64142e0b-4cc0-4b1e-845f-9c560875f993", ), CommandAction( name: "Sawtooth wave", command: "LEDSAW", - deviceCategory: [DeviceType.tail, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.glowtip, uuid: "047b84ad-3eb8-4d9c-b59b-13186cf965ca", ), CommandAction( name: "SOS", command: "LEDSOS", - deviceCategory: [DeviceType.tail, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.glowtip, uuid: "66164945-840f-4302-b27c-e7a7623bf475", ), CommandAction( name: "Beacon", command: "LEDBEA", - deviceCategory: [DeviceType.tail, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.glowtip, uuid: "4955a936-7703-4ce6-8d4a-b18857c0ea0a", ), CommandAction( name: "Flame", command: "LEDFLA", - deviceCategory: [DeviceType.tail, DeviceType.miniTail], + deviceCategory: [DeviceType.tail, DeviceType.miniTail, DeviceType.ears], actionCategory: ActionCategory.glowtip, uuid: "e46566b4-1071-4866-815b-1aefbf06b573", ), @@ -282,6 +283,9 @@ class GetAvailableActions extends _$GetAvailableActions { baseStatefulDevice.hasGlowtip ..removeListener(_listener) ..addListener(_listener); + baseStatefulDevice.isTailCoNTROL + ..removeListener(_listener) + ..addListener(_listener); } return getState(); } @@ -295,6 +299,21 @@ class GetAvailableActions extends _$GetAvailableActions { for (BaseStatefulDevice baseStatefulDevice in availableGear) { // check if command matches device type if (baseAction.deviceCategory.contains(baseStatefulDevice.baseDeviceDefinition.deviceType) && ((baseAction.actionCategory == ActionCategory.glowtip && baseStatefulDevice.hasGlowtip.value == GlowtipStatus.glowtip) || baseAction.actionCategory != ActionCategory.glowtip)) { + // Handle migrating ears to unified firmware + if (baseAction.deviceCategory.contains(DeviceType.ears) && baseStatefulDevice.baseDeviceDefinition.deviceType == DeviceType.ears) { + if (baseStatefulDevice.isTailCoNTROL.value == TailControlStatus.tailControl) { + // skip legacy moves + if (baseAction is EarsMoveList) { + continue; + } + // skip unified moves for legacy firmware ears + } else if (baseStatefulDevice.isTailCoNTROL.value == TailControlStatus.legacy) { + if (baseAction is CommandAction) { + continue; + } + } + } + // get category if it exists if (sortedActions.containsKey(baseAction.actionCategory)) { baseActions = sortedActions[baseAction.actionCategory]; @@ -321,7 +340,7 @@ class GetAvailableActions extends _$GetAvailableActions { } @Riverpod(keepAlive: true) -BuiltMap> getAllActions(GetAllActionsRef ref) { +BuiltMap> getAllActions(Ref ref) { Map> sortedActions = {}; final BuiltList moveLists = ref.watch(moveListsProvider); final BuiltList audioActions = ref.watch(userAudioActionsProvider); @@ -348,50 +367,7 @@ BuiltMap> getAllActions(GetAllActionsRef re } @Riverpod(keepAlive: true) -BuiltMap> getAllActionsFiltered(GetAllActionsFilteredRef ref, BuiltSet deviceType) { - Map> sortedActions = {}; - final BuiltMap> read = ref.watch(getAllActionsProvider); - for (BaseAction baseAction in read.values.flattened) { - Set? baseActions = {}; - // check if command matches device type - if (baseAction.deviceCategory.toBuiltSet().intersection(deviceType).isNotEmpty) { - // get category if it exists - if (sortedActions.containsKey(baseAction.actionCategory)) { - baseActions = sortedActions[baseAction.actionCategory]; - } - // add action to category - baseActions?.add(baseAction); - } - // store result - if (baseActions != null && baseActions.isNotEmpty) { - sortedActions[baseAction.actionCategory] = baseActions; - } - } - return BuiltMap( - sortedActions.map( - (key, value) => MapEntry(key, value.build()), - ), - ); -} - -@Riverpod(keepAlive: true) -BuiltList getAllActionsForCategory(GetAllActionsForCategoryRef ref, ActionCategory actionCategory) { - final BuiltMap> allActions = ref.watch(getAllActionsProvider); - if (allActions.containsKey(actionCategory)) { - return allActions[actionCategory]!.toBuiltList(); - } - return BuiltList(); -} - -BuiltList splitBaseAction(BaseAction baseAction) { - if (baseAction.deviceCategory.length <= 1) { - return [baseAction].build(); - } - return BuiltList(); -} - -@Riverpod(keepAlive: true) -BaseAction? getActionFromUUID(GetActionFromUUIDRef ref, String? uuid) { +BaseAction? getActionFromUUID(Ref ref, String? uuid) { if (uuid == null) { return null; } diff --git a/lib/Backend/app_shortcuts.dart b/lib/Backend/app_shortcuts.dart index 0cba00e91..53a28ad4e 100644 --- a/lib/Backend/app_shortcuts.dart +++ b/lib/Backend/app_shortcuts.dart @@ -1,5 +1,4 @@ import 'package:built_collection/built_collection.dart'; -import 'package:collection/collection.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quick_actions/quick_actions.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -16,7 +15,7 @@ part 'app_shortcuts.g.dart'; const QuickActions quickActions = QuickActions(); @Riverpod(keepAlive: true) -Future appShortcuts(AppShortcutsRef ref) async { +Future appShortcuts(Ref ref) async { await Future.delayed(const Duration(seconds: 5)); quickActions.initialize((shortcutType) { BaseAction? action = ref.read(getActionFromUUIDProvider(shortcutType)); @@ -35,7 +34,7 @@ Future updateShortcuts(BuiltList favoriteActions, Ref ref) .map( (e) => ref.read(getActionFromUUIDProvider(e.actionUUID)), ) - .whereNotNull(); + .nonNulls; quickActions.setShortcutItems( allActions diff --git a/lib/Backend/device_registry.dart b/lib/Backend/device_registry.dart index 8d909f810..abe269c41 100644 --- a/lib/Backend/device_registry.dart +++ b/lib/Backend/device_registry.dart @@ -1,5 +1,6 @@ import 'package:built_collection/built_collection.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logging/logging.dart' as log; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -32,7 +33,7 @@ class DeviceRegistry { uuid: "5fb21175-fef4-448a-a38b-c472d935abab", btName: "minitail", deviceType: DeviceType.miniTail, - fwURL: "https://thetailcompany.com/fw/mini", + fwURL: "https://thetailcompany.com/fw/mini.json", minVersion: Version(major: 5, minor: 0, patch: 0), ), BaseDeviceDefinition( @@ -74,7 +75,7 @@ class DeviceRegistry { } @Riverpod(keepAlive: true) -BuiltSet getByAction(GetByActionRef ref, BaseAction baseAction) { +BuiltSet getByAction(Ref ref, BaseAction baseAction) { deviceRegistryLogger.info("Getting devices for action::$baseAction"); Set foundDevices = {}; final BuiltList watch = ref.watch(getAvailableIdleGearProvider); @@ -109,7 +110,7 @@ class GetAvailableIdleGear extends _$GetAvailableIdleGear { } @Riverpod(keepAlive: true) -BuiltSet getAvailableGearTypes(GetAvailableGearTypesRef ref) { +BuiltSet getAvailableGearTypes(Ref ref) { final BuiltList watch = ref.watch(getAvailableGearProvider); return watch .map( @@ -119,13 +120,13 @@ BuiltSet getAvailableGearTypes(GetAvailableGearTypesRef ref) { } @Riverpod(keepAlive: true) -BuiltList getAvailableIdleGearForAction(GetAvailableIdleGearForActionRef ref, BaseAction baseAction) { +BuiltList getAvailableIdleGearForAction(Ref ref, BaseAction baseAction) { final BuiltList watch = ref.watch(getAvailableIdleGearProvider); return watch.where((element) => baseAction.deviceCategory.contains(element.baseDeviceDefinition.deviceType)).toBuiltList(); } @Riverpod(keepAlive: true) -BuiltList getAvailableIdleGearForType(GetAvailableIdleGearForTypeRef ref, BuiltSet deviceTypes) { +BuiltList getAvailableIdleGearForType(Ref ref, BuiltSet deviceTypes) { final Iterable watch = ref.watch(getAvailableIdleGearProvider); return watch .where( @@ -135,7 +136,7 @@ BuiltList getAvailableIdleGearForType(GetAvailableIdleGearFo } @Riverpod(keepAlive: true) -BuiltList getAvailableGearForType(GetAvailableGearForTypeRef ref, BuiltSet deviceTypes) { +BuiltList getAvailableGearForType(Ref ref, BuiltSet deviceTypes) { final BuiltList watch = ref.watch(getAvailableGearProvider); return watch .where( @@ -145,7 +146,7 @@ BuiltList getAvailableGearForType(GetAvailableGearForTypeRef } @Riverpod(keepAlive: true) -BuiltList getKnownGearForType(GetKnownGearForTypeRef ref, BuiltSet deviceTypes) { +BuiltList getKnownGearForType(Ref ref, BuiltSet deviceTypes) { final BuiltMap watch = ref.watch(knownDevicesProvider); return watch.values .where( @@ -197,7 +198,7 @@ class GetAvailableGear extends _$GetAvailableGear { } @Riverpod(keepAlive: true) -bool isAllKnownGearConnected(IsAllKnownGearConnectedRef ref) { +bool isAllKnownGearConnected(Ref ref) { var knownGear = ref.watch(knownDevicesProvider); BuiltList connectedGear = ref.watch(getAvailableGearProvider); return knownGear.length == connectedGear.length; diff --git a/lib/Backend/firmware_update.dart b/lib/Backend/firmware_update.dart index cd975bf48..b14fa03e7 100644 --- a/lib/Backend/firmware_update.dart +++ b/lib/Backend/firmware_update.dart @@ -1,15 +1,15 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:isolate'; import 'package:collection/collection.dart'; import 'package:crypto/crypto.dart'; import 'package:dio/dio.dart'; -import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:logging/logging.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:tail_app/Backend/plausible_dio.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; @@ -39,7 +39,7 @@ class FWInfo with _$FWInfo { } @Riverpod(keepAlive: true) -Future?> getBaseFirmwareInfo(GetBaseFirmwareInfoRef ref, String url) async { +Future?> getBaseFirmwareInfo(Ref ref, String url) async { Dio dio = await initDio(); Future> valueFuture = dio.get(url, options: Options(responseType: ResponseType.json)) ..onError((error, stackTrace) { @@ -58,7 +58,7 @@ Future?> getBaseFirmwareInfo(GetBaseFirmwareInfoRef ref, String url } @Riverpod() -Future getFirmwareInfo(GetFirmwareInfoRef ref, String url, String hwVer) async { +Future getFirmwareInfo(Ref ref, String url, String hwVer) async { if (url.isEmpty || hwVer.isEmpty) { return null; } @@ -88,7 +88,7 @@ Future getFirmwareInfo(GetFirmwareInfoRef ref, String url, String hwVer } @Riverpod() -Future checkForFWUpdate(CheckForFWUpdateRef ref, BaseStatefulDevice baseStatefulDevice) async { +Future checkForFWUpdate(Ref ref, BaseStatefulDevice baseStatefulDevice) async { if (baseStatefulDevice.fwInfo.value != null) { return baseStatefulDevice.fwInfo.value; } @@ -107,7 +107,7 @@ Future checkForFWUpdate(CheckForFWUpdateRef ref, BaseStatefulDevice bas } @Riverpod() -Future hasOtaUpdate(HasOtaUpdateRef ref, BaseStatefulDevice baseStatefulDevice) async { +Future hasOtaUpdate(Ref ref, BaseStatefulDevice baseStatefulDevice) async { FWInfo? fwInfo = await ref.read(checkForFWUpdateProvider(baseStatefulDevice).future); Version fwVersion = baseStatefulDevice.fwVersion.value; @@ -190,6 +190,7 @@ class OtaUpdater { Timer? _reconnectTimer; Timer? _finalTimer; final Logger _otaLogger = Logger('otaLogger'); + ISentrySpan? transaction; void setManualOtaFile(List? bytes) { if (bytes == null) { @@ -202,8 +203,9 @@ class OtaUpdater { downloadProgress = 1; } - void _onError(OtaError error) { + void _onError(OtaError error, ISentrySpan? span) { otaState = OtaState.error; + span?.status = SpanStatus.fromString(error.name); if (onError != null) { onError!(error); } @@ -231,8 +233,16 @@ class OtaUpdater { } Future beginUpdate() async { + transaction = Sentry.startTransaction('beginUpdate()', 'task'); + transaction?.setData("Gear Model", baseStatefulDevice.baseDeviceDefinition.btName); + transaction?.setData("Current FW Version", baseStatefulDevice.fwVersion.value.toString()); + transaction?.setData("Hardware Version", baseStatefulDevice.hwVersion.value); + transaction?.setData("Target Firmware Version", baseStatefulDevice.fwInfo.value?.version); + if (baseStatefulDevice.batteryLevel.value < 50) { otaState = OtaState.lowBattery; + transaction?.status = SpanStatus.fromString("lowBattery"); + transaction?.finish(); return; } WakelockPlus.enable(); @@ -248,6 +258,7 @@ class OtaUpdater { if (firmwareInfo == null) { return; } + final ISentrySpan? downloadSpan = transaction?.startChild('downloadFirmware()', description: 'operation'); otaState = OtaState.download; downloadProgress = 0; _updateProgress(); @@ -267,12 +278,14 @@ class OtaUpdater { if (digest.toString() == firmwareInfo!.md5sum) { firmwareFile = rs.data; } else { - _onError(OtaError.md5Mismatch); + _onError(OtaError.md5Mismatch, downloadSpan); } } } catch (e) { - _onError(OtaError.downloadFailed); + downloadSpan?.throwable = e; + _onError(OtaError.downloadFailed, downloadSpan); } + downloadSpan?.finish(); } Future _verListener() async { @@ -281,10 +294,13 @@ class OtaUpdater { if (fwInfo != null && version.compareTo(const Version()) > 0 && otaState == OtaState.rebooting) { bool updated = version.compareTo(getVersionSemVer(fwInfo.version)) >= 0; if (!updated) { - _onError(OtaError.gearVersionMismatch); + _onError(OtaError.gearVersionMismatch, transaction); } else { otaState = OtaState.completed; } + if (transaction != null && !transaction!.finished) { + transaction?.finish(); + } } } @@ -301,7 +317,8 @@ class OtaUpdater { const Duration(seconds: 30), () { _otaLogger.warning("Gear did not reconnect"); - _onError(OtaError.gearReconnectTimeout); + _onError(OtaError.gearReconnectTimeout, transaction); + transaction?.finish(); }, ); } else if (connectivityState == ConnectivityState.connected) { @@ -311,6 +328,7 @@ class OtaUpdater { } Future _uploadFirmware() async { + final ISentrySpan? uploadSpan = transaction?.startChild('uploadFirmware()', description: 'operation'); otaState = OtaState.upload; uploadProgress = 0; if (firmwareFile != null) { @@ -322,11 +340,11 @@ class OtaUpdater { _otaLogger.info("Send OTA begin message"); List beginOTA = List.from(const Utf8Encoder().convert("OTA ${firmwareFile!.length} $downloadedMD5")); await sendMessage(baseStatefulDevice, beginOTA); - + uploadSpan?.setData("Gear MTU", mtu); while (uploadProgress < 1 && otaState != OtaState.error) { baseStatefulDevice.deviceState.value = DeviceState.busy; // hold the command queue if (baseStatefulDevice.gearReturnedError.value) { - _onError(OtaError.gearReturnedError); + _onError(OtaError.gearReturnedError, uploadSpan); break; } @@ -337,8 +355,9 @@ class OtaUpdater { } catch (e, s) { _otaLogger.severe("Exception during ota upload:$e", e, s); if ((currentFirmwareUploadPosition + chunk.length) / firmwareFile!.length < 0.99) { - _onError(OtaError.uploadFailed); - + _onError(OtaError.uploadFailed, uploadSpan); + uploadSpan?.throwable = e; + uploadSpan?.finish(); return; } } @@ -353,7 +372,6 @@ class OtaUpdater { if (uploadProgress == 1) { _otaLogger.info("File Uploaded"); otaState = OtaState.rebooting; - //TODO: check if gear disconnects beginScan( scanReason: ScanReason.manual, timeout: const Duration(seconds: 60), @@ -363,7 +381,8 @@ class OtaUpdater { const Duration(seconds: 30), () { _otaLogger.warning("Gear did not disconnect"); - _onError(OtaError.gearDisconnectTimeout); + _onError(OtaError.gearDisconnectTimeout, transaction); + transaction?.finish(); }, ); // start scanning for the gear to reconnect @@ -372,7 +391,8 @@ class OtaUpdater { () { if (otaState != OtaState.completed) { _otaLogger.warning("Gear did not return correct version after reboot"); - _onError(OtaError.gearOtaFinalTimeout); + _onError(OtaError.gearOtaFinalTimeout, transaction); + transaction?.finish(); } }, ); @@ -380,6 +400,7 @@ class OtaUpdater { } baseStatefulDevice.deviceState.value = DeviceState.standby; // release the command queue } + uploadSpan?.finish(); } OtaUpdater({this.onProgress, this.onStateChanged, required this.baseStatefulDevice, this.onError}) { @@ -398,6 +419,9 @@ class OtaUpdater { if (!HiveProxy.getOrDefault(settings, alwaysScanning, defaultValue: alwaysScanningDefault)) { unawaited(stopScan()); } + if (transaction != null && !transaction!.finished) { + transaction?.finish(status: SpanStatus.aborted()); + } } void _cancelTimers() { @@ -406,36 +430,3 @@ class OtaUpdater { _finalTimer?.cancel(); } } - -@pragma('vm:entry-point') -Future updaterIsolate({required String macAddress, required String service, required String txCharacteristic, required List firmwareFile, required String md5Hash, required SendPort port}) async { - BluetoothDevice? bluetoothDevice = FlutterBluePlus.connectedDevices.where((element) => element.remoteId.str == macAddress).firstOrNull; - if (bluetoothDevice == null) { - return; - } - BluetoothCharacteristic? bluetoothCharacteristic = bluetoothDevice.servicesList.firstWhereOrNull((element) => element.uuid == Guid(service))?.characteristics.firstWhereOrNull((element) => element.characteristicUuid == Guid(txCharacteristic)); - if (bluetoothCharacteristic == null) { - return; - } - List beginOTA = List.from(const Utf8Encoder().convert("OTA ${firmwareFile.length} $md5Hash")); - await bluetoothCharacteristic.write(beginOTA); - int current = 0; - double uploadProgress = 0; - - List chunk = firmwareFile.skip(current).take(bluetoothDevice.mtuNow).toList(); - if (chunk.isNotEmpty) { - try { - await bluetoothCharacteristic.write(chunk); - } catch (e, s) { - if ((current + chunk.length) / firmwareFile.length < 0.99) { - port.send("Error"); - return; - } - } - current = current + chunk.length; - } else { - current = firmwareFile.length; - } - uploadProgress = current / firmwareFile.length; - port.send(uploadProgress); -} diff --git a/lib/Backend/move_lists.dart b/lib/Backend/move_lists.dart index 5a8f5ee4c..2e2768393 100644 --- a/lib/Backend/move_lists.dart +++ b/lib/Backend/move_lists.dart @@ -182,6 +182,7 @@ class MoveLists extends _$MoveLists { } } +//TODO: move the core running moves OUT of move_lists Future runAction(BaseAction action, BaseStatefulDevice device) async { //cursed handling of ears specifically //TODO: Remove with TAILCoNTROL update @@ -213,7 +214,7 @@ Future runAction(BaseAction action, BaseStatefulDevice device) async { } else if (action is MoveList) { sequencesLogger.info("Starting MoveList ${action.name}."); //plausible.event(name: "Run Sequence", props: {"Sequence Repeat": action.repeat.toInt().toString(), "Sequence Device Type": device.baseDeviceDefinition.deviceType.name, "Sequence Moves": action.moves.length.toString()}); - if (action.moves.isNotEmpty && action.moves.length <= 5 && device.baseDeviceDefinition.deviceType != DeviceType.ears) { + if (action.moves.isNotEmpty && action.moves.length <= 5 && (device.baseDeviceDefinition.deviceType != DeviceType.ears || device.isTailCoNTROL.value == TailControlStatus.tailControl)) { int preset = 1; //TODO: store String cmd = "USERMOVE U${preset}P${action.moves.length}N${action.repeat.toInt()}"; String a = ''; // servo 1 position @@ -282,14 +283,14 @@ List generateMoveCommand(Move move, BaseStatefulDevice device, List commands = []; if (move.moveType == MoveType.home) { //TODO: Remove for TAILCoNTROL update - if (device.baseDeviceDefinition.deviceType == DeviceType.ears) { + if (device.baseDeviceDefinition.deviceType == DeviceType.ears && device.isTailCoNTROL.value != TailControlStatus.tailControl) { commands.add(BluetoothMessage(message: "EARHOME", device: device, priority: priority, responseMSG: noResponseMsg ? null : "EARHOME END", type: type, timestamp: DateTime.now())); } else { commands.add(BluetoothMessage(message: "TAILHM", device: device, priority: priority, responseMSG: noResponseMsg ? null : "END TAILHM", type: type, timestamp: DateTime.now())); } } else if (move.moveType == MoveType.move) { //TODO: Remove for TAILCoNTROL update - if (device.baseDeviceDefinition.deviceType == DeviceType.ears) { + if (device.baseDeviceDefinition.deviceType == DeviceType.ears && device.isTailCoNTROL.value != TailControlStatus.tailControl) { commands ..add( BluetoothMessage( diff --git a/lib/Backend/sensors.dart b/lib/Backend/sensors.dart index 18de47079..d4f109a87 100644 --- a/lib/Backend/sensors.dart +++ b/lib/Backend/sensors.dart @@ -205,7 +205,7 @@ abstract class TriggerDefinition extends ChangeNotifier implements Comparable allActionsMapped = triggerAction.actions.map((element) => ref.read(getActionFromUUIDProvider(element))).whereNotNull().toList(); + final List allActionsMapped = triggerAction.actions.map((element) => ref.read(getActionFromUUIDProvider(element))).nonNulls.toList(); // no moves exist if (allActionsMapped.isEmpty) { @@ -217,7 +217,13 @@ abstract class TriggerDefinition extends ChangeNotifier implements Comparable actionsToRun = []; - + // we need to handle legacy ears for now + bool hasLegacyEars = ref + .read(getAvailableIdleGearForTypeProvider([DeviceType.ears].toBuiltSet())) + .where( + (p0) => p0.isTailCoNTROL.value == TailControlStatus.legacy, + ) + .isNotEmpty; // add a glowtip action if it exists if (glowActions.isNotEmpty) { final BaseAction glowAction = glowActions[_random.nextInt(glowActions.length)]; @@ -234,16 +240,36 @@ abstract class TriggerDefinition extends ChangeNotifier implements Comparable missingGearAction = baseAction.deviceCategory.toSet().difference(baseAction.deviceCategory.toSet()); - final List remainingActions = moveActions - .where( - // Check if any actions contain the device type of the gear the first action is missing - (element) => element.deviceCategory.toSet().intersection(missingGearAction).isNotEmpty, + final Set missingGearAction = baseAction.deviceCategory + .whereNot( + // filtering out the first actions ears entry if its a unified move but legacy gear is connected + (element) => DeviceType.ears == element && baseAction is CommandAction && hasLegacyEars, ) - .toList(); + .toSet() + .difference(flattenedDeviceTypes); + final List remainingActions = moveActions.where( + // Check if any actions contain the device type of the gear the first action is missing + (element) { + if (baseAction is CommandAction && missingGearAction.contains(DeviceType.ears)) { + if (element is EarsMoveList) { + return true; + } else if (element is CommandAction) { + return false; + } + } else if (baseAction is EarsMoveList && missingGearAction.contains(DeviceType.ears)) { + if (element is CommandAction) { + return true; + } else if (element is EarsMoveList) { + return false; + } + } + return element.deviceCategory.toSet().intersection(missingGearAction).isNotEmpty; + }, + ).toList(); if (remainingActions.isNotEmpty) { final BaseAction otherAction = remainingActions[_random.nextInt(remainingActions.length)]; actionsToRun.add(otherAction); @@ -265,6 +291,12 @@ abstract class TriggerDefinition extends ChangeNotifier implements Comparable>? _contextStreamSubscription; final _watch = WatchConnectivity(); @Riverpod(keepAlive: true) -Future initWear(InitWearRef ref) async { +Future initWear(Ref ref) async { await Future.delayed(const Duration(seconds: 5)); try { // Get the state of device connectivity @@ -33,7 +35,7 @@ Future initWear(InitWearRef ref) async { (event) => _wearLogger.info("Watch Context: $event"), ); - ref.read(updateWearActionsProvider); + //ref.read(updateWearActionsProvider); } catch (e, s) { _wearLogger.severe("exception setting up Wear $e", e, s); } @@ -64,7 +66,10 @@ Future> applicationContext() { } @Riverpod() -Future updateWearActions(UpdateWearActionsRef ref) async { +Future updateWearActions(Ref ref) async { + if (await isWear()) { + return; + } try { Iterable allActions = ref .read(favoriteActionsProvider) @@ -78,8 +83,8 @@ Future updateWearActions(UpdateWearActionsRef ref) async { final List triggersMap = triggers.map((e) => WearTriggerData(uuid: e.uuid, name: e.triggerDefinition!.name, enabled: e.enabled)).toList(); final WearData wearData = WearData(favoriteActions: favoriteMap, configuredTriggers: triggersMap, uiColor: HiveProxy.getOrDefault(settings, appColor, defaultValue: appColorDefault)); - if (await _watch.isReachable) { - //await _watch.updateApplicationContext(wearData.toJson()); + if (await isReachable()) { + await _watch.updateApplicationContext(wearData.toJson()); } } catch (e, s) { _wearLogger.severe("Unable to send favorite actions to watch", e, s); diff --git a/lib/Frontend/Widgets/manage_gear.dart b/lib/Frontend/Widgets/manage_gear.dart index ef500db4b..25f92f655 100644 --- a/lib/Frontend/Widgets/manage_gear.dart +++ b/lib/Frontend/Widgets/manage_gear.dart @@ -409,7 +409,6 @@ class _ManageGearDebugState extends State { Text("UNSUPPORTED: ${widget.device.baseDeviceDefinition.unsupported}"), Text("MIN FIRMWARE: ${widget.device.baseDeviceDefinition.minVersion}"), Text("NVS Config: ${widget.device.gearConfigInfo.value}"), - Text("UART Service: ${widget.device.bluetoothUartService.value}"), ], ), ), @@ -582,6 +581,44 @@ class _ManageGearDebugState extends State { .toList(), ), ), + ListTile( + title: const Text("isTailCoNTROL"), + trailing: DropdownMenu( + initialSelection: widget.device.isTailCoNTROL.value, + onSelected: (value) { + if (value != null) { + setState( + () { + widget.device.isTailCoNTROL.value = value; + }, + ); + } + }, + dropdownMenuEntries: TailControlStatus.values + .map( + (e) => DropdownMenuEntry(value: e, label: e.name), + ) + .toList(), + ), + ), + ListTile( + title: const Text("bluetoothUartService"), + trailing: DropdownMenu( + initialSelection: widget.device.bluetoothUartService.value, + onSelected: (value) { + setState( + () { + widget.device.bluetoothUartService.value = value; + }, + ); + }, + dropdownMenuEntries: uartServices + .map( + (e) => DropdownMenuEntry(value: e, label: e.label), + ) + .toList(), + ), + ), ListTile( title: const Text("RSSI Level"), subtitle: Slider( diff --git a/lib/Frontend/Widgets/tail_blog.dart b/lib/Frontend/Widgets/tail_blog.dart index 0c80fb49b..eb38f7af9 100644 --- a/lib/Frontend/Widgets/tail_blog.dart +++ b/lib/Frontend/Widgets/tail_blog.dart @@ -164,13 +164,13 @@ class _TailBlogState extends State { } } } - if (mounted && context.mounted && results.isNotEmpty) { + if (mounted && context.mounted) { setState(() { - feedState = FeedState.loaded; - }); - } else if (context.mounted) { - setState(() { - feedState = FeedState.error; + if (results.isNotEmpty) { + feedState = FeedState.loaded; + } else { + feedState = FeedState.error; + } }); } } @@ -245,7 +245,7 @@ class _TailBlogImageState extends ConsumerState { } @Riverpod(keepAlive: true) -Future getBlogImage(GetBlogImageRef ref, String url) async { +Future getBlogImage(Ref ref, String url) async { if (!await tailBlogConnectivityCheck()) { return Container(); } diff --git a/lib/Frontend/pages/action_selector.dart b/lib/Frontend/pages/action_selector.dart index 9fa22c9db..69d064d7e 100644 --- a/lib/Frontend/pages/action_selector.dart +++ b/lib/Frontend/pages/action_selector.dart @@ -125,7 +125,7 @@ class _ActionSelectorState extends ConsumerState { tileMode: TileMode.clamp, ), ), - child: ButtonBar( + child: OverflowBar( alignment: MainAxisAlignment.center, children: [ FilledButton( diff --git a/lib/Frontend/pages/actions.dart b/lib/Frontend/pages/actions.dart index d5a0b89f3..00bc4c419 100644 --- a/lib/Frontend/pages/actions.dart +++ b/lib/Frontend/pages/actions.dart @@ -56,7 +56,14 @@ class _ActionPageBuilderState extends ConsumerState { //TODO: Remove for TAILCoNTROL update AnimatedSwitcher( duration: animationTransitionDuration, - child: ref.watch(getAvailableGearForTypeProvider(BuiltSet([DeviceType.ears]))).isNotEmpty ? const EarSpeedWidget() : null, + child: ref + .watch(getAvailableGearForTypeProvider(BuiltSet([DeviceType.ears]))) + .where( + (p0) => p0.isTailCoNTROL.value == TailControlStatus.legacy, + ) + .isNotEmpty + ? const EarSpeedWidget() + : null, ), AnimatedCrossFade( firstChild: PageInfoCard( @@ -174,7 +181,7 @@ class _ActionCardState extends ConsumerState { children: [ // Shows when an action is in progress AnimatedCrossFade( - firstChild: Container(), + firstChild: Center(child: Container()), secondChild: const Center(child: CircularProgressIndicator()), crossFadeState: ref.watch(isGearMoveRunningProvider(widget.action.deviceCategory.toBuiltSet())) ? CrossFadeState.showSecond : CrossFadeState.showFirst, alignment: Alignment.center, @@ -186,6 +193,25 @@ class _ActionCardState extends ConsumerState { child: Row( children: ref .watch(getAvailableGearForTypeProvider(widget.action.deviceCategory.toBuiltSet())) + .where( + (baseStatefulDevice) { + //TODO: remove after tailcontrol migration period + if (widget.action.deviceCategory.contains(DeviceType.ears) && baseStatefulDevice.baseDeviceDefinition.deviceType == DeviceType.ears) { + if (baseStatefulDevice.isTailCoNTROL.value == TailControlStatus.tailControl) { + // skip legacy moves + if (widget.action is EarsMoveList) { + return false; + } + // skip unified moves for legacy firmware ears + } else if (baseStatefulDevice.isTailCoNTROL.value == TailControlStatus.legacy) { + if (widget.action is CommandAction) { + return false; + } + } + } + return true; + }, + ) .map( (e) => Card( color: Color(e.baseStoredDevice.color), diff --git a/lib/Frontend/pages/home.dart b/lib/Frontend/pages/home.dart index 17f303c95..f39dad607 100644 --- a/lib/Frontend/pages/home.dart +++ b/lib/Frontend/pages/home.dart @@ -85,7 +85,7 @@ class _HomeState extends ConsumerState { title: Text(homeWelcomeMessageTitle()), subtitle: Text(homeWelcomeMessage()), ), - ButtonBar( + OverflowBar( children: [ TextButton( onPressed: () async { diff --git a/lib/Frontend/pages/intro.dart b/lib/Frontend/pages/intro.dart index 5333904c9..c82151f5c 100644 --- a/lib/Frontend/pages/intro.dart +++ b/lib/Frontend/pages/intro.dart @@ -110,7 +110,7 @@ class OnBoardingPageState extends ConsumerState { asset: Assets.tailcostickers.tailCoStickersFile144834359, width: MediaQuery.of(context).size.width, ), - footer: ButtonBar( + footer: OverflowBar( alignment: MainAxisAlignment.center, children: [ ElevatedButton( @@ -154,7 +154,7 @@ class OnBoardingPageState extends ConsumerState { asset: Assets.tailcostickers.tailCoStickersFile144834357, width: MediaQuery.of(context).size.width, ), - footer: ButtonBar( + footer: OverflowBar( alignment: MainAxisAlignment.center, children: [ FilledButton( diff --git a/lib/Frontend/pages/settings.dart b/lib/Frontend/pages/settings.dart index 347409315..e74e3f208 100644 --- a/lib/Frontend/pages/settings.dart +++ b/lib/Frontend/pages/settings.dart @@ -41,18 +41,33 @@ class _SettingsState extends ConsumerState { title: Text( settingsAppColor(), ), - trailing: ColorIndicator( - width: 44, - height: 44, - borderRadius: 22, - color: appColorValue, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (HiveProxy.getOrDefault(settings, appColor, defaultValue: appColorDefault) != appColorDefault) ...[ + IconButton( + onPressed: () { + setState(() { + HiveProxy.put(settings, appColor, appColorDefault); + appColorValue = Color(appColorDefault); + }); + }, + icon: Icon(Icons.clear)), + ], + ColorIndicator( + width: 44, + height: 44, + borderRadius: 22, + color: appColorValue, + ) + ], ), onTap: () async { ColorPickerRoute(defaultColor: appColorValue.value).push(context).then( (color) => setState(() { if (color != null) { HiveProxy.put(settings, appColor, color); - appColorValue = color; + appColorValue = Color(color); } }), ); diff --git a/lib/Frontend/pages/triggers.dart b/lib/Frontend/pages/triggers.dart index 891bc2e19..ba6fedec4 100644 --- a/lib/Frontend/pages/triggers.dart +++ b/lib/Frontend/pages/triggers.dart @@ -342,7 +342,7 @@ class _TriggerEditState extends ConsumerState { .map( (e) => ref.read(getActionFromUUIDProvider(e)), ) - .whereNotNull() + .nonNulls .toList(), ), ), @@ -370,7 +370,7 @@ class _TriggerEditState extends ConsumerState { ), ), ), - ButtonBar( + OverflowBar( children: [ TextButton( onPressed: () async { diff --git a/lib/l10n/messages_de_CH.arb b/lib/l10n/messages_de_CH.arb index 1a693020f..20cf99792 100644 --- a/lib/l10n/messages_de_CH.arb +++ b/lib/l10n/messages_de_CH.arb @@ -1046,5 +1046,107 @@ "description": "Description for the tail blog wifi only setting", "type": "text", "placeholders": {} + }, + "manageGearConModePincodeEnableDescription": "Wenn du den 'Convention Mode' aktivierst, wird dis Gesr rebootet und du wirsch drum gebeten, de Pincode ii z'geh. De Pincode wird uf d’Zwischäboard kopier", + "@manageGearConModePincodeEnableDescription": { + "description": "The description for the pin mode button on the gear page", + "type": "text", + "placeholders": {} + }, + "otaFailedReasonDownloadFailed": "Es hät nüt funktioniert, die Firmware-Datei abzulade", + "@otaFailedReasonDownloadFailed": { + "description": "downloadFailed error message for uploading firmware", + "type": "text", + "placeholders": {} + }, + "otaFailedReasonGearVersionMismatch": "D'Firmware-Version vo dim Gerät passt nöd mit der uufgladene Firmware-Version zäme", + "@otaFailedReasonGearVersionMismatch": { + "description": "gearVersionMismatch error message for uploading firmware", + "type": "text", + "placeholders": {} + }, + "otaFailedReasonGearReturnedError": "D'Gear het en unbekannte Störung zruckgebracht", + "@otaFailedReasonGearReturnedError": { + "description": "gearReturnedError error message for uploading firmware", + "type": "text", + "placeholders": {} + }, + "otaFailedReasonUploadFailed": "Uflade vo Firmware uf d'Gear het nöd funktionier", + "@otaFailedReasonUploadFailed": { + "description": "uploadFailed error message for uploading firmware", + "type": "text", + "placeholders": {} + }, + "otaFailedReasonGearReconnectTimeout": "D'Gears het sich nöd i der Zit wieder verbunde", + "@otaFailedReasonGearReconnectTimeout": { + "description": "gearReconnectTimeout error message for uploading firmware", + "type": "text", + "placeholders": {} + }, + "otaFailedReasonGearDisconnectTimeout": "Gear het sich nöd rechtzeitig abgschaltet und eventuell nöd neu gestartet", + "@otaFailedReasonGearDisconnectTimeout": { + "description": "gearDisconnectTimeout error message for uploading firmware", + "type": "text", + "placeholders": {} + }, + "otaFailedReasonGearOtaFinalTimeout": "Zit abgelaufen, während i uf Gear warte, dass es neui Firmware-Version zurücksendet", + "@otaFailedReasonGearOtaFinalTimeout": { + "description": "gearOtaFinalTimeout error message for uploading firmware", + "type": "text", + "placeholders": {} + }, + "supportDescription": "Tippe uf das blaue Chat-Icon, um Unterstützig z'kontaktierä", + "@supportDescription": { + "description": "The description of the email support link on the more page", + "type": "text", + "placeholders": {} + }, + "manageGearConModeTitle": "Konventionsmodus", + "@manageGearConModeTitle": { + "description": "The title for the convention mode page on the gear page", + "type": "text", + "placeholders": {} + }, + "manageGearConModePincodeTitle": "Pin Code aluga", + "@manageGearConModePincodeTitle": { + "description": "The description for the pin mode button on the gear page", + "type": "text", + "placeholders": {} + }, + "manageGearConModePincodeCopy": "I d'Zwüscheablage kopiere", + "@manageGearConModePincodeCopy": { + "description": "The description for copy to clipboard button on the pin code dialog", + "type": "text", + "placeholders": {} + }, + "manageGearConModeToggleTitle": "Konventionsmodus aktivieren", + "@manageGearConModeToggleTitle": { + "description": "The description for the convention mode enabled button on the gear page", + "type": "text", + "placeholders": {} + }, + "otaFailedReasonMD5Mismatch": "Ds File, wo mer abglade hämmer, isch bei dr Prüefig durchgefloge", + "@otaFailedReasonMD5Mismatch": { + "description": "md5Mismatch error message for uploading firmware", + "type": "text", + "placeholders": {} + }, + "supportTitle": "Unterstützig", + "@supportTitle": { + "description": "The label and title of the email support link on the more page", + "type": "text", + "placeholders": {} + }, + "manageGearConModeDescription": "De Konventionsmodus isch e zusätzliche Sicherheitsmassnahme, um z'verhinder, dass anden Geräte sich mit dinere Ausrüstig verbinden chönd.", + "@manageGearConModeDescription": { + "description": "The description for the convention mode page on the gear page", + "type": "text", + "placeholders": {} + }, + "feedbackPageDescription": "Hesch e Idee oder e Problem mit dr App? Lass es üs wüsse. Hinweis: Das isch anonym und kann nüt helfe, um Problem mit Gear z'löse", + "@feedbackPageDescription": { + "description": "The description of the feedback page", + "type": "text", + "placeholders": {} } } diff --git a/lib/main.dart b/lib/main.dart index 052e222d6..3ae574c34 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -24,6 +24,7 @@ import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_hive/sentry_hive.dart'; import 'package:sentry_logging/sentry_logging.dart'; +import 'Backend/Bluetooth/bluetooth_manager.dart'; import 'Backend/Definitions/Action/base_action.dart'; import 'Backend/Definitions/Device/device_definition.dart'; import 'Backend/app_shortcuts.dart'; @@ -40,8 +41,6 @@ import 'Frontend/utils.dart'; import 'constants.dart'; import 'l10n/messages_all_locales.dart'; -//late SharedPreferences prefs; - FutureOr beforeSend(SentryEvent event, Hint hint) async { bool reportingEnabled = HiveProxy.getOrDefault(settings, "allowErrorReporting", defaultValue: true); if (reportingEnabled) { @@ -117,7 +116,9 @@ Future startSentryApp(Widget child) async { ..reportPackages = false ..attachScreenshot = true ..screenshotQuality = SentryScreenshotQuality.low - ..experimental.replay.sessionSampleRate = dynamicConfigInfo.sentryReplay; + ..attachScreenshotOnlyWhenResumed = true + ..experimental.replay.sessionSampleRate = dynamicConfigInfo.sentryReplay + ..experimental.replay.onErrorSampleRate = dynamicConfigInfo.sentryReplay; }, // Init your App. // ignore: missing_provider_scope @@ -172,7 +173,7 @@ Future isWear() async { } void initFlutter() { - WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized()..addObserver(WidgetBindingLogger()); + WidgetsBinding widgetsBinding = SentryWidgetsFlutterBinding.ensureInitialized()..addObserver(WidgetBindingLogger()); FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); // keeps the splash screen visible } @@ -273,9 +274,7 @@ class TailApp extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return WithForegroundTask( - key: GlobalKey(debugLabel: "foregroundTask"), child: ProviderScope( - key: GlobalKey(debugLabel: "providerScope"), observers: [ RiverpodProviderObserver(), ], @@ -314,14 +313,13 @@ class TailApp extends ConsumerWidget { class TailAppWear extends ConsumerWidget { TailAppWear({super.key}) { // Platform messages may fail, so we use a try/catch PlatformException. - mainLogger.info('Starting app'); + mainLogger.info('Starting Watch app'); } // This widget is the root of your application. @override Widget build(BuildContext context, WidgetRef ref) { return ProviderScope( - key: GlobalKey(debugLabel: "providerScope"), observers: [ RiverpodProviderObserver(), ], @@ -434,10 +432,10 @@ class _EagerInitialization extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { // Eagerly initialize providers by watching them. // By using "watch", the provider will stay alive and not be disposed. - //ref.watch(knownDevicesProvider); - //ref.watch(triggerListProvider); - //ref.watch(moveListsProvider); - //ref.watch(favoriteActionsProvider); + ref.watch(knownDevicesProvider); + ref.watch(triggerListProvider); + ref.watch(moveListsProvider); + ref.watch(favoriteActionsProvider); ref.watch(appShortcutsProvider); if (kDebugMode) { ref.watch(initWearProvider); @@ -450,6 +448,7 @@ class _EagerInitialization extends ConsumerWidget { // Eat snacks // Get google-services.json // Configure Github Actions to store and place the files +// add way to generate/reset persistent IDs Future initMarketingNotifications() async { await Klaviyo.instance.initialize(const String.fromEnvironment('KLAVIYO_KEY', defaultValue: "")); final firebaseMessaging = FirebaseMessaging.instance; diff --git a/pubspec.lock b/pubspec.lock index f77a2f8d0..767a6ddc3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,31 +5,31 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" url: "https://pub.dev" source: hosted - version: "72.0.0" + version: "76.0.0" _flutterfire_internals: dependency: transitive description: name: _flutterfire_internals - sha256: "71c01c1998c40b3af1944ad0a5f374b4e6fef7f3d2df487f3970dbeadaeb25a1" + sha256: daa1d780fdecf8af925680c06c86563cdd445deea995d5c9176f1302a2b10bbe url: "https://pub.dev" source: hosted - version: "1.3.46" + version: "1.3.48" _macros: dependency: transitive description: dart source: sdk - version: "0.3.2" + version: "0.3.3" analyzer: - dependency: "direct overridden" + dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "6.11.0" analyzer_plugin: dependency: transitive description: @@ -58,10 +58,10 @@ packages: dependency: transitive description: name: archive - sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a" url: "https://pub.dev" source: hosted - version: "3.6.1" + version: "4.0.2" args: dependency: transitive description: @@ -154,50 +154,50 @@ packages: dependency: transitive description: name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" build_config: dependency: transitive description: name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" build_daemon: dependency: transitive description: name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + sha256: "294a2edaf4814a378725bfe6358210196f5ea37af89ecd81bfa32960113d4948" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.0.3" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + sha256: "99d3980049739a985cf9b21f30881f46db3ebc62c5b8d5e60e27440876b1ba1e" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" + sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573" url: "https://pub.dev" source: hosted - version: "2.4.13" + version: "2.4.14" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 + sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" url: "https://pub.dev" source: hosted - version: "7.3.2" + version: "8.0.0" built_collection: dependency: "direct main" description: @@ -210,10 +210,10 @@ packages: dependency: transitive description: name: built_value - sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2" url: "https://pub.dev" source: hosted - version: "8.9.2" + version: "8.9.3" characters: dependency: transitive description: @@ -307,10 +307,10 @@ packages: dependency: "direct main" description: name: connectivity_plus - sha256: "876849631b0c7dc20f8b471a2a03142841b482438e3b707955464f5ffca3e4c3" + sha256: e0817759ec6d2d8e57eb234e6e57d2173931367a865850c7acea40d4b4f9c27d url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.1.1" connectivity_plus_platform_interface: dependency: transitive description: @@ -331,10 +331,10 @@ packages: dependency: transitive description: name: coverage - sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5" + sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" cronet_http: dependency: transitive description: @@ -387,26 +387,34 @@ packages: dependency: transitive description: name: custom_lint - sha256: "22bd87a362f433ba6aae127a7bac2838645270737f3721b180916d7c5946cb5d" + sha256: "3486c470bb93313a9417f926c7dd694a2e349220992d7b9d14534dc49c15bba9" url: "https://pub.dev" source: hosted - version: "0.5.11" + version: "0.7.0" custom_lint_builder: dependency: transitive description: name: custom_lint_builder - sha256: "0d48e002438950f9582e574ef806b2bea5719d8d14c0f9f754fbad729bcf3b19" + sha256: "42cdc41994eeeddab0d7a722c7093ec52bd0761921eeb2cbdbf33d192a234759" url: "https://pub.dev" source: hosted - version: "0.5.14" + version: "0.7.0" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: "2952837953022de610dacb464f045594854ced6506ac7f76af28d4a6490e189b" + sha256: "02450c3e45e2a6e8b26c4d16687596ab3c4644dd5792e3313aa9ceba5a49b7f5" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + custom_lint_visitor: + dependency: transitive + description: + name: custom_lint_visitor + sha256: bfe9b7a09c4775a587b58d10ebb871d4fe618237639b1e84d5ec62d7dfef25f9 url: "https://pub.dev" source: hosted - version: "0.5.14" + version: "1.0.0+6.11.0" dart_style: dependency: transitive description: @@ -435,18 +443,18 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: f545ffbadee826f26f2e1a0f0cbd667ae9a6011cc0f77c0f8f00a969655e6e95 + sha256: "4fa68e53e26ab17b70ca39f072c285562cfc1589df5bb1e9295db90f6645f431" url: "https://pub.dev" source: hosted - version: "11.1.1" + version: "11.2.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" + sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.0.2" dio: dependency: "direct main" description: @@ -547,58 +555,82 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "16dc141db5a2ccc6520ebb6a2eb5945b1b09e95085c021d9f914f8ded7f1465c" + sha256: c2376a6aae82358a9f9ccdd7d1f4006d08faa39a2767cce01031d9f593a8bd3b url: "https://pub.dev" source: hosted - version: "8.1.4" + version: "8.1.6" + firebase_app_installations: + dependency: "direct main" + description: + name: firebase_app_installations + sha256: "77271db6dbcdcd0a6850e927078f0f98267b9f6152c79d173882340d2dfeb4d8" + url: "https://pub.dev" + source: hosted + version: "0.3.1+7" + firebase_app_installations_platform_interface: + dependency: transitive + description: + name: firebase_app_installations_platform_interface + sha256: f331b130886f44a37996220e33ed98e3c2e0b4cf1a025121b024aa96ba6ac3c6 + url: "https://pub.dev" + source: hosted + version: "0.1.4+47" + firebase_app_installations_web: + dependency: transitive + description: + name: firebase_app_installations_web + sha256: "135e03cb4a9494c24b7ff4a63443b3fc1c17d26000ab6a781d4b848a10139b47" + url: "https://pub.dev" + source: hosted + version: "0.1.6+5" firebase_core: dependency: "direct main" description: name: firebase_core - sha256: "2438a75ad803e818ad3bd5df49137ee619c46b6fc7101f4dbc23da07305ce553" + sha256: "15d761b95dfa2906dfcc31b7fc6fe293188533d1a3ffe78389ba9e69bd7fdbde" url: "https://pub.dev" source: hosted - version: "3.8.0" + version: "3.9.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: e30da58198a6d4b49d5bce4e852f985c32cb10db329ebef9473db2b9f09ce810 + sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.4.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: f967a7138f5d2ffb1ce15950e2a382924239eaa521150a8f144af34e68b3b3e5 + sha256: fbc008cf390d909b823763064b63afefe9f02d8afdb13eb3f485b871afee956b url: "https://pub.dev" source: hosted - version: "2.18.1" + version: "2.19.0" firebase_messaging: dependency: "direct main" description: name: firebase_messaging - sha256: "4d0968ecb860d7baa15a6e2af3469ec5b0d959e51c59ce84a52b0f7632a4aa5a" + sha256: "151a3ee68736abf293aab66d1317ade53c88abe1db09c75a0460aebf7767bbdf" url: "https://pub.dev" source: hosted - version: "15.1.5" + version: "15.1.6" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: a2cb3e7d71d40b6612e2d4e0daa0ae759f6a9d07f693f904d14d22aadf70be10 + sha256: f331ee51e40c243f90cc7bc059222dfec4e5df53125b08d31fb28961b00d2a9d url: "https://pub.dev" source: hosted - version: "4.5.48" + version: "4.5.49" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: "1554e190f0cd9d6fe59f61ae0275ac12006fdb78b07669f1a260d1a9e6de3a1f" + sha256: efaf3fdc54cd77e0eedb8e75f7f01c808828c64d052ddbf94d3009974e47d30f url: "https://pub.dev" source: hosted - version: "3.9.4" + version: "3.9.5" firebase_testlab_detector: dependency: "direct main" description: @@ -619,10 +651,10 @@ packages: dependency: "direct main" description: name: fl_chart - sha256: "74959b99b92b9eebeed1a4049426fd67c4abc3c5a0f4d12e2877097d6a11ae08" + sha256: c724234b05e378383e958f3e82ca84a3e1e3c06a0898462044dd8a24b1ee9864 url: "https://pub.dev" source: hosted - version: "0.69.2" + version: "0.70.0" flex_color_picker: dependency: "direct main" description: @@ -673,10 +705,10 @@ packages: dependency: "direct main" description: name: flutter_foreground_task - sha256: "6c073b3653efdf540c67d4ed67301a9806738eb8ee31046839d2c64f83d771b5" + sha256: "206017ee1bf864f34b8d7bce664a172717caa21af8da23f55866470dfe316644" url: "https://pub.dev" source: hosted - version: "8.14.0" + version: "8.17.0" flutter_gen_core: dependency: transitive description: @@ -693,14 +725,6 @@ packages: url: "https://pub.dev" source: hosted version: "5.8.0" - flutter_isolate: - dependency: "direct main" - description: - name: flutter_isolate - sha256: "36a84e1a22371d8092ea2121145b330c24fb272acb951fb30c60ba44926b8fb3" - url: "https://pub.dev" - source: hosted - version: "2.1.0" flutter_joystick: dependency: "direct main" description: @@ -790,10 +814,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398" + sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" url: "https://pub.dev" source: hosted - version: "2.0.23" + version: "2.0.24" flutter_riverpod: dependency: "direct main" description: @@ -806,10 +830,10 @@ packages: dependency: "direct main" description: name: flutter_screen_lock - sha256: "07cb55016cf16b0374e6f79918964c65f2f722a461d1f56eb79cb88e1123b9a7" + sha256: c15a5082496a42472f08b9e7805b26735ebcd372ec521eb569c767021363b487 url: "https://pub.dev" source: hosted - version: "9.1.0" + version: "9.2.0" flutter_svg: dependency: transitive description: @@ -872,10 +896,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "8660b74171fafae4aa8202100fa2e55349e078281dadc73a241eb8e758534d9d" + sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539" url: "https://pub.dev" source: hosted - version: "14.6.1" + version: "14.6.2" go_router_builder: dependency: "direct dev" description: @@ -976,10 +1000,10 @@ packages: dependency: transitive description: name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" http_parser: dependency: transitive description: @@ -1000,10 +1024,10 @@ packages: dependency: transitive description: name: image - sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d + sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6" url: "https://pub.dev" source: hosted - version: "4.3.0" + version: "4.5.2" image_size_getter: dependency: transitive description: @@ -1065,10 +1089,10 @@ packages: dependency: transitive description: name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" is_wear: dependency: "direct main" description: @@ -1113,27 +1137,27 @@ packages: dependency: "direct main" description: path: "." - ref: patch-1 - resolved-ref: "6a759dc78d5e390f3ff60182a0878ca10c96eedd" - url: "https://github.com/Codel1417/klaviyo_flutter" + ref: acc2eb22f12e54e86df3541ddb23b6983ff5d2ac + resolved-ref: acc2eb22f12e54e86df3541ddb23b6983ff5d2ac + url: "https://github.com/drybnikov/klaviyo_flutter" source: git - version: "0.1.1" + version: "0.1.3" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -1146,10 +1170,10 @@ packages: dependency: transitive description: name: lints - sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.1.1" logarte: dependency: "direct main" description: @@ -1179,10 +1203,10 @@ packages: dependency: transitive description: name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" url: "https://pub.dev" source: hosted - version: "0.1.2-main.4" + version: "0.1.3-main.0" markdown: dependency: transitive description: @@ -1227,10 +1251,10 @@ packages: dependency: "direct dev" description: name: mockito - sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917" + sha256: f99d8d072e249f719a5531735d146d8cf04c580d93920b04de75bef6dfb2daf6 url: "https://pub.dev" source: hosted - version: "5.4.4" + version: "5.4.5" multi_value_listenable_builder: dependency: "direct main" description: @@ -1275,26 +1299,26 @@ packages: dependency: transitive description: name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" package_info_plus: dependency: "direct main" description: name: package_info_plus - sha256: da8d9ac8c4b1df253d1a328b7bf01ae77ef132833479ab40763334db13b91cce + sha256: "70c421fe9d9cc1a9a7f3b05ae56befd469fe4f8daa3b484823141a55442d858d" url: "https://pub.dev" source: hosted - version: "8.1.1" + version: "8.1.2" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 + sha256: a5ef9986efc7bf772f2696183a3992615baa76c1ffb1189318dd8803778fb05b url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" path: dependency: transitive description: @@ -1323,18 +1347,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "8c4967f8b7cb46dc914e178daa29813d83ae502e0529d7b0478330616a691ef7" + sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" url: "https://pub.dev" source: hosted - version: "2.2.14" + version: "2.2.15" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -1364,7 +1388,7 @@ packages: description: path: "packages/pdfx" ref: HEAD - resolved-ref: b3ede682cf9dba578d0d9011597121bf7d723ebd + resolved-ref: f8432a56b787ac9354fe1c94cfff46183773c99b url: "https://github.com/Codel1417/packages.flutter" source: git version: "2.8.0" @@ -1472,6 +1496,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + posix: + dependency: transitive + description: + name: posix + sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a + url: "https://pub.dev" + source: hosted + version: "6.0.1" proximity_sensor: dependency: "direct main" description: @@ -1484,26 +1516,26 @@ packages: dependency: transitive description: name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" quick_actions: dependency: "direct main" description: name: quick_actions - sha256: "2c1d9a91f3218b4e987a7e1e95ba0415b7f48a2cb3ffacc027a1e3d3c117223f" + sha256: "7e35dd6a21f5bbd21acf6899039eaf85001a5ac26d52cbd6a8a2814505b90798" url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.1.0" quick_actions_android: dependency: transitive description: @@ -1516,10 +1548,10 @@ packages: dependency: transitive description: name: quick_actions_ios - sha256: "402596dea62a1028960b93f7651ec22be0e2a91e4fbf92a1c62d3b95f8ff95a5" + sha256: "837b7e6b5973784d3da56b8c959b446b215914f20405d88cd7d22a2fb94e4e4c" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" quick_actions_platform_interface: dependency: transitive description: @@ -1540,10 +1572,10 @@ packages: dependency: transitive description: name: riverpod_analyzer_utils - sha256: "22a089135785f27e601075023f93c6622c43ef28c3ba1bef303cfbc314028e64" + sha256: c6b8222b2b483cb87ae77ad147d6408f400c64f060df7a225b127f4afef4f8c8 url: "https://pub.dev" source: hosted - version: "0.4.3" + version: "0.5.8" riverpod_annotation: dependency: "direct main" description: @@ -1556,26 +1588,26 @@ packages: dependency: "direct dev" description: name: riverpod_generator - sha256: "49e36ca4c7e78f97ae6a2ab3b43c53fd688429482c253b5c3bf5670d2dec6c87" + sha256: "63546d70952015f0981361636bf8f356d9cfd9d7f6f0815e3c07789a41233188" url: "https://pub.dev" source: hosted - version: "3.0.0-dev.6" + version: "2.6.3" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: a2602c6b7fc34a7e36be63ce6399ed0cab66827b6649ba4382e218df34b72754 + sha256: "83e4caa337a9840469b7b9bd8c2351ce85abad80f570d84146911b32086fbd99" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.6.3" rxdart: dependency: transitive description: name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" url: "https://pub.dev" source: hosted - version: "0.27.7" + version: "0.28.0" sensors_plus: dependency: transitive description: @@ -1596,42 +1628,42 @@ packages: dependency: transitive description: name: sentry - sha256: "2440763ae96fa8fd1bcdfc224f5232e1b7a09af76a72f4e626ee313a261faf6f" + sha256: b1ead7ca4da0949aed9482c4962f172021a4417f0a126fa974878c2301c16df7 url: "https://pub.dev" source: hosted - version: "8.10.1" + version: "8.11.2" sentry_dio: dependency: "direct main" description: name: sentry_dio - sha256: cf2c3e332c4112e3c1432410026f98a27d36b03c4dd785a28049109bf331765e + sha256: "69036a13431a49eee1f9e1af46d09808e6ff2efe7f15365adbe0e2a1d1617841" url: "https://pub.dev" source: hosted - version: "8.10.1" + version: "8.11.2" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: "3b30038b3b9303540a8b2c8b1c8f0bb93a207f8e4b25691c59d969ddeb4734fd" + sha256: d978861bc413ef98b663b065a65e780b255bfcdc0e2fa307884f7f6df0f1a406 url: "https://pub.dev" source: hosted - version: "8.10.1" + version: "8.11.2" sentry_hive: dependency: "direct main" description: name: sentry_hive - sha256: "28f15d08a2bb9a4d70a100c930ade4a81a20147ccdd9ca40cdd0f18112d86a77" + sha256: f29d3911b164f4304522e70f4c599e06cdaaca25eae56b989ec02453e1a723a8 url: "https://pub.dev" source: hosted - version: "8.10.1" + version: "8.11.2" sentry_logging: dependency: "direct main" description: name: sentry_logging - sha256: "60ce631ad38eadab524cdc3698e1906ab04dacba7629bd8b29d2f2b73f92d210" + sha256: "793a0488baaaa63e1af99ce7cfbb4d81d82cb1bb39a5b90467da3c46816b6c72" url: "https://pub.dev" source: hosted - version: "8.10.1" + version: "8.11.2" shake: dependency: "direct main" description: @@ -1645,26 +1677,26 @@ packages: dependency: transitive description: name: shared_preferences - sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82" + sha256: "3c7e73920c694a436afaf65ab60ce3453d91f84208d761fbd83fc21182134d93" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.3.4" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab" + sha256: "02a7d8a9ef346c9af715811b01fbd8e27845ad2c41148eefd31321471b41863d" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d" + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.5.4" shared_preferences_linux: dependency: transitive description: @@ -1733,7 +1765,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_gen: dependency: transitive description: @@ -1746,10 +1778,10 @@ packages: dependency: transitive description: name: source_helper - sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" url: "https://pub.dev" source: hosted - version: "1.3.4" + version: "1.3.5" source_map_stack_trace: dependency: transitive description: @@ -1762,10 +1794,10 @@ packages: dependency: transitive description: name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" url: "https://pub.dev" source: hosted - version: "0.10.12" + version: "0.10.13" source_span: dependency: transitive description: @@ -1786,10 +1818,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" state_notifier: dependency: transitive description: @@ -1810,18 +1842,18 @@ packages: dependency: transitive description: name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" synchronized: dependency: transitive description: @@ -1842,26 +1874,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" + sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" url: "https://pub.dev" source: hosted - version: "1.25.7" + version: "1.25.8" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" test_core: dependency: transitive description: name: test_core - sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" + sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" time: dependency: transitive description: @@ -1874,10 +1906,10 @@ packages: dependency: transitive description: name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" typed_data: dependency: transitive description: @@ -1906,10 +1938,10 @@ packages: dependency: "direct main" description: name: upgrader - sha256: "9b907a8c956dbf3f2d0430d16134e27543cba98eab31f19a2240ab1c4d920506" + sha256: eb5a4888873d7998605306c4212491efdff8e59ee609d946dbcd6df83598d004 url: "https://pub.dev" source: hosted - version: "11.3.0" + version: "11.3.1" url_launcher: dependency: "direct main" description: @@ -1930,10 +1962,10 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.2" url_launcher_linux: dependency: transitive description: @@ -1946,10 +1978,10 @@ packages: dependency: transitive description: name: url_launcher_macos - sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -2034,18 +2066,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.0" wakelock_plus: dependency: "direct main" description: name: wakelock_plus - sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484 + sha256: "1aeab49f24aec1e5ab417d7cdfc47c7bbcb815353f1840667ffe68c89a0cd2e6" url: "https://pub.dev" source: hosted - version: "1.2.8" + version: "1.2.9" wakelock_plus_platform_interface: dependency: transitive description: @@ -2074,10 +2106,10 @@ packages: dependency: transitive description: name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" web: dependency: transitive description: @@ -2154,10 +2186,10 @@ packages: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.24.0" + dart: ">=3.6.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8d21dfea1..25fe367ad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: sdk: flutter cross_platform: ^3.0.1 logging: ^1.3.0 - go_router: ^14.6.1 + go_router: ^14.6.2 vector_math: ^2.1.4 # used for joystick collection: ^1.19.1 # Priority Queue intl: #pinned to flutter version? @@ -31,25 +31,24 @@ dependencies: built_collection: ^5.1.1 # Platform Interfaces - device_info_plus: ^11.1.1 - wakelock_plus: ^1.2.8 # Keeps the screen awake - file_picker: ^8.1.4 # used to manually select firmware file + device_info_plus: ^11.2.0 + wakelock_plus: ^1.2.9 # Keeps the screen awake + file_picker: ^8.1.6 # used to manually select firmware file path_provider: ^2.1.5 # used to get paths for app storage and cache storage - package_info_plus: ^8.1.1 + package_info_plus: ^8.1.2 permission_handler: ^11.3.1 url_launcher: ^6.3.1 # Open URLS in external apps flutter_blue_plus: ^1.34.5 - flutter_foreground_task: ^8.14.0 # Keep the app running in the background on android + flutter_foreground_task: ^8.17.0 # Keep the app running in the background on android install_referrer: # Needs gradle namespace git: url: https://github.com/undreeyyy/flutter_plugin_install_referrer ref: fd87e9b8f0d5ed909e929388244456f72b9b63c7 - quick_actions: ^1.0.8 # puts favorites on the home screen + quick_actions: ^1.1.0 # puts favorites on the home screen audioplayers: ^6.1.0 firebase_testlab_detector: ^1.0.2 platform: ^3.1.6 - connectivity_plus: ^6.1.0 - flutter_isolate: ^2.1.0 + connectivity_plus: ^6.1.1 # Watch is_wear: ^0.0.2+3 @@ -61,12 +60,12 @@ dependencies: riverpod_annotation: ^2.6.1 # Widgets / UI - flutter_screen_lock: ^9.1.0 # used to hide dev mode toggle + flutter_screen_lock: ^9.2.0 # used to hide dev mode toggle introduction_screen: ^3.1.14 # Onboarding flex_color_picker: ^3.6.0 flutter_adaptive_scaffold: ^0.3.1 animate_do: ^3.3.4 - fl_chart: ^0.69.2 # Used for the battery graph + fl_chart: ^0.70.0 # Used for the battery graph chart_sparkline: ^1.1.1 # used for the move easing visual flutter_joystick: ^0.2.1 multi_value_listenable_builder: ^0.0.2 @@ -109,29 +108,30 @@ dependencies: # play services in_app_review: ^2.0.10 - upgrader: ^11.3.0 + upgrader: ^11.3.1 google_api_availability: ^5.0.0 - firebase_messaging: ^15.1.5 - firebase_core: ^3.8.0 + firebase_messaging: ^15.1.6 + firebase_core: ^3.9.0 + firebase_app_installations: ^0.3.1+7 # Spicy plausible_analytics: ^0.3.0 # Privacy Preserving analytics klaviyo_flutter: git: - url: https://github.com/Codel1417/klaviyo_flutter - ref: patch-1 + url: https://github.com/drybnikov/klaviyo_flutter + ref: acc2eb22f12e54e86df3541ddb23b6983ff5d2ac # Sentry - sentry_flutter: ^8.10.1 # Base sentry + Flutter integration - sentry_logging: ^8.10.1 # Collects app logs - sentry_hive: ^8.10.1 # Collects Hive storage accesses - sentry_dio: ^8.10.1 # Collects Dio HTTP requests + sentry_flutter: ^8.11.2 # Base sentry + Flutter integration + sentry_logging: ^8.11.2 # Collects app logs + sentry_hive: ^8.11.2 # Collects Hive storage accesses + sentry_dio: ^8.11.2 # Collects Dio HTTP requests feedback_sentry: ^3.1.0 dev_dependencies: build_runner: # Required for build flutter_gen_runner: - riverpod_generator: ^3.0.0-dev.6 #required for @Riverpod annotations + riverpod_generator: ^2.6.3 #required for @Riverpod annotations json_serializable: ^6.9.0 # required for @JsonSerializable annotations hive_generator: ^2.0.1 # required for @HiveType annotations go_router_builder: ^2.7.1 @@ -150,7 +150,7 @@ dev_dependencies: dependency_overrides: collection: 1.19.1 - analyzer: 6.7.0 +#analyzer: 6.7.0 flutter: uses-material-design: true @@ -165,6 +165,7 @@ sentry: # used by the sentry-dart-plugin to upload symbols. Credentials are prov upload_debug_symbols: true upload_source_maps: true upload_sources: true + symbols_path: ./symbols icons_launcher: image_path: "assets/TC_Logo.png" diff --git a/test/Backend/action_registry_test.dart b/test/Backend/action_registry_test.dart index d045f9706..16e12241a 100644 --- a/test/Backend/action_registry_test.dart +++ b/test/Backend/action_registry_test.dart @@ -78,40 +78,5 @@ void main() { var actions = container.read(getAllActionsProvider); expect(actions.length, 5); }); - test('Tail Actions', () { - final container = ProviderContainer( - overrides: [], - ); - var actions = container.read(getAllActionsFilteredProvider(BuiltSet({DeviceType.tail}))); - expect(actions.length, 4); - }); - test('Ear Actions', () { - final container = ProviderContainer( - overrides: [], - ); - var actions = container.read(getAllActionsFilteredProvider(BuiltSet({DeviceType.ears}))); - expect(actions.length, 1); - }); - test('Wings Actions', () { - final container = ProviderContainer( - overrides: [], - ); - var actions = container.read(getAllActionsFilteredProvider(BuiltSet({DeviceType.wings}))); - expect(actions.length, 3); - }); - test('Mini Tail Actions', () { - final container = ProviderContainer( - overrides: [], - ); - var actions = container.read(getAllActionsFilteredProvider(BuiltSet({DeviceType.miniTail}))); - expect(actions.length, 3); - }); - test('No Actions', () { - final container = ProviderContainer( - overrides: [], - ); - var actions = container.read(getAllActionsFilteredProvider(BuiltSet())); - expect(actions.length, 0); - }); }); }