From dc261417df4d74b637691aaf2ac71e304de475b1 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Wed, 26 Feb 2025 02:02:26 +0200 Subject: [PATCH 01/16] feat: enhance private view mechanism --- .../example/pubspec.lock | 30 +- .../lib/instabug_dio_interceptor.dart | 3 +- .../instabug_dio_interceptor/pubspec.lock | 38 +- .../flutter/InstabugFlutterPlugin.java | 23 +- .../flutter}/model/ScreenshotResult.java | 2 +- .../instabug/flutter/modules/InstabugApi.java | 33 +- .../flutter}/modules/InstabugPrivateView.java | 29 +- .../flutter}/modules/PrivateViewManager.java | 18 +- .../capturing/BoundryCaptureManager.java | 5 +- .../modules/capturing/CaptureManager.java | 2 +- .../capturing/PixelCopyCaptureManager.java | 4 +- .../capturing/ScreenshotResultCallback.java | 5 +- .../instabug/flutter/util/ArgsRegistry.java | 9 + .../instabug/flutter/ArgsRegistryTest.java | 16 + .../com/instabug/flutter/InstabugApiTest.java | 15 +- .../ios/InstabugTests/ArgsRegistryTests.m | 13 + .../ios/InstabugTests/InstabugApiTests.m | 9 +- .../instabug_flutter/example/ios/Podfile.lock | 2 +- .../instabug_flutter/example/lib/main.dart | 17 +- .../example/lib/src/app_routes.dart | 3 + .../src/components/fatal_crashes_content.dart | 10 +- .../lib/src/components/network_content.dart | 8 +- .../example/lib/src/screens/my_home_page.dart | 12 +- .../lib/src/screens/private_view_page.dart | 232 +++++- .../example/lib/src/widget/nested_view.dart | 11 +- .../instabug_flutter/example/pubspec.lock | 34 +- .../ios/Classes/InstabugFlutterPlugin.m | 5 + .../ios/Classes/Modules/InstabugApi.m | 16 +- .../ios/Classes/Modules/PrivateViewApi.h | 0 .../ios/Classes/Modules/PrivateViewApi.m | 29 +- .../ios/Classes/Modules/PrivateViewHostApi.h | 0 .../ios/Classes/Modules/PrivateViewHostApi.m | 4 + .../ios/Classes/Util/ArgsRegistry.h | 1 + .../ios/Classes/Util/ArgsRegistry.m | 12 + .../FlutterPluginRegistrar+FlutterEngine.h | 0 .../FlutterPluginRegistrar+FlutterEngine.m | 0 .../lib/instabug_flutter.dart | 5 +- .../lib/src/modules/instabug.dart | 6 +- .../utils/instabug_navigator_observer.dart | 35 +- .../lib/src/utils/instabug_widget.dart | 60 ++ .../private_views/instabug_private_view.dart | 13 + .../instabug_sliver_private_view.dart | 14 + .../private_views/private_views_manager.dart | 136 ++++ .../screen_loading/screenshot_pipeline.dart | 154 ++++ .../src/utils/user_steps/widget_utils.dart | 29 +- .../pigeons/instabug.api.dart | 5 +- .../pigeons/instabug_private_view.api.dart | 1 + packages/instabug_flutter/pubspec.lock | 38 +- .../instabug_flutter/test/instabug_test.dart | 4 +- .../instabug_navigator_observer_test.dart | 10 +- .../example/pubspec.lock | 32 +- .../instabug_flutter_modular/pubspec.lock | 52 +- .../instabug_http_client/example/pubspec.lock | 30 +- .../lib/instabug_http_client.dart | 4 +- .../lib/instabug_http_logger.dart | 2 +- packages/instabug_http_client/pubspec.lock | 52 +- .../test/instabug_http_client_test.dart | 16 +- packages/instabug_private_views/.metadata | 33 - packages/instabug_private_views/CHANGELOG.md | 7 - packages/instabug_private_views/LICENSE | 21 - packages/instabug_private_views/README.md | 63 -- .../android/build.gradle | 56 -- .../android/settings.gradle | 1 - .../android/src/main/AndroidManifest.xml | 3 - .../InstabugPrivateViewsPlugin.java | 88 -- .../BoundryScreenshotCaptorTest.java | 80 -- .../PixelCopyScreenshotCaptorTest.java | 94 --- .../PrivateViewManagerTest.java | 146 ---- .../example-hybrid-ios-app/.gitignore | 45 -- .../example-hybrid-ios-app/Podfile | 21 - .../project.pbxproj | 435 ---------- .../hybrid-flutter-app/AppDelegate.swift | 41 - .../AccentColor.colorset/Contents.json | 11 - .../AppIcon.appiconset/Contents.json | 35 - .../Assets.xcassets/Contents.json | 6 - .../Base.lproj/LaunchScreen.storyboard | 25 - .../Base.lproj/Main.storyboard | 86 -- .../hybrid-flutter-app/Info.plist | 25 - .../hybrid-flutter-app/SceneDelegate.swift | 52 -- .../hybrid-flutter-app/ViewController.swift | 29 - .../example-hybrid-ios-app/init.sh | 6 - .../my_flutter/.gitignore | 49 -- .../my_flutter/.metadata | 10 - .../my_flutter/README.md | 11 - .../my_flutter/lib/main.dart | 76 -- .../my_flutter/pubspec.lock | 227 ------ .../my_flutter/pubspec.yaml | 80 -- .../my_flutter/pubspec_overrides.yaml | 6 - .../instabug_private_views/example/.metadata | 45 -- .../instabug_private_views/example/README.md | 16 - .../example/android/app/build.gradle | 44 - .../android/app/src/debug/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 45 -- .../MainActivity.java | 6 - .../com/instabug/example/MainActivity.kt | 5 - .../res/drawable-v21/launch_background.xml | 12 - .../main/res/drawable/launch_background.xml | 12 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values-night/styles.xml | 18 - .../app/src/main/res/values/styles.xml | 18 - .../app/src/profile/AndroidManifest.xml | 7 - .../example/android/build.gradle | 24 - .../example/android/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.properties | 5 - .../example/android/gradlew | 160 ---- .../example/android/gradlew.bat | 90 --- .../example/android/settings.gradle | 25 - .../example/assets/img.png | Bin 181305 -> 0 bytes .../ios/Flutter/AppFrameworkInfo.plist | 26 - .../example/ios/Flutter/Debug.xcconfig | 2 - .../example/ios/Flutter/Release.xcconfig | 2 - .../example/ios/Podfile | 46 -- .../example/ios/Podfile.lock | 49 -- .../ios/Runner.xcodeproj/project.pbxproj | 761 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 98 --- .../contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../example/ios/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 122 --- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 295 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 406 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 450 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 282 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 462 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 704 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 406 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 586 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 862 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 862 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 1674 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 762 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 1226 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 1418 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 - .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../example/ios/Runner/Info.plist | 49 -- .../ios/Runner/Runner-Bridging-Header.h | 1 - .../ios/RunnerTests/PrivateViewApiTests.m | 206 ----- .../ios/RunnerTests/PrivateViewHostApiTests.m | 57 -- .../RunnerTests/RunnerTests-Bridging-Header.h | 4 - .../example/lib/main.dart | 29 - .../example/lib/private_view_page.dart | 389 --------- .../example/lib/widget/instabug_button.dart | 48 -- .../lib/widget/instabug_text_field.dart | 46 -- .../example/lib/widget/section_title.dart | 20 - .../example/pubspec.lock | 304 ------- .../example/pubspec.yaml | 70 -- .../example/pubspec_overrides.yaml | 6 - .../instabug_private_views/ios/.gitignore | 38 - .../ios/Assets/.gitkeep | 0 .../ios/Classes/InstabugPrivateViewsPlugin.h | 4 - .../ios/Classes/InstabugPrivateViewsPlugin.m | 13 - .../instabug_private_views-Bridging-Header.h | 4 - .../ios/Resources/PrivacyInfo.xcprivacy | 14 - .../ios/instabug_private_views.podspec | 30 - .../lib/instabug_private_view.dart | 11 - .../lib/src/instabug_private_view.dart | 56 -- .../lib/src/instabug_sliver_private_view.dart | 58 -- .../lib/src/private_views_manager.dart | 83 -- .../base_render_visibility_detector.dart | 266 ------ .../sliver_visibility_detector.dart | 85 -- .../visibility_detector.dart | 49 -- .../visibillity_utils.dart | 46 -- packages/instabug_private_views/pubspec.lock | 716 ---------------- packages/instabug_private_views/pubspec.yaml | 36 - .../pubspec_overrides.yaml | 4 - packages/instabug_private_views/release.sh | 13 - .../instabug_private_views/scripts/pigeon.sh | 35 - .../test/instabug_private_view_test.dart | 82 -- .../instabug_sliver_private_view_test.dart | 99 --- 184 files changed, 1086 insertions(+), 6902 deletions(-) rename packages/{instabug_private_views/android/src/main/java/com/instabug/instabug_private_views => instabug_flutter/android/src/main/java/com/instabug/flutter}/model/ScreenshotResult.java (89%) rename packages/{instabug_private_views/android/src/main/java/com/instabug/instabug_private_views => instabug_flutter/android/src/main/java/com/instabug/flutter}/modules/InstabugPrivateView.java (60%) rename packages/{instabug_private_views/android/src/main/java/com/instabug/instabug_private_views => instabug_flutter/android/src/main/java/com/instabug/flutter}/modules/PrivateViewManager.java (91%) rename packages/{instabug_private_views/android/src/main/java/com/instabug/instabug_private_views => instabug_flutter/android/src/main/java/com/instabug/flutter}/modules/capturing/BoundryCaptureManager.java (91%) rename packages/{instabug_private_views/android/src/main/java/com/instabug/instabug_private_views => instabug_flutter/android/src/main/java/com/instabug/flutter}/modules/capturing/CaptureManager.java (71%) rename packages/{instabug_private_views/android/src/main/java/com/instabug/instabug_private_views => instabug_flutter/android/src/main/java/com/instabug/flutter}/modules/capturing/PixelCopyCaptureManager.java (96%) rename packages/{instabug_private_views/android/src/main/java/com/instabug/instabug_private_views => instabug_flutter/android/src/main/java/com/instabug/flutter}/modules/capturing/ScreenshotResultCallback.java (50%) rename packages/{instabug_private_views => instabug_flutter}/ios/Classes/Modules/PrivateViewApi.h (100%) rename packages/{instabug_private_views => instabug_flutter}/ios/Classes/Modules/PrivateViewApi.m (83%) rename packages/{instabug_private_views => instabug_flutter}/ios/Classes/Modules/PrivateViewHostApi.h (100%) rename packages/{instabug_private_views => instabug_flutter}/ios/Classes/Modules/PrivateViewHostApi.m (97%) rename packages/{instabug_private_views => instabug_flutter}/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.h (100%) rename packages/{instabug_private_views => instabug_flutter}/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.m (100%) create mode 100644 packages/instabug_flutter/lib/src/utils/instabug_widget.dart create mode 100644 packages/instabug_flutter/lib/src/utils/private_views/instabug_private_view.dart create mode 100644 packages/instabug_flutter/lib/src/utils/private_views/instabug_sliver_private_view.dart create mode 100644 packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart create mode 100644 packages/instabug_flutter/lib/src/utils/screen_loading/screenshot_pipeline.dart rename packages/{instabug_private_views => instabug_flutter}/pigeons/instabug_private_view.api.dart (99%) delete mode 100644 packages/instabug_private_views/.metadata delete mode 100644 packages/instabug_private_views/CHANGELOG.md delete mode 100644 packages/instabug_private_views/LICENSE delete mode 100644 packages/instabug_private_views/README.md delete mode 100644 packages/instabug_private_views/android/build.gradle delete mode 100644 packages/instabug_private_views/android/settings.gradle delete mode 100644 packages/instabug_private_views/android/src/main/AndroidManifest.xml delete mode 100644 packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/InstabugPrivateViewsPlugin.java delete mode 100644 packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/BoundryScreenshotCaptorTest.java delete mode 100644 packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/PixelCopyScreenshotCaptorTest.java delete mode 100644 packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/PrivateViewManagerTest.java delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/.gitignore delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/Podfile delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app.xcodeproj/project.pbxproj delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/AppDelegate.swift delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/AccentColor.colorset/Contents.json delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/Contents.json delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Base.lproj/Main.storyboard delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Info.plist delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/SceneDelegate.swift delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/ViewController.swift delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/init.sh delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/my_flutter/.gitignore delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/my_flutter/.metadata delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/my_flutter/README.md delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/my_flutter/lib/main.dart delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec.lock delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec.yaml delete mode 100644 packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec_overrides.yaml delete mode 100644 packages/instabug_private_views/example/.metadata delete mode 100644 packages/instabug_private_views/example/README.md delete mode 100644 packages/instabug_private_views/example/android/app/build.gradle delete mode 100644 packages/instabug_private_views/example/android/app/src/debug/AndroidManifest.xml delete mode 100644 packages/instabug_private_views/example/android/app/src/main/AndroidManifest.xml delete mode 100644 packages/instabug_private_views/example/android/app/src/main/java/com/instabug/instabug_private_views_example/MainActivity.java delete mode 100644 packages/instabug_private_views/example/android/app/src/main/kotlin/com/instabug/example/MainActivity.kt delete mode 100644 packages/instabug_private_views/example/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 packages/instabug_private_views/example/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 packages/instabug_private_views/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 packages/instabug_private_views/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 packages/instabug_private_views/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 packages/instabug_private_views/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 packages/instabug_private_views/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 packages/instabug_private_views/example/android/app/src/main/res/values-night/styles.xml delete mode 100644 packages/instabug_private_views/example/android/app/src/main/res/values/styles.xml delete mode 100644 packages/instabug_private_views/example/android/app/src/profile/AndroidManifest.xml delete mode 100644 packages/instabug_private_views/example/android/build.gradle delete mode 100644 packages/instabug_private_views/example/android/gradle.properties delete mode 100644 packages/instabug_private_views/example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100755 packages/instabug_private_views/example/android/gradlew delete mode 100644 packages/instabug_private_views/example/android/gradlew.bat delete mode 100644 packages/instabug_private_views/example/android/settings.gradle delete mode 100644 packages/instabug_private_views/example/assets/img.png delete mode 100644 packages/instabug_private_views/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/instabug_private_views/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/instabug_private_views/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/instabug_private_views/example/ios/Podfile delete mode 100644 packages/instabug_private_views/example/ios/Podfile.lock delete mode 100644 packages/instabug_private_views/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 packages/instabug_private_views/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/instabug_private_views/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/instabug_private_views/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 packages/instabug_private_views/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 packages/instabug_private_views/example/ios/Runner/AppDelegate.swift delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 packages/instabug_private_views/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/instabug_private_views/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/instabug_private_views/example/ios/Runner/Info.plist delete mode 100644 packages/instabug_private_views/example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 packages/instabug_private_views/example/ios/RunnerTests/PrivateViewApiTests.m delete mode 100644 packages/instabug_private_views/example/ios/RunnerTests/PrivateViewHostApiTests.m delete mode 100644 packages/instabug_private_views/example/ios/RunnerTests/RunnerTests-Bridging-Header.h delete mode 100644 packages/instabug_private_views/example/lib/main.dart delete mode 100644 packages/instabug_private_views/example/lib/private_view_page.dart delete mode 100644 packages/instabug_private_views/example/lib/widget/instabug_button.dart delete mode 100644 packages/instabug_private_views/example/lib/widget/instabug_text_field.dart delete mode 100644 packages/instabug_private_views/example/lib/widget/section_title.dart delete mode 100644 packages/instabug_private_views/example/pubspec.lock delete mode 100644 packages/instabug_private_views/example/pubspec.yaml delete mode 100644 packages/instabug_private_views/example/pubspec_overrides.yaml delete mode 100644 packages/instabug_private_views/ios/.gitignore delete mode 100644 packages/instabug_private_views/ios/Assets/.gitkeep delete mode 100644 packages/instabug_private_views/ios/Classes/InstabugPrivateViewsPlugin.h delete mode 100644 packages/instabug_private_views/ios/Classes/InstabugPrivateViewsPlugin.m delete mode 100644 packages/instabug_private_views/ios/Classes/instabug_private_views-Bridging-Header.h delete mode 100644 packages/instabug_private_views/ios/Resources/PrivacyInfo.xcprivacy delete mode 100644 packages/instabug_private_views/ios/instabug_private_views.podspec delete mode 100644 packages/instabug_private_views/lib/instabug_private_view.dart delete mode 100644 packages/instabug_private_views/lib/src/instabug_private_view.dart delete mode 100644 packages/instabug_private_views/lib/src/instabug_sliver_private_view.dart delete mode 100644 packages/instabug_private_views/lib/src/private_views_manager.dart delete mode 100644 packages/instabug_private_views/lib/src/visibility_detector/base_render_visibility_detector.dart delete mode 100644 packages/instabug_private_views/lib/src/visibility_detector/sliver_visibility_detector.dart delete mode 100644 packages/instabug_private_views/lib/src/visibility_detector/visibility_detector.dart delete mode 100644 packages/instabug_private_views/lib/src/visibility_detector/visibillity_utils.dart delete mode 100644 packages/instabug_private_views/pubspec.lock delete mode 100644 packages/instabug_private_views/pubspec.yaml delete mode 100644 packages/instabug_private_views/pubspec_overrides.yaml delete mode 100755 packages/instabug_private_views/release.sh delete mode 100644 packages/instabug_private_views/scripts/pigeon.sh delete mode 100644 packages/instabug_private_views/test/instabug_private_view_test.dart delete mode 100644 packages/instabug_private_views/test/instabug_sliver_private_view_test.dart diff --git a/packages/instabug_dio_interceptor/example/pubspec.lock b/packages/instabug_dio_interceptor/example/pubspec.lock index cc912e03a..c05b421e4 100644 --- a/packages/instabug_dio_interceptor/example/pubspec.lock +++ b/packages/instabug_dio_interceptor/example/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" cupertino_icons: dependency: "direct main" description: @@ -117,18 +117,18 @@ packages: 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: @@ -181,7 +181,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -194,10 +194,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" stream_channel: dependency: transitive description: @@ -210,10 +210,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" term_glyph: dependency: transitive description: @@ -226,10 +226,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" typed_data: dependency: transitive description: @@ -250,10 +250,10 @@ 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" web: dependency: transitive description: diff --git a/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart b/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart index 72b8af3ae..2210e9986 100644 --- a/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart +++ b/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart @@ -84,8 +84,7 @@ class InstabugDioInterceptor extends Interceptor { var responseBodySize = 0; if (responseHeaders.containsKey('content-length')) { // ignore: avoid_dynamic_calls - responseBodySize = - int.parse((responseHeaders['content-length'][0]) ?? '0'); + responseBodySize = int.parse((responseHeaders['content-length'][0]) ?? '0'); } else if (response.data != null) { responseBodySize = response.data.toString().length; } diff --git a/packages/instabug_dio_interceptor/pubspec.lock b/packages/instabug_dio_interceptor/pubspec.lock index 753b9a7fe..8a2504759 100644 --- a/packages/instabug_dio_interceptor/pubspec.lock +++ b/packages/instabug_dio_interceptor/pubspec.lock @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" convert: dependency: transitive description: @@ -326,18 +326,18 @@ packages: 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: @@ -518,7 +518,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_gen: dependency: transitive description: @@ -555,10 +555,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" stream_channel: dependency: transitive description: @@ -579,10 +579,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" tar: dependency: transitive description: @@ -603,26 +603,26 @@ packages: dependency: transitive 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" timing: dependency: transitive description: @@ -651,10 +651,10 @@ 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" watcher: dependency: transitive description: diff --git a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java index b79d82dbb..a12cff5d0 100644 --- a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/InstabugFlutterPlugin.java @@ -10,16 +10,20 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.instabug.flutter.generated.InstabugPrivateViewPigeon; import com.instabug.flutter.modules.ApmApi; import com.instabug.flutter.modules.BugReportingApi; import com.instabug.flutter.modules.CrashReportingApi; import com.instabug.flutter.modules.FeatureRequestsApi; import com.instabug.flutter.modules.InstabugApi; import com.instabug.flutter.modules.InstabugLogApi; +import com.instabug.flutter.modules.InstabugPrivateView; +import com.instabug.flutter.modules.PrivateViewManager; import com.instabug.flutter.modules.RepliesApi; import com.instabug.flutter.modules.SessionReplayApi; import com.instabug.flutter.modules.SurveysApi; -import com.instabug.library.internal.crossplatform.InternalCore; +import com.instabug.flutter.modules.capturing.BoundryCaptureManager; +import com.instabug.flutter.modules.capturing.PixelCopyCaptureManager; import java.util.concurrent.Callable; @@ -37,6 +41,9 @@ public class InstabugFlutterPlugin implements FlutterPlugin, ActivityAware { private static Activity activity; + private static PrivateViewManager privateViewManager; + + /** * Embedding v1 */ @@ -59,21 +66,31 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { activity = binding.getActivity(); + if (privateViewManager != null) { + privateViewManager.setActivity(activity); + } } @Override public void onDetachedFromActivityForConfigChanges() { activity = null; + privateViewManager.setActivity(null); + } @Override public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { activity = binding.getActivity(); + if (privateViewManager != null) { + privateViewManager.setActivity(activity); + } } @Override public void onDetachedFromActivity() { activity = null; + privateViewManager.setActivity(null); + } private static void register(Context context, BinaryMessenger messenger, FlutterRenderer renderer) { @@ -84,6 +101,9 @@ public Bitmap call() { } }; + privateViewManager = new PrivateViewManager(new InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi(messenger), new PixelCopyCaptureManager(), new BoundryCaptureManager(renderer)); + InstabugPrivateView.init(messenger, privateViewManager); + ApmApi.init(messenger); BugReportingApi.init(messenger); CrashReportingApi.init(messenger); @@ -93,6 +113,7 @@ public Bitmap call() { RepliesApi.init(messenger); SessionReplayApi.init(messenger); SurveysApi.init(messenger); + } @Nullable diff --git a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/model/ScreenshotResult.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/model/ScreenshotResult.java similarity index 89% rename from packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/model/ScreenshotResult.java rename to packages/instabug_flutter/android/src/main/java/com/instabug/flutter/model/ScreenshotResult.java index 107d431d2..66a3c51cb 100644 --- a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/model/ScreenshotResult.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/model/ScreenshotResult.java @@ -1,4 +1,4 @@ -package com.instabug.instabug_private_views.model; +package com.instabug.flutter.model; import android.graphics.Bitmap; diff --git a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index 503d1a643..ffe874919 100644 --- a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -6,13 +6,16 @@ import android.graphics.BitmapFactory; import android.net.Uri; import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; + import com.instabug.flutter.generated.InstabugPigeon; import com.instabug.flutter.util.ArgsRegistry; import com.instabug.flutter.util.Reflection; import com.instabug.flutter.util.ThreadManager; +import com.instabug.library.MaskingType; import com.instabug.library.ReproMode; import com.instabug.library.internal.crossplatform.CoreFeature; import com.instabug.library.internal.crossplatform.CoreFeaturesState; @@ -33,9 +36,11 @@ import com.instabug.library.model.NetworkLog; import com.instabug.library.screenshot.instacapture.ScreenshotRequest; import com.instabug.library.ui.onboarding.WelcomeMessage; + import io.flutter.FlutterInjector; import io.flutter.embedding.engine.loader.FlutterLoader; import io.flutter.plugin.common.BinaryMessenger; + import org.jetbrains.annotations.NotNull; import org.json.JSONObject; @@ -44,6 +49,7 @@ import java.io.InputStream; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -106,7 +112,9 @@ public Boolean isEnabled() { @NotNull @Override - public Boolean isBuilt() { return Instabug.isBuilt(); } + public Boolean isBuilt() { + return Instabug.isBuilt(); + } @Override public void init(@NonNull String token, @NonNull List invocationEvents, @NonNull String debugLogsLevel) { @@ -128,17 +136,28 @@ public void init(@NonNull String token, @NonNull List invocationEvents, Instabug.setScreenshotProvider(screenshotProvider); - try{ + try { Class myClass = Class.forName("com.instabug.library.Instabug"); // Enable/Disable native user steps capturing Method method = myClass.getDeclaredMethod("shouldDisableNativeUserStepsCapturing", boolean.class); method.setAccessible(true); - method.invoke(null,true); + method.invoke(null, true); } catch (Exception e) { e.printStackTrace(); } } + @Override + public void enableAutoMasking(@NonNull List autoMasking) { + int[] autoMaskingArray = new int[autoMasking.size()]; + for (int i = 0; i < autoMasking.size(); i++) { + String key = autoMasking.get(i); + autoMaskingArray[i] = ArgsRegistry.autoMasking.get(key); + } + + Instabug.setAutoMaskScreenshotsTypes(Arrays.copyOfRange(autoMaskingArray, 0, autoMaskingArray.length)); + } + @Override public void show() { Instabug.show(); @@ -177,7 +196,7 @@ public void setEnableUserSteps(@NonNull Boolean isEnabled) { @Override - public void logUserSteps(@NonNull String gestureType, @NonNull String message,@Nullable String viewName) { + public void logUserSteps(@NonNull String gestureType, @NonNull String message, @Nullable String viewName) { try { final String stepType = ArgsRegistry.gestureStepType.get(gestureType); final long timeStamp = System.currentTimeMillis(); @@ -186,7 +205,7 @@ public void logUserSteps(@NonNull String gestureType, @NonNull String message,@N Method method = Reflection.getMethod(Class.forName("com.instabug.library.Instabug"), "addUserStep", long.class, String.class, String.class, String.class, String.class); if (method != null) { - if (viewName != null){ + if (viewName != null) { view = viewName; } @@ -393,7 +412,7 @@ public void setReproStepsConfig(@Nullable String bugMode, @Nullable String crash } @Override - public void reportScreenChange(@NonNull String screenName) { + public void reportScreenChange(byte[] image, @NonNull String screenName) { try { Method method = Reflection.getMethod(Class.forName("com.instabug.library.Instabug"), "reportScreenChange", Bitmap.class, String.class); @@ -404,7 +423,7 @@ public void reportScreenChange(@NonNull String screenName) { Method reportViewChange = Reflection.getMethod(Class.forName("com.instabug.library.Instabug"), "reportCurrentViewChange", String.class); if (reportViewChange != null) { - reportViewChange.invoke(null,screenName); + reportViewChange.invoke(null, screenName); } } catch (Exception e) { diff --git a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/InstabugPrivateView.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugPrivateView.java similarity index 60% rename from packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/InstabugPrivateView.java rename to packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugPrivateView.java index 6a20b768d..b0a41cfcd 100644 --- a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/InstabugPrivateView.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugPrivateView.java @@ -1,8 +1,10 @@ -package com.instabug.instabug_private_views.modules; +package com.instabug.flutter.modules; -import com.instabug.flutter.modules.InstabugApi; +import android.os.Handler; +import android.os.Looper; + +import com.instabug.flutter.generated.InstabugPrivateViewPigeon; import com.instabug.flutter.util.privateViews.ScreenshotCaptor; -import com.instabug.instabug_private_views.generated.InstabugPrivateViewPigeon; import com.instabug.library.internal.crossplatform.InternalCore; import io.flutter.plugin.common.BinaryMessenger; @@ -11,24 +13,37 @@ public class InstabugPrivateView implements InstabugPrivateViewPigeon.InstabugPr PrivateViewManager privateViewManager; public static void init(BinaryMessenger messenger, PrivateViewManager privateViewManager) { - final InstabugPrivateView api = new InstabugPrivateView(messenger,privateViewManager); + final InstabugPrivateView api = new InstabugPrivateView(messenger, privateViewManager); InstabugPrivateViewPigeon.InstabugPrivateViewHostApi.setup(messenger, api); } public InstabugPrivateView(BinaryMessenger messenger, PrivateViewManager privateViewManager) { this.privateViewManager = privateViewManager; InstabugPrivateViewPigeon.InstabugPrivateViewHostApi.setup(messenger, this); - + init(); } + static long time = System.currentTimeMillis(); + @Override public void init() { InstabugApi.setScreenshotCaptor(new ScreenshotCaptor() { @Override public void capture(CapturingCallback listener) { - privateViewManager.mask(listener); + + (new Handler(Looper.getMainLooper())).postDelayed(new Runnable() { + @Override + public void run() { + time = System.currentTimeMillis(); + +// time = System.currentTimeMillis(); + privateViewManager.mask(listener); + + } + }, 300); + } - },InternalCore.INSTANCE); + }, InternalCore.INSTANCE); } } diff --git a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/PrivateViewManager.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/PrivateViewManager.java similarity index 91% rename from packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/PrivateViewManager.java rename to packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/PrivateViewManager.java index d1d25d416..fd105be5a 100644 --- a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/PrivateViewManager.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/PrivateViewManager.java @@ -1,4 +1,4 @@ -package com.instabug.instabug_private_views.modules; +package com.instabug.flutter.modules; import android.app.Activity; import android.graphics.Bitmap; @@ -9,12 +9,12 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import com.instabug.flutter.generated.InstabugPrivateViewPigeon; +import com.instabug.flutter.model.ScreenshotResult; +import com.instabug.flutter.modules.capturing.CaptureManager; +import com.instabug.flutter.modules.capturing.ScreenshotResultCallback; import com.instabug.flutter.util.ThreadManager; import com.instabug.flutter.util.privateViews.ScreenshotCaptor; -import com.instabug.instabug_private_views.generated.InstabugPrivateViewPigeon; -import com.instabug.instabug_private_views.model.ScreenshotResult; -import com.instabug.instabug_private_views.modules.capturing.CaptureManager; -import com.instabug.instabug_private_views.modules.capturing.ScreenshotResultCallback; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -85,6 +85,7 @@ public void run() { @Override public void onScreenshotResult(ScreenshotResult result) { processScreenshot(result, privateViews, latch, capturingCallback); + } @Override @@ -113,6 +114,9 @@ private void processScreenshot(ScreenshotResult result, AtomicReference privateViews) float bottom = privateViews.get(i + 3).floatValue() * pixelRatio; canvas.drawRect(left, top, right, bottom, paint); // Mask private view } - } catch (Exception e){ -e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); } } } \ No newline at end of file diff --git a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/BoundryCaptureManager.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/BoundryCaptureManager.java similarity index 91% rename from packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/BoundryCaptureManager.java rename to packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/BoundryCaptureManager.java index 4c9f3d047..6f8409749 100644 --- a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/BoundryCaptureManager.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/BoundryCaptureManager.java @@ -1,12 +1,13 @@ -package com.instabug.instabug_private_views.modules.capturing; +package com.instabug.flutter.modules.capturing; import android.app.Activity; import android.graphics.Bitmap; import android.util.DisplayMetrics; import android.view.View; +import com.instabug.flutter.model.ScreenshotResult; import com.instabug.flutter.util.ThreadManager; -import com.instabug.instabug_private_views.model.ScreenshotResult; + import io.flutter.embedding.engine.renderer.FlutterRenderer; public class BoundryCaptureManager implements CaptureManager { diff --git a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/CaptureManager.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/CaptureManager.java similarity index 71% rename from packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/CaptureManager.java rename to packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/CaptureManager.java index 4b6ccff84..f15aa4780 100644 --- a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/CaptureManager.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/CaptureManager.java @@ -1,4 +1,4 @@ -package com.instabug.instabug_private_views.modules.capturing; +package com.instabug.flutter.modules.capturing; import android.app.Activity; diff --git a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/PixelCopyCaptureManager.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/PixelCopyCaptureManager.java similarity index 96% rename from packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/PixelCopyCaptureManager.java rename to packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/PixelCopyCaptureManager.java index f8f3d2cca..be19f1ca6 100644 --- a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/PixelCopyCaptureManager.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/PixelCopyCaptureManager.java @@ -1,4 +1,4 @@ -package com.instabug.instabug_private_views.modules.capturing; +package com.instabug.flutter.modules.capturing; import android.app.Activity; import android.graphics.Bitmap; @@ -11,7 +11,7 @@ import androidx.annotation.RequiresApi; -import com.instabug.instabug_private_views.model.ScreenshotResult; +import com.instabug.flutter.model.ScreenshotResult; import com.instabug.library.util.memory.MemoryUtils; import io.flutter.embedding.android.FlutterActivity; diff --git a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/ScreenshotResultCallback.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/ScreenshotResultCallback.java similarity index 50% rename from packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/ScreenshotResultCallback.java rename to packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/ScreenshotResultCallback.java index fd6c0f23f..e01b9b95d 100644 --- a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/modules/capturing/ScreenshotResultCallback.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/capturing/ScreenshotResultCallback.java @@ -1,6 +1,7 @@ -package com.instabug.instabug_private_views.modules.capturing; +package com.instabug.flutter.modules.capturing; -import com.instabug.instabug_private_views.model.ScreenshotResult; + +import com.instabug.flutter.model.ScreenshotResult; public interface ScreenshotResultCallback { void onScreenshotResult(ScreenshotResult screenshotResult); diff --git a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/util/ArgsRegistry.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/util/ArgsRegistry.java index ec37144b8..2c37e500d 100644 --- a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/util/ArgsRegistry.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/util/ArgsRegistry.java @@ -9,6 +9,7 @@ import com.instabug.featuresrequest.ActionType; import com.instabug.library.InstabugColorTheme; import com.instabug.library.InstabugCustomTextPlaceHolder.Key; +import com.instabug.library.MaskingType; import com.instabug.library.OnSdkDismissCallback.DismissType; import com.instabug.library.ReproMode; import com.instabug.library.extendedbugreport.ExtendedBugReport; @@ -59,6 +60,14 @@ public T get(Object key) { put("ColorTheme.light", InstabugColorTheme.InstabugColorThemeLight); put("ColorTheme.dark", InstabugColorTheme.InstabugColorThemeDark); }}; + + public static final ArgsMap autoMasking = new ArgsMap() {{ + put("AutoMasking.labels", MaskingType.LABELS); + put("AutoMasking.textInputs", MaskingType.TEXT_INPUTS); + put("AutoMasking.media", MaskingType.MEDIA); + put("AutoMasking.none", MaskingType.MASK_NOTHING); + }}; + public static ArgsMap nonFatalExceptionLevel = new ArgsMap() {{ put("NonFatalExceptionLevel.critical", IBGNonFatalException.Level.CRITICAL); put("NonFatalExceptionLevel.error", IBGNonFatalException.Level.ERROR); diff --git a/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/ArgsRegistryTest.java b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/ArgsRegistryTest.java index 04082b07e..9a35ef83b 100644 --- a/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/ArgsRegistryTest.java +++ b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/ArgsRegistryTest.java @@ -9,6 +9,7 @@ import com.instabug.flutter.util.ArgsRegistry; import com.instabug.library.InstabugColorTheme; import com.instabug.library.InstabugCustomTextPlaceHolder.Key; +import com.instabug.library.MaskingType; import com.instabug.library.OnSdkDismissCallback.DismissType; import com.instabug.library.ReproMode; import com.instabug.library.extendedbugreport.ExtendedBugReport; @@ -166,6 +167,21 @@ public void testExtendedBugReportStates() { } } + @Test + public void testAutoMasking() { + Integer[] values = { + MaskingType.MASK_NOTHING, + MaskingType.MEDIA, + MaskingType.LABELS, + MaskingType.TEXT_INPUTS, + + }; + + for (Integer value : values) { + assertTrue(ArgsRegistry.autoMasking.containsValue(value)); + } + } + @Test public void testReproModes() { Integer[] values = { diff --git a/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index f0de4c401..d7b3e36fd 100644 --- a/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -41,6 +41,7 @@ import com.instabug.library.InstabugCustomTextPlaceHolder; import com.instabug.library.IssueType; import com.instabug.library.LogLevel; +import com.instabug.library.MaskingType; import com.instabug.library.Platform; import com.instabug.library.ReproConfigurations; import com.instabug.library.ReproMode; @@ -477,7 +478,7 @@ public void testSetReproStepsConfig() { public void testReportScreenChange() { String screenName = "HomeScreen"; - api.reportScreenChange(screenName); + api.reportScreenChange(null,screenName); reflected.verify(() -> MockReflected.reportScreenChange(null, screenName)); } @@ -689,4 +690,16 @@ public void testLogUserSteps() { } + @Test + public void testAutoMasking() { + String maskLabel = "AutoMasking.labels"; + String maskTextInputs = "AutoMasking.textInputs"; + String maskMedia = "AutoMasking.media"; + String maskNone = "AutoMasking.none"; + + + api.enableAutoMasking(List.of(maskLabel, maskMedia, maskTextInputs,maskNone)); + + mInstabug.verify(() -> Instabug.setAutoMaskScreenshotsTypes(MaskingType.LABELS,MaskingType.MEDIA,MaskingType.TEXT_INPUTS,MaskingType.MASK_NOTHING)); + } } diff --git a/packages/instabug_flutter/example/ios/InstabugTests/ArgsRegistryTests.m b/packages/instabug_flutter/example/ios/InstabugTests/ArgsRegistryTests.m index a59f88d4e..6e346cf33 100644 --- a/packages/instabug_flutter/example/ios/InstabugTests/ArgsRegistryTests.m +++ b/packages/instabug_flutter/example/ios/InstabugTests/ArgsRegistryTests.m @@ -269,4 +269,17 @@ - (void)testPlaceholders { } } +- (void)testAutoaAsking { + NSArray *values = @[ + @(IBGAutoMaskScreenshotOptionMedia), + @(IBGAutoMaskScreenshotOptionLabels), + @(IBGAutoMaskScreenshotOptionTextInputs), + @(IBGAutoMaskScreenshotOptionMaskNothing) + ]; + + for (NSNumber *value in values) { + XCTAssertTrue([[ArgsRegistry.autoMasking allValues] containsObject:value]); + } +} + @end diff --git a/packages/instabug_flutter/example/ios/InstabugTests/InstabugApiTests.m b/packages/instabug_flutter/example/ios/InstabugTests/InstabugApiTests.m index 4d7898c2b..c4b61064c 100644 --- a/packages/instabug_flutter/example/ios/InstabugTests/InstabugApiTests.m +++ b/packages/instabug_flutter/example/ios/InstabugTests/InstabugApiTests.m @@ -333,7 +333,7 @@ - (void)testReportScreenChange { NSString *screenName = @"HomeScreen"; FlutterError *error; - [self.api reportScreenChangeScreenName:screenName error:&error]; + [self.api reportScreenChangeImage:nil screenName:screenName error:&error]; OCMVerify([self.mInstabug logViewDidAppearEvent:screenName]); } @@ -622,5 +622,12 @@ - (void)testLogUserStepsGestureType{ XCTAssertNil(error, @"Error should be nil"); } +- (void)testAutoMasking { + NSArray *autoMaskingTypes = @[@"AutoMasking.labels", @"AutoMasking.textInputs",@"AutoMasking.media",@"AutoMasking.none"]; + FlutterError *error; + + [self.api enableAutoMaskingAutoMasking:autoMaskingTypes error:&error]; + OCMVerify([self.mInstabug setAutoMaskScreenshots: (IBGAutoMaskScreenshotOptionMaskNothing | IBGAutoMaskScreenshotOptionTextInputs | IBGAutoMaskScreenshotOptionLabels | IBGAutoMaskScreenshotOptionMedia)]); +} @end diff --git a/packages/instabug_flutter/example/ios/Podfile.lock b/packages/instabug_flutter/example/ios/Podfile.lock index 4d0647f67..6b1fb5687 100644 --- a/packages/instabug_flutter/example/ios/Podfile.lock +++ b/packages/instabug_flutter/example/ios/Podfile.lock @@ -39,4 +39,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 87a326d297554318d9004349a35d82ffe3f0c228 -COCOAPODS: 1.14.3 +COCOAPODS: 1.16.2 diff --git a/packages/instabug_flutter/example/lib/main.dart b/packages/instabug_flutter/example/lib/main.dart index 95c49a49a..fcaec264b 100644 --- a/packages/instabug_flutter/example/lib/main.dart +++ b/packages/instabug_flutter/example/lib/main.dart @@ -25,17 +25,29 @@ import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager import 'package:instabug_flutter_example/src/widget/section_title.dart'; part 'src/components/fatal_crashes_content.dart'; + part 'src/components/flows_content.dart'; + part 'src/components/network_content.dart'; + part 'src/components/non_fatal_crashes_content.dart'; + part 'src/components/page.dart'; + part 'src/components/traces_content.dart'; + part 'src/screens/apm_page.dart'; + part 'src/screens/complex_page.dart'; + part 'src/screens/crashes_page.dart'; + part 'src/screens/my_home_page.dart'; + part 'src/screens/screen_capture_premature_extension_page.dart'; + part 'src/screens/screen_loading_page.dart'; + part 'src/screens/user_steps_page.dart'; void main() { @@ -51,12 +63,13 @@ void main() { Instabug.setWelcomeMessageMode(WelcomeMessageMode.disabled); - FlutterError.onError = (FlutterErrorDetails details) { Zone.current.handleUncaughtError(details.exception, details.stack!); }; - runApp(const InstabugUserSteps(child: MyApp())); // runApp(const MyApp()); + runApp( + const InstabugWidget(automasking: [AutoMasking.labels,AutoMasking.textInputs,AutoMasking.media], child: MyApp()), + ); }, CrashReporting.reportCrash, ); diff --git a/packages/instabug_flutter/example/lib/src/app_routes.dart b/packages/instabug_flutter/example/lib/src/app_routes.dart index ee3c3b06b..d3947ff7b 100644 --- a/packages/instabug_flutter/example/lib/src/app_routes.dart +++ b/packages/instabug_flutter/example/lib/src/app_routes.dart @@ -1,5 +1,6 @@ import 'package:flutter/widgets.dart' show BuildContext; import 'package:instabug_flutter_example/main.dart'; +import 'package:instabug_flutter_example/src/screens/private_view_page.dart'; final appRoutes = { /// ["/"] route name should only be used with [onGenerateRoute:] when no @@ -10,6 +11,8 @@ final appRoutes = { const MyHomePage(title: 'Flutter Demo Home Pag'), CrashesPage.screenName: (BuildContext context) => const CrashesPage(), ComplexPage.screenName: (BuildContext context) => const ComplexPage(), + PrivateViewPage.screenName: (BuildContext context) => const PrivateViewPage(), + ApmPage.screenName: (BuildContext context) => const ApmPage(), ScreenLoadingPage.screenName: (BuildContext context) => const ScreenLoadingPage(), diff --git a/packages/instabug_flutter/example/lib/src/components/fatal_crashes_content.dart b/packages/instabug_flutter/example/lib/src/components/fatal_crashes_content.dart index c262b63a6..71ea2d59c 100644 --- a/packages/instabug_flutter/example/lib/src/components/fatal_crashes_content.dart +++ b/packages/instabug_flutter/example/lib/src/components/fatal_crashes_content.dart @@ -18,10 +18,12 @@ class FatalCrashesContent extends StatelessWidget { mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: [ - InstabugButton( - text: 'Throw Exception', - onPressed: () => throwUnhandledException( - Exception('This is a generic exception.')), + InstabugPrivateView( + child: InstabugButton( + text: 'Throw Exception', + onPressed: () => throwUnhandledException( + Exception('This is a generic exception.')), + ), ), InstabugButton( text: 'Throw StateError', diff --git a/packages/instabug_flutter/example/lib/src/components/network_content.dart b/packages/instabug_flutter/example/lib/src/components/network_content.dart index 77ac744b2..d531e17bd 100644 --- a/packages/instabug_flutter/example/lib/src/components/network_content.dart +++ b/packages/instabug_flutter/example/lib/src/components/network_content.dart @@ -18,9 +18,11 @@ class _NetworkContentState extends State { Widget build(BuildContext context) { return Column( children: [ - InstabugClipboardInput( - label: 'Endpoint Url', - controller: endpointUrlController, + InstabugPrivateView( + child: InstabugClipboardInput( + label: 'Endpoint Url', + controller: endpointUrlController, + ), ), InstabugButton( text: 'Send Request To Url', diff --git a/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart b/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart index ae2d2c53e..081269d83 100644 --- a/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart +++ b/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart @@ -60,7 +60,7 @@ class _MyHomePageState extends State { } void reportScreenChange() { - Instabug.reportScreenChange(screenNameController.text); + Instabug.reportScreenChange(null,screenNameController.text); } void sendBugReport() { @@ -170,7 +170,7 @@ class _MyHomePageState extends State { context, MaterialPageRoute( builder: (context) => const PrivateViewPage(), - settings: const RouteSettings(name: ComplexPage.screenName), + settings: const RouteSettings(name: PrivateViewPage.screenName), ), ); } @@ -318,9 +318,11 @@ class _MyHomePageState extends State { onPressed: showManualSurvey, text: 'Show Multiple Questions Survey', ), - InstabugButton( - onPressed: showFeatureRequests, - text: 'Show Feature Requests', + InstabugPrivateView( + child: InstabugButton( + onPressed: showFeatureRequests, + text: 'Show Feature Requests', + ), ), InstabugButton( onPressed: _navigateToCrashes, diff --git a/packages/instabug_flutter/example/lib/src/screens/private_view_page.dart b/packages/instabug_flutter/example/lib/src/screens/private_view_page.dart index 56a58dacf..585d7cc78 100644 --- a/packages/instabug_flutter/example/lib/src/screens/private_view_page.dart +++ b/packages/instabug_flutter/example/lib/src/screens/private_view_page.dart @@ -1,7 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter_example/src/widget/instabug_button.dart'; +import 'package:instabug_flutter_example/src/widget/section_title.dart'; import 'package:video_player/video_player.dart'; class PrivateViewPage extends StatefulWidget { + static const screenName = 'private'; + const PrivateViewPage({Key? key}) : super(key: key); @override @@ -10,6 +15,23 @@ class PrivateViewPage extends StatefulWidget { class _PrivateViewPageState extends State { late VideoPlayerController _controller; + double _currentSliderValue = 20.0; + + RangeValues _currentRangeValues = const RangeValues(40, 80); + + String? _sliderStatus; + + bool? isChecked = true; + + int? _selectedValue = 1; + + bool light = true; + double _scale = 1.0; // Initial scale of the image + + TextEditingController _controller2 = TextEditingController(); + + String _currentValue = ''; + List _items = List.generate(20, (index) => 'Item ${index + 1}'); @override void initState() { @@ -20,6 +42,11 @@ class _PrivateViewPageState extends State { )..initialize().then((_) { setState(() {}); }); + _controller2.addListener(() { + setState(() { + _currentValue = _controller2.text; + }); + }); } @override @@ -28,18 +55,205 @@ class _PrivateViewPageState extends State { super.dispose(); } + void _handleRadioValueChanged(int? value) { + setState(() { + _selectedValue = value; + }); + } + + int count = 200; + final list=List.generate( + 20, + (_) => InstabugPrivateView( + child: Container( + margin: const EdgeInsets.all(2), + width: 4, + height: 4, + color: Colors.red, + ), + )); @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text("Private Views page")), - body: const SingleChildScrollView( - child: Padding( - padding: EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [], - ), + appBar: AppBar(title: const Text("Private Views page")), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 16), + const InstabugPrivateView( + child: Text( + 'Private TextView', + style: TextStyle(fontSize: 18), + textAlign: TextAlign.center, + ), + ), + const SizedBox(height: 16), + Wrap( + children: list, + ), + const SizedBox(height: 16), + InstabugPrivateView( + child: ElevatedButton( + onPressed: () { + const snackBar = SnackBar( + content: Text('Hello, you clicked on a private button'), + ); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + }, + child: const Text('I am a private button'), + ), + ), + const SizedBox(height: 16), + const BackButton(), + const SectionTitle('TextInput'), + Column( + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + // Set the padding value + child: Column( + children: [ + TextField( + key: const Key('text_field'), + controller: _controller2, + // Bind the controller to the TextField + decoration: const InputDecoration( + labelText: + "Type something in a text field with key", + border: OutlineInputBorder(), + ), + ), + InstabugPrivateView( + child: TextField( + controller: _controller2, + // Bind the controller to the TextField + decoration: const InputDecoration( + labelText: "Private view", + border: OutlineInputBorder(), + ), + ), + ), + InstabugPrivateView( + child: TextField( + controller: _controller2, + // Bind the controller to the TextField + obscureText: true, + decoration: const InputDecoration( + border: OutlineInputBorder(), + labelText: 'Password', + ), + ), + ), + TextFormField( + obscureText: true, + controller: _controller2, + // Bind the controller to the TextField + decoration: const InputDecoration( + icon: Icon(Icons.person), + hintText: 'What do people call you?', + labelText: 'Name *', + ), + onSaved: (String? value) { + // This optional block of code can be used to run + // code when the user saves the form. + }, + validator: (String? value) { + return (value != null && value.contains('@')) + ? 'Do not use the @ char.' + : null; + }, + ), + ], + ), + ), + ], + ), + InstabugPrivateView( + child: Image.asset( + 'assets/img.png', + // Add this image to your assets folder + height: 100, + ), + ), + const SizedBox(height: 33), + const InstabugPrivateView( + child: TextField( + obscureText: true, + decoration: InputDecoration( + hintText: 'password', + labelText: 'Password', + border: OutlineInputBorder(), + ), + ), + ), + const SizedBox(height: 16), + const TextField( + keyboardType: TextInputType.emailAddress, + decoration: InputDecoration( + hintText: 'Email', + labelText: 'Email', + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 16), + const Column( + children: [ + InstabugPrivateView( + child: Text( + 'Private TextView in column', + style: TextStyle(fontSize: 18), + textAlign: TextAlign.center, + ), + ), + SizedBox( + height: 10, + ), + Text( + 'TextView in column', + style: TextStyle(fontSize: 18), + textAlign: TextAlign.center, + ), + ], + ), + const SizedBox(height: 24), + Container( + height: 300, + child: _controller.value.isInitialized + ? AspectRatio( + aspectRatio: _controller.value.aspectRatio, + child: VideoPlayer(_controller), + ) + : const Center(child: CircularProgressIndicator()), + ), + const SizedBox(height: 24), + const SizedBox(height: 24), + const SizedBox(height: 24), + SizedBox( + height: 200, + child: CustomScrollView( + slivers: [ + InstabugSliverPrivateView( + sliver: SliverToBoxAdapter( + child: Container( + color: Colors.red, + child: const Text( + "Private Sliver Widget", + style: TextStyle(fontSize: 18), + textAlign: TextAlign.center, + ), + ), + ), + ) + ], + ), + ) + ], ), - )); + ), + ), + ); } } diff --git a/packages/instabug_flutter/example/lib/src/widget/nested_view.dart b/packages/instabug_flutter/example/lib/src/widget/nested_view.dart index e61099f8c..8ef9e46ad 100644 --- a/packages/instabug_flutter/example/lib/src/widget/nested_view.dart +++ b/packages/instabug_flutter/example/lib/src/widget/nested_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter_example/main.dart'; class NestedView extends StatelessWidget { @@ -31,10 +32,12 @@ class NestedView extends StatelessWidget { Row( children: List.generate( breadth, - (index) => NestedView( - depth: depth - 1, - breadth: breadth, - child: child, + (index) => InstabugPrivateView( + child: NestedView( + depth: depth - 1, + breadth: breadth, + child: child, + ), ), ), ), diff --git a/packages/instabug_flutter/example/pubspec.lock b/packages/instabug_flutter/example/pubspec.lock index 2fe784636..33aec3774 100644 --- a/packages/instabug_flutter/example/pubspec.lock +++ b/packages/instabug_flutter/example/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" csslib: dependency: transitive description: @@ -140,18 +140,18 @@ packages: 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: @@ -228,7 +228,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -241,10 +241,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" stream_channel: dependency: transitive description: @@ -257,10 +257,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" sync_http: dependency: transitive description: @@ -281,10 +281,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" typed_data: dependency: transitive description: @@ -345,10 +345,10 @@ 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" web: dependency: transitive description: @@ -361,10 +361,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.4" sdks: dart: ">=3.5.0 <4.0.0" flutter: ">=3.24.0" diff --git a/packages/instabug_flutter/ios/Classes/InstabugFlutterPlugin.m b/packages/instabug_flutter/ios/Classes/InstabugFlutterPlugin.m index 9b9182ae7..12ab5a58b 100644 --- a/packages/instabug_flutter/ios/Classes/InstabugFlutterPlugin.m +++ b/packages/instabug_flutter/ios/Classes/InstabugFlutterPlugin.m @@ -9,6 +9,8 @@ #import "RepliesApi.h" #import "SessionReplayApi.h" #import "SurveysApi.h" +#import "PrivateViewApi.h" +#import "PrivateViewHostApi.h" @implementation InstabugFlutterPlugin @@ -22,6 +24,9 @@ + (void)registerWithRegistrar:(NSObject *)registrar { InitRepliesApi([registrar messenger]); InitSessionReplayApi([registrar messenger]); InitSurveysApi([registrar messenger]); + PrivateViewApi* privateViewApi = InitPrivateViewApi([registrar messenger],registrar); + InitPrivateViewApi([registrar messenger], registrar); + InitPrivateViewHostApi([registrar messenger], privateViewApi); } @end diff --git a/packages/instabug_flutter/ios/Classes/Modules/InstabugApi.m b/packages/instabug_flutter/ios/Classes/Modules/InstabugApi.m index ba809f00b..e22f03453 100644 --- a/packages/instabug_flutter/ios/Classes/Modules/InstabugApi.m +++ b/packages/instabug_flutter/ios/Classes/Modules/InstabugApi.m @@ -209,7 +209,7 @@ - (void)setCustomBrandingImageLight:(NSString *)light dark:(NSString *)dark erro } } -- (void)reportScreenChangeScreenName:(NSString *)screenName error:(FlutterError *_Nullable *_Nonnull)error { +- (void)reportScreenChangeImage:(nullable FlutterStandardTypedData *)image screenName:(nonnull NSString *)screenName error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { SEL setPrivateApiSEL = NSSelectorFromString(@"logViewDidAppearEvent:"); if ([[Instabug class] respondsToSelector:setPrivateApiSEL]) { NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[Instabug class] methodSignatureForSelector:setPrivateApiSEL]]; @@ -416,6 +416,20 @@ - (void)setEnableUserStepsIsEnabled:(nonnull NSNumber *)isEnabled error:(Flutter Instabug.trackUserSteps = isEnabled.boolValue; } +- (void)enableAutoMaskingAutoMasking:(nonnull NSArray *)autoMasking error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { + IBGAutoMaskScreenshotOption resolvedEvents = 0; + + for (NSString *event in autoMasking) { + resolvedEvents |= (ArgsRegistry.autoMasking[event]).integerValue; + } + + [Instabug setAutoMaskScreenshots: resolvedEvents]; + +} + + + + + (void)setScreenshotMaskingHandler:(nullable void (^)(UIImage * _Nonnull __strong, void (^ _Nonnull __strong)(UIImage * _Nonnull __strong)))maskingHandler { [Instabug setScreenshotMaskingHandler:maskingHandler]; diff --git a/packages/instabug_private_views/ios/Classes/Modules/PrivateViewApi.h b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.h similarity index 100% rename from packages/instabug_private_views/ios/Classes/Modules/PrivateViewApi.h rename to packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.h diff --git a/packages/instabug_private_views/ios/Classes/Modules/PrivateViewApi.m b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m similarity index 83% rename from packages/instabug_private_views/ios/Classes/Modules/PrivateViewApi.m rename to packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m index 3b3a8cf7c..3bebca63b 100644 --- a/packages/instabug_private_views/ios/Classes/Modules/PrivateViewApi.m +++ b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m @@ -1,5 +1,5 @@ #import "PrivateViewApi.h" -#import "FlutterPluginRegistrar+FlutterEngine.h" +#import "../Util/FlutterPluginRegistrar+FlutterEngine.h" extern PrivateViewApi* InitPrivateViewApi( id messenger, @@ -21,19 +21,25 @@ - (instancetype)initWithFlutterApi:(InstabugPrivateViewFlutterApi *)api return self; } +static long long currentTimeMillis; + + - (void)mask:(UIImage *)screenshot completion:(void (^)(UIImage *))completion { __weak typeof(self) weakSelf = self; -// Capture screenshot in parallel - + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + + currentTimeMillis = (long long)([[NSDate date] timeIntervalSince1970] * 1000); [self.flutterApi getPrivateViewsWithCompletion:^(NSArray *rectangles, FlutterError *error) { UIImage *capturedScreenshot = [self captureScreenshot]; - [weakSelf handlePrivateViewsResult:rectangles - error:error - screenshot:capturedScreenshot - completion:completion]; - }]; + + [weakSelf handlePrivateViewsResult:rectangles + error:error + screenshot:capturedScreenshot + completion:completion]; + }]; + }); } #pragma mark - Private Methods @@ -66,7 +72,14 @@ - (void)handlePrivateViewsResult:(NSArray *)rectangles NSArray *privateViews = [self convertToRectangles:rectangles]; UIImage *maskedScreenshot = [self drawMaskedImage:screenshot withPrivateViews:privateViews]; + static long long currentTimeMillis2; + currentTimeMillis2 = (long long)([[NSDate date] timeIntervalSince1970] * 1000); + + long long timeDifference = currentTimeMillis2 - currentTimeMillis; + completion(maskedScreenshot); + NSLog(@"Time Difference: %lld ms (Last: %lld, Current: %lld)", timeDifference, currentTimeMillis2, currentTimeMillis); + } diff --git a/packages/instabug_private_views/ios/Classes/Modules/PrivateViewHostApi.h b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewHostApi.h similarity index 100% rename from packages/instabug_private_views/ios/Classes/Modules/PrivateViewHostApi.h rename to packages/instabug_flutter/ios/Classes/Modules/PrivateViewHostApi.h diff --git a/packages/instabug_private_views/ios/Classes/Modules/PrivateViewHostApi.m b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewHostApi.m similarity index 97% rename from packages/instabug_private_views/ios/Classes/Modules/PrivateViewHostApi.m rename to packages/instabug_flutter/ios/Classes/Modules/PrivateViewHostApi.m index 6b1c26c4d..e7dbea5cf 100644 --- a/packages/instabug_private_views/ios/Classes/Modules/PrivateViewHostApi.m +++ b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewHostApi.m @@ -16,8 +16,12 @@ extern void InitPrivateViewHostApi(id _Nonnull messenger @implementation PrivateViewHostApi + - (void)initWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { [InstabugApi setScreenshotMaskingHandler:^(UIImage * _Nonnull screenshot, void (^ _Nonnull completion)(UIImage * _Nullable)) { + + + [self.privateViewApi mask:screenshot completion:^(UIImage * _Nonnull maskedImage) { if (maskedImage != nil) { completion(maskedImage); diff --git a/packages/instabug_flutter/ios/Classes/Util/ArgsRegistry.h b/packages/instabug_flutter/ios/Classes/Util/ArgsRegistry.h index f6f5347bc..ad94d22d0 100644 --- a/packages/instabug_flutter/ios/Classes/Util/ArgsRegistry.h +++ b/packages/instabug_flutter/ios/Classes/Util/ArgsRegistry.h @@ -18,6 +18,7 @@ typedef NSDictionary ArgsDictionary; + (ArgsDictionary *)extendedBugReportStates; + (ArgsDictionary *)reproModes; + (ArgsDictionary *)nonFatalExceptionLevel; ++ (ArgsDictionary *)autoMasking; + (ArgsDictionary *)locales; + (ArgsDictionary *)userStepsGesture; diff --git a/packages/instabug_flutter/ios/Classes/Util/ArgsRegistry.m b/packages/instabug_flutter/ios/Classes/Util/ArgsRegistry.m index 6cb9eae31..b2e1d6c9f 100644 --- a/packages/instabug_flutter/ios/Classes/Util/ArgsRegistry.m +++ b/packages/instabug_flutter/ios/Classes/Util/ArgsRegistry.m @@ -43,6 +43,18 @@ + (ArgsDictionary *)floatingButtonEdges { }; } ++ (ArgsDictionary *)autoMasking { + return @{ + @"AutoMasking.labels" : @(IBGAutoMaskScreenshotOptionLabels), + @"AutoMasking.textInputs" : @(IBGAutoMaskScreenshotOptionTextInputs), + @"AutoMasking.media" : @(IBGAutoMaskScreenshotOptionMedia), + @"AutoMasking.none" : @(IBGAutoMaskScreenshotOptionMaskNothing +), + + }; +} + + + (ArgsDictionary *)recordButtonPositions { return @{ @"Position.topLeft" : @(IBGPositionTopLeft), diff --git a/packages/instabug_private_views/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.h b/packages/instabug_flutter/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.h similarity index 100% rename from packages/instabug_private_views/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.h rename to packages/instabug_flutter/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.h diff --git a/packages/instabug_private_views/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.m b/packages/instabug_flutter/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.m similarity index 100% rename from packages/instabug_private_views/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.m rename to packages/instabug_flutter/ios/Classes/Util/FlutterPluginRegistrar+FlutterEngine.m diff --git a/packages/instabug_flutter/lib/instabug_flutter.dart b/packages/instabug_flutter/lib/instabug_flutter.dart index 26bf50459..25a3d6ffc 100644 --- a/packages/instabug_flutter/lib/instabug_flutter.dart +++ b/packages/instabug_flutter/lib/instabug_flutter.dart @@ -5,7 +5,6 @@ export 'src/models/feature_flag.dart'; export 'src/models/network_data.dart'; export 'src/models/trace.dart'; export 'src/models/w3c_header.dart'; - // Modules export 'src/modules/apm.dart'; export 'src/modules/bug_reporting.dart'; @@ -19,7 +18,11 @@ export 'src/modules/session_replay.dart'; export 'src/modules/surveys.dart'; // Utils export 'src/utils/instabug_navigator_observer.dart'; +export 'src/utils/instabug_widget.dart'; +export 'src/utils/private_views/instabug_private_view.dart'; +export 'src/utils/private_views/instabug_sliver_private_view.dart'; export 'src/utils/screen_loading/instabug_capture_screen_loading.dart'; export 'src/utils/screen_loading/route_matcher.dart'; +export 'src/utils/screen_loading/screenshot_pipeline.dart' show AutoMasking; export 'src/utils/screen_name_masker.dart' show ScreenNameMaskingCallback; export 'src/utils/user_steps/instabug_user_steps.dart'; diff --git a/packages/instabug_flutter/lib/src/modules/instabug.dart b/packages/instabug_flutter/lib/src/modules/instabug.dart index 82d0528f1..ee862826d 100644 --- a/packages/instabug_flutter/lib/src/modules/instabug.dart +++ b/packages/instabug_flutter/lib/src/modules/instabug.dart @@ -11,7 +11,6 @@ import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/material.dart'; - // to maintain supported versions prior to Flutter 3.3 // ignore: unused_import import 'package:flutter/services.dart'; @@ -406,8 +405,9 @@ class Instabug { /// Reports that the screen has been changed (repro steps) /// [screenName] String containing the screen name - static Future reportScreenChange(String screenName) async { - return _host.reportScreenChange(screenName); + static Future reportScreenChange( + Uint8List? image, String screenName,) async { + return _host.reportScreenChange(image, screenName); } /// Changes the font of Instabug's UI. diff --git a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart index d9d6b02db..7f8b93c4e 100644 --- a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart +++ b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter/src/models/instabug_route.dart'; import 'package:instabug_flutter/src/modules/instabug.dart'; +import 'package:instabug_flutter/src/utils/ibg_build_info.dart'; import 'package:instabug_flutter/src/utils/instabug_logger.dart'; import 'package:instabug_flutter/src/utils/repro_steps_constants.dart'; import 'package:instabug_flutter/src/utils/screen_loading/screen_loading_manager.dart'; @@ -23,21 +24,29 @@ class InstabugNavigatorObserver extends NavigatorObserver { name: maskedScreenName, ); - // Starts a the new UI trace which is exclusive to screen loading - ScreenLoadingManager.I.startUiTrace(maskedScreenName, screenName); - // If there is a step that hasn't been pushed yet - if (_steps.isNotEmpty) { - // Report the last step and remove it from the list - Instabug.reportScreenChange(_steps.last.name); - _steps.removeLast(); - } - - // Add the new step to the list - _steps.add(route); - Future.delayed(const Duration(milliseconds: 1000), () { + WidgetsBinding.instance.addPostFrameCallback((_) async { + // Starts a the new UI trace which is exclusive to screen loading + ScreenLoadingManager.I.startUiTrace(maskedScreenName, screenName); + // If there is a step that hasn't been pushed yet + if (_steps.isNotEmpty) { + if (IBGBuildInfo.instance.isIOS) { + await Future.delayed(const Duration(milliseconds: 100)); + } + Instabug.reportScreenChange(null, _steps.last.name); + + // Report the last step and remove it from the list + _steps.removeLast(); + } + + // Add the new step to the list + _steps.add(route); + // If this route is in the array, report it and remove it from the list if (_steps.contains(route)) { - Instabug.reportScreenChange(route.name); + if (IBGBuildInfo.instance.isIOS) { + await Future.delayed(const Duration(milliseconds: 100)); + } + Instabug.reportScreenChange(null, route.name); _steps.remove(route); } }); diff --git a/packages/instabug_flutter/lib/src/utils/instabug_widget.dart b/packages/instabug_flutter/lib/src/utils/instabug_widget.dart new file mode 100644 index 000000000..f63ca8776 --- /dev/null +++ b/packages/instabug_flutter/lib/src/utils/instabug_widget.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/instabug_private_view.api.g.dart'; +import 'package:instabug_flutter/src/utils/private_views/private_views_manager.dart'; +import 'package:meta/meta.dart'; + +@internal +final instabugWidgetKey = GlobalKey(debugLabel: 'instabug_screenshot_widget'); + +class InstabugWidget extends StatefulWidget { + final Widget child; + final bool enablePrivateViews; + final bool enableUserSteps; + final List? automasking; + + const InstabugWidget({ + Key? key, + required this.child, + this.enableUserSteps = true, + this.enablePrivateViews = true, + this.automasking, + }) : super(key: key); + + @override + State createState() => _InstabugWidgetState(); +} + +class _InstabugWidgetState extends State { + @override + void initState() { + if (widget.enablePrivateViews) { + _enableInstabugMaskingPrivateViews(); + } + if (widget.automasking != null) { + PrivateViewsManager.I.addAutoMasking(widget.automasking!); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + final child = widget.enableUserSteps + ? InstabugUserSteps(child: widget.child) + : widget.child; + + if (widget.enablePrivateViews) { + return RepaintBoundary( + key: instabugWidgetKey, + child: child, + ); + } + return child; + } +} + +void _enableInstabugMaskingPrivateViews() { + final api = InstabugPrivateViewHostApi(); + api.init(); + InstabugPrivateViewFlutterApi.setup(PrivateViewsManager.I); +} diff --git a/packages/instabug_flutter/lib/src/utils/private_views/instabug_private_view.dart b/packages/instabug_flutter/lib/src/utils/private_views/instabug_private_view.dart new file mode 100644 index 000000000..997407426 --- /dev/null +++ b/packages/instabug_flutter/lib/src/utils/private_views/instabug_private_view.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; + + +class InstabugPrivateView extends StatelessWidget { + final Widget child; + + const InstabugPrivateView({required this.child, Key? key}):super(key: key); + + @override + Widget build(BuildContext context) { + return child; + } +} diff --git a/packages/instabug_flutter/lib/src/utils/private_views/instabug_sliver_private_view.dart b/packages/instabug_flutter/lib/src/utils/private_views/instabug_sliver_private_view.dart new file mode 100644 index 000000000..1ea626f5a --- /dev/null +++ b/packages/instabug_flutter/lib/src/utils/private_views/instabug_sliver_private_view.dart @@ -0,0 +1,14 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class InstabugSliverPrivateView extends StatelessWidget { + final Widget sliver; + + const InstabugSliverPrivateView({required this.sliver, Key? key}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return sliver; + } +} diff --git a/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart b/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart new file mode 100644 index 000000000..1aba259df --- /dev/null +++ b/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart @@ -0,0 +1,136 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/generated/instabug.api.g.dart'; +import 'package:instabug_flutter/src/generated/instabug_private_view.api.g.dart'; +import 'package:instabug_flutter/src/utils/enum_converter.dart'; +import 'package:instabug_flutter/src/utils/screen_loading/screenshot_pipeline.dart'; + +/// responsible for masking views +/// before they are sent to the native SDKs. +class PrivateViewsManager implements InstabugPrivateViewFlutterApi { + PrivateViewsManager._() { + _viewChecks = List.of([isPrivateWidget]); + } + + static PrivateViewsManager _instance = PrivateViewsManager._(); + + static PrivateViewsManager get instance => _instance; + static final _host = InstabugHostApi(); + + /// Shorthand for [instance] + static PrivateViewsManager get I => instance; + + @visibleForTesting + // ignore: use_setters_to_change_properties + static void setInstance(PrivateViewsManager instance) { + _instance = instance; + } + + static bool isPrivateWidget(Widget widget) { + final isPrivate = (widget.runtimeType == InstabugPrivateView) || + (widget.runtimeType == InstabugSliverPrivateView); + + return isPrivate; + } + + late List _viewChecks; + + void addAutoMasking(List masking) { + _viewChecks= List.of([isPrivateWidget]); + if (masking.contains(AutoMasking.none) == false) { + _viewChecks.addAll(masking.map((e) => e.hides()).toList()); + } + _host.enableAutoMasking(masking.mapToString()); + } + + Rect? getLayoutRectInfoFromRenderObject(RenderObject? renderObject) { + if (renderObject == null) { + return null; + } + + final globalOffset = _getRenderGlobalOffset(renderObject); + + if (renderObject is RenderProxyBox) { + if (renderObject.child == null) { + return null; + } + + return MatrixUtils.transformRect( + renderObject.child!.getTransformTo(renderObject), + Offset.zero & renderObject.child!.size, + ).shift(globalOffset); + } + + return renderObject.paintBounds.shift(globalOffset); + } + + // The is the same implementation used in RenderBox.localToGlobal (a subclass of RenderObject) + Offset _getRenderGlobalOffset(RenderObject renderObject) { + return MatrixUtils.transformPoint( + renderObject.getTransformTo(null), + Offset.zero, + ); + } + + List getRectsOfPrivateViews() { + final context = instabugWidgetKey.currentContext; + if (context == null) return []; + + final rootRenderObject = + context.findRenderObject() as RenderRepaintBoundary?; + if (rootRenderObject is! RenderBox) return []; + + final bounds = Offset.zero & rootRenderObject!.size; + + final rects = []; + + void findPrivateViews(Element element) { + final widget = element.widget; + final isPrivate = _viewChecks.any((e)=>e.call(widget)); + if (isPrivate) { + final renderObject = element.findRenderObject(); + if (renderObject is RenderBox && + renderObject.attached && + element.mounted) { + final isElementInCurrentScreen = isElementInCurrentRoute(element); + final rect = getLayoutRectInfoFromRenderObject(renderObject); + if (rect != null && + rect.overlaps(bounds) && + isElementInCurrentScreen) { + rects.add(rect); + } + } + } else { + element.visitChildElements(findPrivateViews); + } + } + + rects.clear(); + context.visitChildElements(findPrivateViews); + + return rects; + } + + bool isElementInCurrentRoute(Element element) { + final modalRoute = ModalRoute.of(element); + return modalRoute?.isCurrent ?? false; + } + + @override + List getPrivateViews() { + final rects = getRectsOfPrivateViews(); + final result = []; + + for (final rect in rects) { + result.addAll([ + rect.left, + rect.top, + rect.right, + rect.bottom, + ]); + } + + return result; + } +} diff --git a/packages/instabug_flutter/lib/src/utils/screen_loading/screenshot_pipeline.dart b/packages/instabug_flutter/lib/src/utils/screen_loading/screenshot_pipeline.dart new file mode 100644 index 000000000..015951b1f --- /dev/null +++ b/packages/instabug_flutter/lib/src/utils/screen_loading/screenshot_pipeline.dart @@ -0,0 +1,154 @@ +import 'dart:typed_data'; +import 'dart:ui' as ui; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/utils/user_steps/widget_utils.dart'; + +enum AutoMasking { labels, textInputs, media, none } + +extension ValidationMethod on AutoMasking { + bool Function(Widget) hides() { + switch (this) { + case AutoMasking.labels: + return isTextWidget; + case AutoMasking.textInputs: + return isTextInputWidget; + case AutoMasking.media: + return isMedia; + case AutoMasking.none: + return (_) => false; + } + } +} + +class ScreenshotPipeLine { + ScreenshotPipeLine._internal(); + + static final viewChecks = List.of([_isPrivate]); + + static void addAutoMasking(List masking) { + viewChecks.addAll(masking.map((e) => e.hides()).toList()); + } + + static Future getScreenShot() async { + await Future.delayed(const Duration(milliseconds: 300)); + + final context = instabugWidgetKey.currentContext; + + final renderObject = context?.findRenderObject() as RenderRepaintBoundary?; + if (context == null || renderObject == null) { + return null; + } + + final image = renderObject.toImageSync(); + final rects = _getRectsOfPrivateViews(); + // Create a new canvas to draw on + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + + // Draw the original image on the canvas + final imagePaint = Paint(); + + canvas.drawImage(image, Offset.zero, imagePaint); + + // Draw rectangles with black color + final rectPaint = Paint() + ..color = Colors.black + ..style = PaintingStyle.fill + ..strokeWidth = 1; // Adjust stroke width if needed + + for (final rect in rects) { + canvas.drawRect(rect, rectPaint); + } + + // Convert canvas to image + final finalImage = recorder.endRecording().toImageSync( + image.width, + image.height, + ); + + final data = await finalImage.toByteData(format: ui.ImageByteFormat.png); + final imageBytes = data!.buffer.asUint8List(); + return imageBytes; + } + + static List _getRectsOfPrivateViews() { + final context = instabugWidgetKey.currentContext; + if (context == null) return []; + + final rootRenderObject = + context.findRenderObject() as RenderRepaintBoundary?; + if (rootRenderObject is! RenderBox) return []; + + final bounds = Offset.zero & rootRenderObject!.size; + + final rects = []; + + void findPrivateViews(Element element) { + final widget = element.widget; + + final isPrivate = viewChecks.any((e) => e.call(widget)); + // final isText = isTextWidget(widget); + if (isPrivate) { + final renderObject = element.findRenderObject(); + if (renderObject is RenderBox && + renderObject.attached && + element.mounted) { + final isElementInCurrentScreen = _isElementInCurrentRoute(element); + final rect = _getLayoutRectInfoFromRenderObject(renderObject); + if (rect != null && + rect.overlaps(bounds) && + isElementInCurrentScreen) { + rects.add(rect); + } + } + } else { + element.visitChildElements(findPrivateViews); + } + } + + rects.clear(); + context.visitChildElements(findPrivateViews); + + return rects; + } + + static bool _isPrivate(Widget widget) { + return widget.runtimeType.toString() == 'InstabugPrivateView' || + widget.runtimeType.toString() == 'InstabugSliverPrivateView'; + } + + static bool _isElementInCurrentRoute(Element element) { + final modalRoute = ModalRoute.of(element); + return modalRoute?.isCurrent ?? false; + } + + static Rect? _getLayoutRectInfoFromRenderObject(RenderObject? renderObject) { + if (renderObject == null) { + return null; + } + + final globalOffset = _getRenderGlobalOffset(renderObject); + + if (renderObject is RenderProxyBox) { + if (renderObject.child == null) { + return null; + } + + return MatrixUtils.transformRect( + renderObject.child!.getTransformTo(renderObject), + Offset.zero & renderObject.child!.size, + ).shift(globalOffset); + } + + return renderObject.paintBounds.shift(globalOffset); + } + + static Offset _getRenderGlobalOffset(RenderObject renderObject) { + return MatrixUtils.transformPoint( + renderObject.getTransformTo(null), + Offset.zero, + ); + } +} diff --git a/packages/instabug_flutter/lib/src/utils/user_steps/widget_utils.dart b/packages/instabug_flutter/lib/src/utils/user_steps/widget_utils.dart index 3e2cc0cb1..7c4718586 100644 --- a/packages/instabug_flutter/lib/src/utils/user_steps/widget_utils.dart +++ b/packages/instabug_flutter/lib/src/utils/user_steps/widget_utils.dart @@ -87,7 +87,7 @@ bool isImageWidget(Widget? widget) { if (widget == null) { return false; } - return widget is Image || + final isDefaultImage = widget is Image || widget is FadeInImage || widget is NetworkImage || widget is AssetImage || @@ -95,8 +95,35 @@ bool isImageWidget(Widget? widget) { widget is FileImage || widget is MemoryImage || widget is ImageProvider; + + if (isDefaultImage) { + return true; + } + final imageWidgetTypes = { + 'CachedNetworkImage', // From cached_network_image package + 'SvgPicture', // flutter_svg package + 'OctoImage', // octo_image package + }; + + return imageWidgetTypes.contains(widget.runtimeType.toString()); } +bool isVideoPlayerWidget(Widget widget) { + final videoPlayerTypes = { + 'VideoPlayer', // flutter_video_player + 'Chewie', // chewie video player + 'BetterPlayer', // better_player package + 'YoutubePlayer', // youtube_player_flutter + 'VlcPlayer', // flutter_vlc_player + 'FlickVideoPlayer', // flick_video_player + }; + + return videoPlayerTypes.contains(widget.runtimeType.toString()); +} + +bool isMedia(Widget widget){ + return isImageWidget(widget) || isVideoPlayerWidget(widget); +} /// Checks if a widget is toggleable (e.g., switch, checkbox, etc.). bool isToggleableWidget(Widget widget) { return widget is Checkbox || diff --git a/packages/instabug_flutter/pigeons/instabug.api.dart b/packages/instabug_flutter/pigeons/instabug.api.dart index ca1d9eef7..dd6b9f088 100644 --- a/packages/instabug_flutter/pigeons/instabug.api.dart +++ b/packages/instabug_flutter/pigeons/instabug.api.dart @@ -19,6 +19,8 @@ abstract class InstabugHostApi { void init(String token, List invocationEvents, String debugLogsLevel); + void enableAutoMasking(List autoMasking); + void show(); void showWelcomeMessageWithMode(String mode); @@ -85,8 +87,7 @@ abstract class InstabugHostApi { String? crashMode, String? sessionReplayMode, ); - - void reportScreenChange(String screenName); + void reportScreenChange(Uint8List? image,String screenName); void setCustomBrandingImage(String light, String dark); diff --git a/packages/instabug_private_views/pigeons/instabug_private_view.api.dart b/packages/instabug_flutter/pigeons/instabug_private_view.api.dart similarity index 99% rename from packages/instabug_private_views/pigeons/instabug_private_view.api.dart rename to packages/instabug_flutter/pigeons/instabug_private_view.api.dart index 9a84a63f3..76a84b101 100644 --- a/packages/instabug_private_views/pigeons/instabug_private_view.api.dart +++ b/packages/instabug_flutter/pigeons/instabug_private_view.api.dart @@ -3,6 +3,7 @@ import 'package:pigeon/pigeon.dart'; @FlutterApi() abstract class InstabugPrivateViewFlutterApi { List getPrivateViews(); + } @HostApi() diff --git a/packages/instabug_flutter/pubspec.lock b/packages/instabug_flutter/pubspec.lock index 850b79e0f..346b5865d 100644 --- a/packages/instabug_flutter/pubspec.lock +++ b/packages/instabug_flutter/pubspec.lock @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" convert: dependency: transitive description: @@ -311,18 +311,18 @@ packages: 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: @@ -519,7 +519,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_gen: dependency: transitive description: @@ -556,10 +556,10 @@ packages: dependency: "direct main" description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" stream_channel: dependency: transitive description: @@ -580,10 +580,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" tar: dependency: transitive description: @@ -604,26 +604,26 @@ packages: dependency: transitive 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" timing: dependency: transitive description: @@ -652,10 +652,10 @@ 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" watcher: dependency: transitive description: diff --git a/packages/instabug_flutter/test/instabug_test.dart b/packages/instabug_flutter/test/instabug_test.dart index 1ee67a9d3..e1b0de4a0 100644 --- a/packages/instabug_flutter/test/instabug_test.dart +++ b/packages/instabug_flutter/test/instabug_test.dart @@ -419,10 +419,10 @@ void main() { test('[reportScreenChange] should call host method', () async { const screen = "home"; - await Instabug.reportScreenChange(screen); + await Instabug.reportScreenChange(null,screen); verify( - mHost.reportScreenChange(screen), + mHost.reportScreenChange(null,screen), ).called(1); }); diff --git a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart index ebf541137..6ab79a950 100644 --- a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart +++ b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart @@ -51,7 +51,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(screen), + mHost.reportScreenChange(null,screen), ).called(1); }); }); @@ -69,7 +69,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(previousScreen), + mHost.reportScreenChange(null,previousScreen), ).called(1); }); }); @@ -87,7 +87,7 @@ void main() { ); verifyNever( - mHost.reportScreenChange(any), + mHost.reportScreenChange(null,any), ); }); }); @@ -106,7 +106,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(fallback), + mHost.reportScreenChange(null,fallback), ).called(1); }); }); @@ -126,7 +126,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(maskedScreen), + mHost.reportScreenChange(null,maskedScreen), ).called(1); }); }); diff --git a/packages/instabug_flutter_modular/example/pubspec.lock b/packages/instabug_flutter_modular/example/pubspec.lock index aee784432..3f5e6fbd0 100644 --- a/packages/instabug_flutter_modular/example/pubspec.lock +++ b/packages/instabug_flutter_modular/example/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" cupertino_icons: dependency: "direct main" description: @@ -109,18 +109,18 @@ packages: 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: @@ -189,7 +189,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -202,10 +202,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" stream_channel: dependency: transitive description: @@ -218,10 +218,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" term_glyph: dependency: transitive description: @@ -234,10 +234,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" vector_math: dependency: transitive description: @@ -250,10 +250,10 @@ 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" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.4.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/instabug_flutter_modular/pubspec.lock b/packages/instabug_flutter_modular/pubspec.lock index 92e83db90..5a8fb0853 100644 --- a/packages/instabug_flutter_modular/pubspec.lock +++ b/packages/instabug_flutter_modular/pubspec.lock @@ -5,23 +5,23 @@ 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" _macros: dependency: transitive description: dart source: sdk - version: "0.3.2" + version: "0.3.3" analyzer: dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "6.11.0" args: dependency: transitive description: @@ -154,10 +154,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" convert: dependency: transitive description: @@ -347,18 +347,18 @@ packages: 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: @@ -387,10 +387,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: @@ -563,7 +563,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_gen: dependency: transitive description: @@ -600,10 +600,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" stream_channel: dependency: transitive description: @@ -624,10 +624,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" tar: dependency: transitive description: @@ -648,26 +648,26 @@ packages: dependency: transitive 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" timing: dependency: transitive description: @@ -696,10 +696,10 @@ 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" watcher: dependency: transitive description: diff --git a/packages/instabug_http_client/example/pubspec.lock b/packages/instabug_http_client/example/pubspec.lock index 78cb15f97..c0867996d 100644 --- a/packages/instabug_http_client/example/pubspec.lock +++ b/packages/instabug_http_client/example/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" cupertino_icons: dependency: "direct main" description: @@ -109,18 +109,18 @@ packages: 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: @@ -173,7 +173,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -186,10 +186,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" stream_channel: dependency: transitive description: @@ -202,10 +202,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" term_glyph: dependency: transitive description: @@ -218,10 +218,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" typed_data: dependency: transitive description: @@ -242,10 +242,10 @@ 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" sdks: dart: ">=3.5.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/instabug_http_client/lib/instabug_http_client.dart b/packages/instabug_http_client/lib/instabug_http_client.dart index 624d72cc1..3acb08fd9 100644 --- a/packages/instabug_http_client/lib/instabug_http_client.dart +++ b/packages/instabug_http_client/lib/instabug_http_client.dart @@ -47,7 +47,7 @@ class InstabugHttpClient extends InstabugHttpLogger implements http.Client { } Future getW3cHeader( - Map requestHeader, DateTime startTime) async { + Map requestHeader, DateTime startTime,) async { final w3cHeader = await _networklogger.getW3CHeader( requestHeader, startTime.millisecondsSinceEpoch, @@ -157,7 +157,7 @@ class InstabugHttpClient extends InstabugHttpLogger implements http.Client { http.Response.fromStream(streamedResponse) .then((http.Response response) { logger.onLogger(response, - startTime: startTime, w3CHeader: w3cHeader); + startTime: startTime, w3CHeader: w3cHeader,); // Need to return new StreamedResponse, as body only can be listened once return http.StreamedResponse( Stream>.value(response.bodyBytes), diff --git a/packages/instabug_http_client/lib/instabug_http_logger.dart b/packages/instabug_http_client/lib/instabug_http_logger.dart index a0b9fa6e7..4da358730 100644 --- a/packages/instabug_http_client/lib/instabug_http_logger.dart +++ b/packages/instabug_http_client/lib/instabug_http_logger.dart @@ -5,7 +5,7 @@ import 'package:instabug_flutter/instabug_flutter.dart'; class InstabugHttpLogger { void onLogger(http.Response response, - {DateTime? startTime, W3CHeader? w3CHeader}) { + {DateTime? startTime, W3CHeader? w3CHeader,}) { final networkLogger = NetworkLogger(); final requestHeaders = {}; diff --git a/packages/instabug_http_client/pubspec.lock b/packages/instabug_http_client/pubspec.lock index 576d3ee35..15fac02e7 100644 --- a/packages/instabug_http_client/pubspec.lock +++ b/packages/instabug_http_client/pubspec.lock @@ -5,23 +5,23 @@ 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" _macros: dependency: transitive description: dart source: sdk - version: "0.3.2" + version: "0.3.3" analyzer: dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "6.11.0" args: dependency: transitive description: @@ -154,10 +154,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" convert: dependency: transitive description: @@ -323,18 +323,18 @@ packages: 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: @@ -363,10 +363,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: @@ -523,7 +523,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_gen: dependency: transitive description: @@ -560,10 +560,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" stream_channel: dependency: transitive description: @@ -584,10 +584,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" tar: dependency: transitive description: @@ -608,26 +608,26 @@ packages: dependency: transitive 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" timing: dependency: transitive description: @@ -656,10 +656,10 @@ 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" watcher: dependency: transitive description: diff --git a/packages/instabug_http_client/test/instabug_http_client_test.dart b/packages/instabug_http_client/test/instabug_http_client_test.dart index abcd12b25..3467d443c 100644 --- a/packages/instabug_http_client/test/instabug_http_client_test.dart +++ b/packages/instabug_http_client/test/instabug_http_client_test.dart @@ -55,7 +55,7 @@ Future main() async { test('expect instabug http client GET to return response', () async { when( - instabugHttpClient.client.get(url, headers: anyNamed('headers'))) + instabugHttpClient.client.get(url, headers: anyNamed('headers')),) .thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.get(url); expect(result, isInstanceOf()); @@ -68,7 +68,7 @@ Future main() async { test('expect instabug http client HEAD to return response', () async { when( - instabugHttpClient.client.head(url, headers: anyNamed('headers'))) + instabugHttpClient.client.head(url, headers: anyNamed('headers')),) .thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.head(url); expect(result, isInstanceOf()); @@ -81,7 +81,7 @@ Future main() async { test('expect instabug http client DELETE to return response', () async { when( - instabugHttpClient.client.delete(url, headers: anyNamed('headers'))) + instabugHttpClient.client.delete(url, headers: anyNamed('headers')),) .thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.delete(url); expect(result, isInstanceOf()); @@ -94,7 +94,7 @@ Future main() async { test('expect instabug http client PATCH to return response', () async { when( - instabugHttpClient.client.patch(url, headers: anyNamed('headers'))) + instabugHttpClient.client.patch(url, headers: anyNamed('headers')),) .thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.patch(url); expect(result, isInstanceOf()); @@ -107,7 +107,7 @@ Future main() async { test('expect instabug http client POST to return response', () async { when( - instabugHttpClient.client.post(url, headers: anyNamed('headers'))) + instabugHttpClient.client.post(url, headers: anyNamed('headers')),) .thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.post(url); expect(result, isInstanceOf()); @@ -120,7 +120,7 @@ Future main() async { test('expect instabug http client PUT to return response', () async { when( - instabugHttpClient.client.put(url, headers: anyNamed('headers'))) + instabugHttpClient.client.put(url, headers: anyNamed('headers')),) .thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.put(url); expect(result, isInstanceOf()); @@ -134,7 +134,7 @@ Future main() async { test('expect instabug http client READ to return response', () async { const response = 'Some response string'; when( - instabugHttpClient.client.read(url, headers: anyNamed('headers'))) + instabugHttpClient.client.read(url, headers: anyNamed('headers')),) .thenAnswer((_) async => response); final result = await instabugHttpClient.read(url); @@ -194,7 +194,7 @@ Future main() async { test('stress test for GET method', () async { when( - instabugHttpClient.client.get(url, headers: anyNamed('headers'))) + instabugHttpClient.client.get(url, headers: anyNamed('headers')),) .thenAnswer((_) async => mockedResponse); for (var i = 0; i < 10000; i++) { await instabugHttpClient.get(url); diff --git a/packages/instabug_private_views/.metadata b/packages/instabug_private_views/.metadata deleted file mode 100644 index 97e8389f1..000000000 --- a/packages/instabug_private_views/.metadata +++ /dev/null @@ -1,33 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "603104015dd692ea3403755b55d07813d5cf8965" - channel: "stable" - -project_type: plugin - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - platform: android - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - platform: ios - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/instabug_private_views/CHANGELOG.md b/packages/instabug_private_views/CHANGELOG.md deleted file mode 100644 index 26deb9dda..000000000 --- a/packages/instabug_private_views/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -# Changelog - -## [UnReleased](https://github.com/Instabug/) - -### Added - -- Add support for masking private views during screen capturing ([#527](https://github.com/Instabug/Instabug-Flutter/pull/527)). diff --git a/packages/instabug_private_views/LICENSE b/packages/instabug_private_views/LICENSE deleted file mode 100644 index 80d729766..000000000 --- a/packages/instabug_private_views/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) Instabug - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/packages/instabug_private_views/README.md b/packages/instabug_private_views/README.md deleted file mode 100644 index 0c7f936a8..000000000 --- a/packages/instabug_private_views/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# instabug_private_views - -An add-on for the Instabug Flutter SDK that provides private views support in screen. - -[![Twitter](https://img.shields.io/badge/twitter-@Instabug-blue.svg)](https://twitter.com/Instabug) - -An add-on for the [Instabug Flutter SDK](https://github.com/Instabug/Instabug-Flutter) hat provides private views support in screenshot capturing [Flutter Private views](https://pub.dev/packages/). - -## Installation - -1. Add `instabug_private_views` to your `pubspec.yaml` file. - -```yaml -dependencies: - instabug_private_views: -``` - -2. Install the package by running the following command. - -```sh -flutter pub get -``` - -## Usage - -1. enable `PrivateViews` after `init` the SDK: - - -```dart - -void main() { - - Instabug.init( - token: 'App token', - invocationEvents: [InvocationEvent.floatingButton], - ); - - ReproSteps.enableMaskingPrivateViews(); - - runApp(MyApp()); - -} -``` - -2. Wrap the view you want to mask with `InstabugPrivateView`: - -```dart - InstabugPrivateView( -child: const Text( -'Private TextView', -style: TextStyle(fontSize: 18), -textAlign: TextAlign.center, -), -), -``` - -you can use `InstabugSliverPrivateView` if you want to wrap Sliver widget -```dart - InstabugSliverPrivateView( -sliver: SliverToBoxAdapter( -child: /// child -)), -``` \ No newline at end of file diff --git a/packages/instabug_private_views/android/build.gradle b/packages/instabug_private_views/android/build.gradle deleted file mode 100644 index 50025559f..000000000 --- a/packages/instabug_private_views/android/build.gradle +++ /dev/null @@ -1,56 +0,0 @@ -group = "com.instabug.instabug_private_views" -version = "1.0" - -buildscript { - repositories { - google() - mavenCentral() - } - - dependencies { - classpath("com.android.tools.build:gradle:8.1.0") - } -} - -rootProject.allprojects { - repositories { - google() - mavenCentral() - } -} - -apply plugin: "com.android.library" - -android { - if (project.android.hasProperty("namespace")) { - namespace = "com.instabug.instabug_private_views" - } - - compileSdk = 34 - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - - defaultConfig { - minSdk = 21 - } - - dependencies { - testImplementation("junit:junit:4.13.2") - testImplementation("org.mockito:mockito-core:5.0.0") - testImplementation ('org.robolectric:robolectric:4.12.2') - - } - - testOptions { - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen {false} - showStandardStreams = true - } - } - } -} diff --git a/packages/instabug_private_views/android/settings.gradle b/packages/instabug_private_views/android/settings.gradle deleted file mode 100644 index 64f5453f5..000000000 --- a/packages/instabug_private_views/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'instabug_private_views' diff --git a/packages/instabug_private_views/android/src/main/AndroidManifest.xml b/packages/instabug_private_views/android/src/main/AndroidManifest.xml deleted file mode 100644 index 23fe3b997..000000000 --- a/packages/instabug_private_views/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/InstabugPrivateViewsPlugin.java b/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/InstabugPrivateViewsPlugin.java deleted file mode 100644 index 2065b60c1..000000000 --- a/packages/instabug_private_views/android/src/main/java/com/instabug/instabug_private_views/InstabugPrivateViewsPlugin.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.instabug.instabug_private_views; - -import android.annotation.SuppressLint; -import android.app.Activity; - -import androidx.annotation.NonNull; - -import com.instabug.instabug_private_views.generated.InstabugPrivateViewPigeon; -import com.instabug.instabug_private_views.modules.capturing.BoundryCaptureManager; -import com.instabug.instabug_private_views.modules.InstabugPrivateView; -import com.instabug.instabug_private_views.modules.capturing.PixelCopyCaptureManager; -import com.instabug.instabug_private_views.modules.PrivateViewManager; -import com.instabug.library.internal.crossplatform.InternalCore; - -import io.flutter.embedding.engine.plugins.FlutterPlugin; -import io.flutter.embedding.engine.plugins.activity.ActivityAware; -import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; -import io.flutter.embedding.engine.renderer.FlutterRenderer; -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.PluginRegistry; - -/** - * InstabugPrivateViewsPlugin - */ -public class InstabugPrivateViewsPlugin implements FlutterPlugin, ActivityAware { - private static final String TAG = InstabugPrivateViewsPlugin.class.getName(); - - @SuppressLint("StaticFieldLeak") - private static Activity activity; - - PrivateViewManager privateViewManager; - - /** - * Embedding v1 - */ - @SuppressWarnings("deprecation") - public void registerWith(PluginRegistry.Registrar registrar) { - activity = registrar.activity(); - register( registrar.messenger(), (FlutterRenderer) registrar.textures()); - } - - - @Override - public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { - register(binding.getBinaryMessenger(), (FlutterRenderer) binding.getTextureRegistry()); - } - - @Override - public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { - activity = null; - } - - @Override - public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { - activity = binding.getActivity(); - if (privateViewManager != null) { - privateViewManager.setActivity(activity); - } - - } - - @Override - public void onDetachedFromActivityForConfigChanges() { - activity = null; - privateViewManager.setActivity(null); - - } - - @Override - public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { - activity = binding.getActivity(); - privateViewManager.setActivity(activity); - - } - - @Override - public void onDetachedFromActivity() { - activity = null; - privateViewManager.setActivity(null); - - } - - private void register(BinaryMessenger messenger, FlutterRenderer renderer) { - privateViewManager = new PrivateViewManager(new InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi(messenger), new PixelCopyCaptureManager(), new BoundryCaptureManager(renderer)); - InstabugPrivateView.init(messenger,privateViewManager); - - } -} diff --git a/packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/BoundryScreenshotCaptorTest.java b/packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/BoundryScreenshotCaptorTest.java deleted file mode 100644 index 979f6c6c5..000000000 --- a/packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/BoundryScreenshotCaptorTest.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.instabug.instabug_private_views; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.robolectric.Shadows.shadowOf; - -import android.app.Activity; -import android.graphics.Bitmap; -import android.os.Looper; - -import com.instabug.instabug_private_views.modules.capturing.BoundryCaptureManager; -import com.instabug.instabug_private_views.modules.capturing.CaptureManager; -import com.instabug.instabug_private_views.model.ScreenshotResult; -import com.instabug.instabug_private_views.modules.capturing.ScreenshotResultCallback; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import io.flutter.embedding.engine.renderer.FlutterRenderer; - -@RunWith(RobolectricTestRunner.class) -@Config(sdk = {28}, manifest = Config.NONE) -public class BoundryScreenshotCaptorTest { - private Activity activityMock; - private Bitmap bitmap; - private CaptureManager captureManager; - - @Before - public void setUp() { - FlutterRenderer rendererMock = mock(FlutterRenderer.class); - activityMock = spy(Robolectric.buildActivity(Activity.class).setup().create().start().resume().get()); - bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); - when(rendererMock.getBitmap()).thenReturn(bitmap); - captureManager = new BoundryCaptureManager(rendererMock); - } - - @Test - public void testCaptureGivenEmptyActivity() { - ScreenshotResultCallback mockCallback = mock(ScreenshotResultCallback.class); - - captureManager.capture(null, mockCallback); - shadowOf(Looper.getMainLooper()).idle(); - - verify(mockCallback).onError(); - verify(mockCallback, never()).onScreenshotResult(any(ScreenshotResult.class)); - - } - - @Test - public void testCapture() { - ScreenshotResultCallback mockCallback = mock(ScreenshotResultCallback.class); - captureManager.capture(activityMock, mockCallback); - shadowOf(Looper.getMainLooper()).idle(); - - verify(mockCallback, never()).onError(); - verify(mockCallback).onScreenshotResult(argThat(new ArgumentMatcher() { - @Override - public boolean matches(ScreenshotResult argument) { - return (Math.abs(activityMock.getResources().getDisplayMetrics().density - argument.getPixelRatio()) < 0.01)&& - bitmap == argument.getScreenshot(); - - } - })); - } - - -} diff --git a/packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/PixelCopyScreenshotCaptorTest.java b/packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/PixelCopyScreenshotCaptorTest.java deleted file mode 100644 index 4841e8506..000000000 --- a/packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/PixelCopyScreenshotCaptorTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.instabug.instabug_private_views; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.robolectric.Shadows.shadowOf; - -import android.app.Activity; -import android.graphics.Bitmap; -import android.os.Looper; -import android.view.SurfaceView; - -import com.instabug.instabug_private_views.modules.capturing.CaptureManager; -import com.instabug.instabug_private_views.modules.capturing.PixelCopyCaptureManager; -import com.instabug.instabug_private_views.model.ScreenshotResult; -import com.instabug.instabug_private_views.modules.capturing.ScreenshotResultCallback; -import com.instabug.library.util.memory.MemoryUtils; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockedStatic; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import io.flutter.embedding.android.FlutterActivity; -import io.flutter.embedding.android.FlutterView; -import io.flutter.embedding.engine.renderer.FlutterRenderer; - -@RunWith(RobolectricTestRunner.class) -@Config(sdk = {28}, manifest = Config.NONE) -public class PixelCopyScreenshotCaptorTest { - private Activity activityMock; - private Bitmap bitmap; - private CaptureManager captureManager; - - @Before - public void setUp() { - FlutterRenderer rendererMock = mock(FlutterRenderer.class); - activityMock = spy(Robolectric.buildActivity(Activity.class).setup().create().start().resume().get()); - bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); - when(rendererMock.getBitmap()).thenReturn(bitmap); - captureManager = new PixelCopyCaptureManager(); - } - - @Test - public void testCaptureWithPixelCopyGivenEmptyView() { - - ScreenshotResultCallback mockScreenshotResultCallback = mock(ScreenshotResultCallback.class); - when(activityMock.findViewById(FlutterActivity.FLUTTER_VIEW_ID)).thenReturn(null); - captureManager.capture(activityMock,mockScreenshotResultCallback); - - verify(mockScreenshotResultCallback).onError(); - } - - @Test - public void testCaptureWithPixelCopy() { - try (MockedStatic mockedStatic = mockStatic(MemoryUtils.class)) { - mockedStatic.when(() -> MemoryUtils.getFreeMemory(any())).thenReturn(Long.MAX_VALUE); - - mockFlutterViewInPixelCopy(); - - ScreenshotResultCallback mockScreenshotResultCallback = mock(ScreenshotResultCallback.class); - - - captureManager.capture(activityMock, mockScreenshotResultCallback); - shadowOf(Looper.getMainLooper()).idle(); - - verify(mockScreenshotResultCallback, timeout(1000)).onScreenshotResult(any(ScreenshotResult.class)); // PixelCopy success - - } - } - - - private void mockFlutterViewInPixelCopy() { - - SurfaceView mockSurfaceView = mock(SurfaceView.class); - FlutterView flutterView = mock(FlutterView.class); - when(flutterView.getChildAt(0)).thenReturn(mockSurfaceView); - when(flutterView.getChildCount()).thenReturn(1); - - when(activityMock.findViewById(FlutterActivity.FLUTTER_VIEW_ID)).thenReturn(flutterView); - when(mockSurfaceView.getWidth()).thenReturn(100); - when(mockSurfaceView.getHeight()).thenReturn(100); - } -} diff --git a/packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/PrivateViewManagerTest.java b/packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/PrivateViewManagerTest.java deleted file mode 100644 index e08b3c50d..000000000 --- a/packages/instabug_private_views/android/src/test/java/com/instabug/instabug_private_views/PrivateViewManagerTest.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.instabug.instabug_private_views; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.robolectric.Shadows.shadowOf; - -import android.app.Activity; -import android.graphics.Bitmap; -import android.os.Build; -import android.os.Looper; -import android.view.SurfaceView; -import com.instabug.instabug_private_views.generated.InstabugPrivateViewPigeon; -import com.instabug.instabug_private_views.modules.capturing.BoundryCaptureManager; -import com.instabug.instabug_private_views.modules.capturing.CaptureManager; -import com.instabug.instabug_private_views.modules.capturing.PixelCopyCaptureManager; -import com.instabug.instabug_private_views.modules.PrivateViewManager; -import com.instabug.instabug_private_views.model.ScreenshotResult; -import com.instabug.library.screenshot.ScreenshotCaptor; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.Arrays; -import java.util.List; - -import io.flutter.embedding.android.FlutterActivity; -import io.flutter.embedding.android.FlutterView; -import io.flutter.embedding.engine.renderer.FlutterRenderer; - -@RunWith(RobolectricTestRunner.class) -@Config(sdk = {28}, manifest = Config.NONE) -public class PrivateViewManagerTest { - - private PrivateViewManager privateViewManager; - private InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi InstabugPrivateViewFlutterApiMock; - private Activity activityMock; - private Bitmap bitmap; - private CaptureManager pixelCopyScreenCaptor, boundryScreenCaptor; - - @Before - public void setUp() { - InstabugPrivateViewFlutterApiMock = mock(InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi.class); - FlutterRenderer rendererMock = mock(FlutterRenderer.class); - activityMock = spy(Robolectric.buildActivity(Activity.class).setup().create().start().resume().get()); - bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); - when(rendererMock.getBitmap()).thenReturn(bitmap); - pixelCopyScreenCaptor = spy(new PixelCopyCaptureManager()); - boundryScreenCaptor = spy(new BoundryCaptureManager(rendererMock)); - privateViewManager = spy(new PrivateViewManager(InstabugPrivateViewFlutterApiMock, pixelCopyScreenCaptor, boundryScreenCaptor)); - privateViewManager.setActivity(activityMock); - - } - - - @Test - public void testMaskGivenEmptyActivity() { - ScreenshotCaptor.CapturingCallback capturingCallbackMock = mock(ScreenshotCaptor.CapturingCallback.class); - privateViewManager.setActivity(null); - privateViewManager.mask(capturingCallbackMock); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Throwable.class); - verify(capturingCallbackMock).onCapturingFailure(argumentCaptor.capture()); - assertEquals( PrivateViewManager.EXCEPTION_MESSAGE, argumentCaptor.getValue().getMessage()); - } - - @Test - public void testMask() throws InterruptedException { - ScreenshotCaptor.CapturingCallback capturingCallbackMock = mock(ScreenshotCaptor.CapturingCallback.class); - doAnswer(invocation -> { - InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi.Reply> callback = invocation.getArgument(0); // Get the callback - callback.reply(Arrays.asList(10.0, 20.0, 100.0, 200.0)); // Trigger the success callback - return null; - }).when(InstabugPrivateViewFlutterApiMock).getPrivateViews(any(InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi.Reply.class)); // Mock the method call - - - // Trigger the mask operation - privateViewManager.mask(capturingCallbackMock); - // Mock that latch.await() has been called - shadowOf(Looper.getMainLooper()).idle(); - - // Simulate a successful bitmap capture - verify(capturingCallbackMock, timeout(1000)).onCapturingSuccess(bitmap); - } - - - private void mockFlutterViewInPixelCopy() { - SurfaceView mockSurfaceView = mock(SurfaceView.class); - FlutterView flutterView = mock(FlutterView.class); - when(flutterView.getChildAt(0)).thenReturn(mockSurfaceView); - when(flutterView.getChildCount()).thenReturn(1); - - when(activityMock.findViewById(FlutterActivity.FLUTTER_VIEW_ID)).thenReturn(flutterView); - when(mockSurfaceView.getWidth()).thenReturn(100); - when(mockSurfaceView.getHeight()).thenReturn(100); - } - - - @Test - public void testMaskPrivateViews() { - ScreenshotResult mockResult = mock(ScreenshotResult.class); - when(mockResult.getScreenshot()).thenReturn(Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888)); - when(mockResult.getPixelRatio()).thenReturn(2.0f); - - List privateViews = Arrays.asList(10.0, 20.0, 100.0, 200.0); - - privateViewManager.maskPrivateViews(mockResult, privateViews); - - assertNotNull(mockResult.getScreenshot()); - } - - @Test - @Config(sdk = {Build.VERSION_CODES.M}) - public void testMaskShouldGetScreenshotWhenAPIVersionLessThan28() { - ScreenshotCaptor.CapturingCallback capturingCallbackMock = mock(ScreenshotCaptor.CapturingCallback.class); - privateViewManager.mask(capturingCallbackMock); - shadowOf(Looper.getMainLooper()).idle(); - - verify(boundryScreenCaptor).capture(any(), any()); - - } - - @Test - public void testMaskShouldCallPixelCopyWhenAPIVersionMoreThan28() { - ScreenshotCaptor.CapturingCallback capturingCallbackMock = mock(ScreenshotCaptor.CapturingCallback.class); - mockFlutterViewInPixelCopy(); - privateViewManager.mask(capturingCallbackMock); - shadowOf(Looper.getMainLooper()).idle(); - verify(boundryScreenCaptor, never()).capture(any(), any()); - verify(pixelCopyScreenCaptor).capture(any(), any()); - - - } -} \ No newline at end of file diff --git a/packages/instabug_private_views/example-hybrid-ios-app/.gitignore b/packages/instabug_private_views/example-hybrid-ios-app/.gitignore deleted file mode 100644 index 2624e2177..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# Xcode -DerivedData/ -build/ -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 -*.xcworkspace -!default.xcworkspace -xcuserdata/ -*.moved-aside -*.xcuserstate -*.xcscmblueprint - -# iOS Specific -*.hmap -*.ipa -*.dSYM.zip -*.dSYM - -# Swift Package Manager -.build/ -.swiftpm/xcode/package.xcworkspace/ -.swiftpm/ - -# CocoaPods (if used) -Pods/ -Podfile.lock - -# Carthage (if used) -Carthage/Build/ - -# Fastlane (if used) -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots -fastlane/test_output - -# Bundle artifact -*.xcarchive - -# Temporary files -*.tmp -*.swp -*.swm diff --git a/packages/instabug_private_views/example-hybrid-ios-app/Podfile b/packages/instabug_private_views/example-hybrid-ios-app/Podfile deleted file mode 100644 index 775126029..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/Podfile +++ /dev/null @@ -1,21 +0,0 @@ -# Uncomment the next line to define a global platform for your project -# platform :ios, '9.0' - -flutter_application_path = 'my_flutter' -load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') - -target 'hybrid-flutter-app' do - # Comment the next line if you don't want to use dynamic frameworks - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/feature-flutter-private-views-base/13.4.2/Instabug.podspec' - - use_frameworks! - - install_all_flutter_pods(flutter_application_path) - - # Pods for hybrid-flutter-app - -end - -post_install do |installer| - flutter_post_install(installer) if defined?(flutter_post_install) -end diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app.xcodeproj/project.pbxproj b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app.xcodeproj/project.pbxproj deleted file mode 100644 index 5e6fb0c4d..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app.xcodeproj/project.pbxproj +++ /dev/null @@ -1,435 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - CC1152E765F8580640185243 /* Pods_hybrid_flutter_app.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 74A87659FEAAB6DF26380477 /* Pods_hybrid_flutter_app.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 6A35F6E0DFACBBAB47D661EA /* Pods-hybrid-flutter-app.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-hybrid-flutter-app.debug.xcconfig"; path = "Target Support Files/Pods-hybrid-flutter-app/Pods-hybrid-flutter-app.debug.xcconfig"; sourceTree = ""; }; - 74A87659FEAAB6DF26380477 /* Pods_hybrid_flutter_app.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_hybrid_flutter_app.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9F7459A16324C6347AA6DAFB /* Pods-hybrid-flutter-app.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-hybrid-flutter-app.release.xcconfig"; path = "Target Support Files/Pods-hybrid-flutter-app/Pods-hybrid-flutter-app.release.xcconfig"; sourceTree = ""; }; - BE9EC8252CD1812F0026F537 /* hybrid-flutter-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "hybrid-flutter-app.app"; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - BE9EC8372CD181310026F537 /* Exceptions for "hybrid-flutter-app" folder in "hybrid-flutter-app" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, - ); - target = BE9EC8242CD1812F0026F537 /* hybrid-flutter-app */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - BE9EC8272CD1812F0026F537 /* hybrid-flutter-app */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - BE9EC8372CD181310026F537 /* Exceptions for "hybrid-flutter-app" folder in "hybrid-flutter-app" target */, - ); - path = "hybrid-flutter-app"; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - BE9EC8222CD1812F0026F537 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - CC1152E765F8580640185243 /* Pods_hybrid_flutter_app.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 324CF1E79ACC6661E48AC83B /* Pods */ = { - isa = PBXGroup; - children = ( - 6A35F6E0DFACBBAB47D661EA /* Pods-hybrid-flutter-app.debug.xcconfig */, - 9F7459A16324C6347AA6DAFB /* Pods-hybrid-flutter-app.release.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 60FD6C74BF2A20B8B71EECA2 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 74A87659FEAAB6DF26380477 /* Pods_hybrid_flutter_app.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - BE9EC81C2CD1812F0026F537 = { - isa = PBXGroup; - children = ( - BE9EC8272CD1812F0026F537 /* hybrid-flutter-app */, - BE9EC8262CD1812F0026F537 /* Products */, - 324CF1E79ACC6661E48AC83B /* Pods */, - 60FD6C74BF2A20B8B71EECA2 /* Frameworks */, - ); - sourceTree = ""; - }; - BE9EC8262CD1812F0026F537 /* Products */ = { - isa = PBXGroup; - children = ( - BE9EC8252CD1812F0026F537 /* hybrid-flutter-app.app */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - BE9EC8242CD1812F0026F537 /* hybrid-flutter-app */ = { - isa = PBXNativeTarget; - buildConfigurationList = BE9EC8382CD181310026F537 /* Build configuration list for PBXNativeTarget "hybrid-flutter-app" */; - buildPhases = ( - 12C1309DE0C239420C1F847F /* [CP] Check Pods Manifest.lock */, - 742AC800B4072D761DDE7C14 /* [CP-User] Run Flutter Build my_flutter Script */, - BE9EC8212CD1812F0026F537 /* Sources */, - BE9EC8222CD1812F0026F537 /* Frameworks */, - BE9EC8232CD1812F0026F537 /* Resources */, - 56BEAC412A6C93A663ED05C8 /* [CP-User] Embed Flutter Build my_flutter Script */, - A3E7F43B3A5E735EC880C3EF /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - BE9EC8272CD1812F0026F537 /* hybrid-flutter-app */, - ); - name = "hybrid-flutter-app"; - productName = "hybrid-flutter-app"; - productReference = BE9EC8252CD1812F0026F537 /* hybrid-flutter-app.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - BE9EC81D2CD1812F0026F537 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1600; - LastUpgradeCheck = 1600; - TargetAttributes = { - BE9EC8242CD1812F0026F537 = { - CreatedOnToolsVersion = 16.0; - }; - }; - }; - buildConfigurationList = BE9EC8202CD1812F0026F537 /* Build configuration list for PBXProject "hybrid-flutter-app" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = BE9EC81C2CD1812F0026F537; - minimizedProjectReferenceProxies = 1; - preferredProjectObjectVersion = 77; - productRefGroup = BE9EC8262CD1812F0026F537 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - BE9EC8242CD1812F0026F537 /* hybrid-flutter-app */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - BE9EC8232CD1812F0026F537 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 12C1309DE0C239420C1F847F /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-hybrid-flutter-app-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 56BEAC412A6C93A663ED05C8 /* [CP-User] Embed Flutter Build my_flutter Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - name = "[CP-User] Embed Flutter Build my_flutter Script"; - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "set -e\nset -u\nsource \"${SRCROOT}/my_flutter/.ios/Flutter/flutter_export_environment.sh\"\nexport VERBOSE_SCRIPT_LOGGING=1 && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh embed_and_thin"; - }; - 742AC800B4072D761DDE7C14 /* [CP-User] Run Flutter Build my_flutter Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - name = "[CP-User] Run Flutter Build my_flutter Script"; - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "set -e\nset -u\nsource \"${SRCROOT}/my_flutter/.ios/Flutter/flutter_export_environment.sh\"\nexport VERBOSE_SCRIPT_LOGGING=1 && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh build"; - }; - A3E7F43B3A5E735EC880C3EF /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-hybrid-flutter-app/Pods-hybrid-flutter-app-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-hybrid-flutter-app/Pods-hybrid-flutter-app-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-hybrid-flutter-app/Pods-hybrid-flutter-app-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - BE9EC8212CD1812F0026F537 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - BE9EC8392CD181310026F537 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 6A35F6E0DFACBBAB47D661EA /* Pods-hybrid-flutter-app.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = VF78H8LBT4; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "hybrid-flutter-app/Info.plist"; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "com.ahmedalaa.hybrid-flutter-app"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - BE9EC83A2CD181310026F537 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9F7459A16324C6347AA6DAFB /* Pods-hybrid-flutter-app.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = VF78H8LBT4; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "hybrid-flutter-app/Info.plist"; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "com.ahmedalaa.hybrid-flutter-app"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - BE9EC83B2CD181310026F537 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.0; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - BE9EC83C2CD181310026F537 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.0; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - BE9EC8202CD1812F0026F537 /* Build configuration list for PBXProject "hybrid-flutter-app" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BE9EC83B2CD181310026F537 /* Debug */, - BE9EC83C2CD181310026F537 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - BE9EC8382CD181310026F537 /* Build configuration list for PBXNativeTarget "hybrid-flutter-app" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - BE9EC8392CD181310026F537 /* Debug */, - BE9EC83A2CD181310026F537 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = BE9EC81D2CD1812F0026F537 /* Project object */; -} diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/AppDelegate.swift b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/AppDelegate.swift deleted file mode 100644 index 9157e26ae..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/AppDelegate.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// AppDelegate.swift -// hybrid-flutter-app -// -// Created by Ahmed alaa on 29/10/2024. -// - -import UIKit -import Flutter -import FlutterPluginRegistrant -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - - var flutterEngine: FlutterEngine! - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - flutterEngine = FlutterEngine(name: "my flutter engine") - flutterEngine.run() - GeneratedPluginRegistrant.register(with: flutterEngine) - - return true - } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - - -} - diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/AccentColor.colorset/Contents.json b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb8789700..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 230588010..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/Contents.json b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Base.lproj/LaunchScreen.storyboard b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329f..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Base.lproj/Main.storyboard b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Base.lproj/Main.storyboard deleted file mode 100644 index ddecb9df6..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Base.lproj/Main.storyboard +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Info.plist b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Info.plist deleted file mode 100644 index dd3c9afda..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/Info.plist +++ /dev/null @@ -1,25 +0,0 @@ - - - - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - - - - diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/SceneDelegate.swift b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/SceneDelegate.swift deleted file mode 100644 index d41584377..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/SceneDelegate.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// SceneDelegate.swift -// hybrid-flutter-app -// -// Created by Ahmed alaa on 29/10/2024. -// - -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - guard let _ = (scene as? UIWindowScene) else { return } - } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - - -} - diff --git a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/ViewController.swift b/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/ViewController.swift deleted file mode 100644 index 49fc98fd1..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/hybrid-flutter-app/ViewController.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// ViewController.swift -// hybrid-flutter-app -// -// Created by Ahmed alaa on 29/10/2024. -// - -import UIKit -import Flutter -class ViewController: UIViewController { - - @IBOutlet weak var flutterView: UIView! - override func viewDidLoad() { - super.viewDidLoad() - let appDelegate = UIApplication.shared.delegate as! AppDelegate - - - let flutterViewController = FlutterViewController(engine: appDelegate.flutterEngine, nibName: nil, bundle: nil) - - addChild(flutterViewController) - flutterViewController.view.frame = flutterView.bounds - flutterView.addSubview(flutterViewController.view) - flutterViewController.didMove(toParent: self) - // Do any additional setup after loading the view. - } - - -} - diff --git a/packages/instabug_private_views/example-hybrid-ios-app/init.sh b/packages/instabug_private_views/example-hybrid-ios-app/init.sh deleted file mode 100644 index bbdbd30db..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/init.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -cd my_flutter -flutter pub get -cd ../ -pod install --repo-update \ No newline at end of file diff --git a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/.gitignore b/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/.gitignore deleted file mode 100644 index 525e05cfb..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/.gitignore +++ /dev/null @@ -1,49 +0,0 @@ -.DS_Store -.dart_tool/ - -.pub/ - -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -migrate_working_dir/ - -*.swp -profile - -DerivedData/ - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -build/ -.android/ -.ios/ -.flutter-plugins -.flutter-plugins-dependencies - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json diff --git a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/.metadata b/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/.metadata deleted file mode 100644 index 1ff39d995..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "603104015dd692ea3403755b55d07813d5cf8965" - channel: "stable" - -project_type: module diff --git a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/README.md b/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/README.md deleted file mode 100644 index 12d679054..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# my_flutter - -A new Flutter module project. - -## Getting Started - -For help getting started with Flutter development, view the online -[documentation](https://flutter.dev/). - -For instructions integrating Flutter modules to your existing applications, -see the [add-to-app documentation](https://flutter.dev/to/add-to-app). diff --git a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/lib/main.dart b/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/lib/main.dart deleted file mode 100644 index 45f87f0bf..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/lib/main.dart +++ /dev/null @@ -1,76 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_private_views/instabug_private_view.dart'; - -void main() { - runZonedGuarded( - () { - WidgetsFlutterBinding.ensureInitialized(); - - Instabug.init( - token: 'ed6f659591566da19b67857e1b9d40ab', - invocationEvents: [InvocationEvent.floatingButton], - debugLogsLevel: LogLevel.verbose, - ); - - FlutterError.onError = (FlutterErrorDetails details) { - Zone.current.handleUncaughtError(details.exception, details.stack!); - }; - - enableInstabugMaskingPrivateViews(); - runApp(const MyApp()); - }, - CrashReporting.reportCrash, - ); -} - -class MyApp extends StatelessWidget { - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - debugShowCheckedModeBanner: false, - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: const MyHomePage(title: 'Flutter View'), - ); - } - - const MyApp({Key? key}) : super(key: key); -} - -class MyHomePage extends StatefulWidget { - const MyHomePage({Key? key, required this.title}) : super(key: key); - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - InstabugPrivateView( - child: const Text( - 'Private text', - ), - ), - ], - ), - ), // This trailing comma makes auto-formatting nicer for build methods. - ); - } -} diff --git a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec.lock b/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec.lock deleted file mode 100644 index 1e5288b3d..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec.lock +++ /dev/null @@ -1,227 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - characters: - dependency: transitive - description: - name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - clock: - dependency: transitive - description: - name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" - source: hosted - version: "1.1.1" - collection: - dependency: transitive - description: - name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a - url: "https://pub.dev" - source: hosted - version: "1.18.0" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - instabug_flutter: - dependency: "direct main" - description: - path: "../../../instabug_flutter" - relative: true - source: path - version: "14.0.0" - instabug_private_views: - dependency: "direct main" - description: - path: "../.." - relative: true - source: path - version: "1.0.1" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" - url: "https://pub.dev" - source: hosted - version: "10.0.5" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" - url: "https://pub.dev" - source: hosted - version: "3.0.5" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - lints: - dependency: transitive - description: - name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb - url: "https://pub.dev" - source: hosted - version: "0.12.16+1" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 - url: "https://pub.dev" - source: hosted - version: "1.15.0" - path: - dependency: transitive - description: - name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" - url: "https://pub.dev" - source: hosted - version: "1.9.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" - url: "https://pub.dev" - source: hosted - version: "1.11.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 - url: "https://pub.dev" - source: hosted - version: "2.1.2" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" - url: "https://pub.dev" - source: hosted - version: "0.7.2" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" - url: "https://pub.dev" - source: hosted - version: "14.2.5" -sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec.yaml b/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec.yaml deleted file mode 100644 index 5fc02c8cf..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec.yaml +++ /dev/null @@ -1,80 +0,0 @@ -name: my_flutter -description: "A new Flutter module project." - -version: 1.0.0+1 - -environment: - sdk: ">=2.12.0 <4.0.0" - -dependency_overrides: - instabug_flutter: - path: '../../../instabug_flutter' - -dependencies: - flutter: - sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 - instabug_flutter: - path: '../../../instabug_flutter' - instabug_private_views: - path: '../../../instabug_private_views' -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^4.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -flutter: - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add Flutter specific assets to your application, add an assets section, - # like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add Flutter specific custom fonts to your application, add a fonts - # section here, in this "flutter" section. Each entry in this list should - # have a "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package - - - # This section identifies your Flutter project as a module meant for - # embedding in a native host app. These identifiers should _not_ ordinarily - # be changed after generation - they are used to ensure that the tooling can - # maintain consistency when adding or modifying assets and plugins. - # They also do not have any bearing on your native host application's - # identifiers, which may be completely independent or the same as these. - module: - androidX: true - androidPackage: com.example.my_flutter - iosBundleIdentifier: com.example.myFlutter diff --git a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec_overrides.yaml b/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec_overrides.yaml deleted file mode 100644 index 385dc32cf..000000000 --- a/packages/instabug_private_views/example-hybrid-ios-app/my_flutter/pubspec_overrides.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# melos_managed_dependency_overrides: instabug_flutter,instabug_private_views -dependency_overrides: - instabug_flutter: - path: ../../../instabug_flutter - instabug_private_views: - path: ../.. diff --git a/packages/instabug_private_views/example/.metadata b/packages/instabug_private_views/example/.metadata deleted file mode 100644 index c2aa44bdb..000000000 --- a/packages/instabug_private_views/example/.metadata +++ /dev/null @@ -1,45 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "603104015dd692ea3403755b55d07813d5cf8965" - channel: "stable" - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - platform: android - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - platform: ios - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - platform: linux - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - platform: macos - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - platform: web - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - platform: windows - create_revision: 603104015dd692ea3403755b55d07813d5cf8965 - base_revision: 603104015dd692ea3403755b55d07813d5cf8965 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/instabug_private_views/example/README.md b/packages/instabug_private_views/example/README.md deleted file mode 100644 index 81240d7ca..000000000 --- a/packages/instabug_private_views/example/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# instabug_private_views_example - -Demonstrates how to use the instabug_private_views plugin. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/packages/instabug_private_views/example/android/app/build.gradle b/packages/instabug_private_views/example/android/app/build.gradle deleted file mode 100644 index a3103874a..000000000 --- a/packages/instabug_private_views/example/android/app/build.gradle +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" -} - -android { - namespace = "com.instabug.instabug_private_views_example" - compileSdk = 34 - ndkVersion = flutter.ndkVersion - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.instabug.instabug_private_views_example" - // You can update the following values to match your application needs. - // For more information, see: https://flutter.dev/to/review-gradle-config. - minSdk = flutter.minSdkVersion - targetSdk = flutter.targetSdkVersion - versionCode = flutter.versionCode - versionName = flutter.versionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug - } - } -} - -flutter { - source = "../.." -} diff --git a/packages/instabug_private_views/example/android/app/src/debug/AndroidManifest.xml b/packages/instabug_private_views/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 399f6981d..000000000 --- a/packages/instabug_private_views/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/instabug_private_views/example/android/app/src/main/AndroidManifest.xml b/packages/instabug_private_views/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 1a4340728..000000000 --- a/packages/instabug_private_views/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/instabug_private_views/example/android/app/src/main/java/com/instabug/instabug_private_views_example/MainActivity.java b/packages/instabug_private_views/example/android/app/src/main/java/com/instabug/instabug_private_views_example/MainActivity.java deleted file mode 100644 index bd7b0511b..000000000 --- a/packages/instabug_private_views/example/android/app/src/main/java/com/instabug/instabug_private_views_example/MainActivity.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.instabug.instabug_private_views_example; - -import io.flutter.embedding.android.FlutterActivity; - -public class MainActivity extends FlutterActivity { -} diff --git a/packages/instabug_private_views/example/android/app/src/main/kotlin/com/instabug/example/MainActivity.kt b/packages/instabug_private_views/example/android/app/src/main/kotlin/com/instabug/example/MainActivity.kt deleted file mode 100644 index 3759d1c71..000000000 --- a/packages/instabug_private_views/example/android/app/src/main/kotlin/com/instabug/example/MainActivity.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.instabug.example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() diff --git a/packages/instabug_private_views/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/instabug_private_views/example/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3f..000000000 --- a/packages/instabug_private_views/example/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/packages/instabug_private_views/example/android/app/src/main/res/drawable/launch_background.xml b/packages/instabug_private_views/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f88..000000000 --- a/packages/instabug_private_views/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/packages/instabug_private_views/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/instabug_private_views/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/packages/instabug_private_views/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/instabug_private_views/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/packages/instabug_private_views/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/instabug_private_views/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/packages/instabug_private_views/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/instabug_private_views/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/packages/instabug_private_views/example/android/app/src/main/res/values-night/styles.xml b/packages/instabug_private_views/example/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 06952be74..000000000 --- a/packages/instabug_private_views/example/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/packages/instabug_private_views/example/android/app/src/main/res/values/styles.xml b/packages/instabug_private_views/example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index cb1ef8805..000000000 --- a/packages/instabug_private_views/example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/packages/instabug_private_views/example/android/app/src/profile/AndroidManifest.xml b/packages/instabug_private_views/example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 399f6981d..000000000 --- a/packages/instabug_private_views/example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/instabug_private_views/example/android/build.gradle b/packages/instabug_private_views/example/android/build.gradle deleted file mode 100644 index 3b7cbec9f..000000000 --- a/packages/instabug_private_views/example/android/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = "../build" -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") - tasks.withType(Test) { - // Prevent tests in moduleA from running - if (project.name == 'video_player_android') { - exclude '**/*' - } - } -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} \ No newline at end of file diff --git a/packages/instabug_private_views/example/android/gradle.properties b/packages/instabug_private_views/example/android/gradle.properties deleted file mode 100644 index 259717082..000000000 --- a/packages/instabug_private_views/example/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError -android.useAndroidX=true -android.enableJetifier=true diff --git a/packages/instabug_private_views/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/instabug_private_views/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 7bb2df6ba..000000000 --- a/packages/instabug_private_views/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip diff --git a/packages/instabug_private_views/example/android/gradlew b/packages/instabug_private_views/example/android/gradlew deleted file mode 100755 index 9d82f7891..000000000 --- a/packages/instabug_private_views/example/android/gradlew +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/packages/instabug_private_views/example/android/gradlew.bat b/packages/instabug_private_views/example/android/gradlew.bat deleted file mode 100644 index 8a0b282aa..000000000 --- a/packages/instabug_private_views/example/android/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/packages/instabug_private_views/example/android/settings.gradle b/packages/instabug_private_views/example/android/settings.gradle deleted file mode 100644 index b9e43bd37..000000000 --- a/packages/instabug_private_views/example/android/settings.gradle +++ /dev/null @@ -1,25 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false -} - -include ":app" diff --git a/packages/instabug_private_views/example/assets/img.png b/packages/instabug_private_views/example/assets/img.png deleted file mode 100644 index fff04770f0f3a9e8a34bce7c805a3f02a9862c09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 181305 zcmced^;cBi8}H8yHBt`UFm#82bfdI@AOebnbT`rrA)$05T_PYYAW}n@lG2?6(%mzc z@4BD+FWg`DIqR%-*4k(9XFtz-zxMk?X=^GI;8NoP06?Is@=ON+zz?@z0D}E+IrIK| z0|0P9^_l!DZ{xiH9B-q^`tvg?G71NY^ihRJtnp#-VVM0xc$f+*A6Z)B!_qEGE>9An zh~9UtP4kI*6?Ox)6-&)LC(_J0P`5O_yc&ViuEDD*e6^Y8-^wANP{9H7Kw!H1^VkX@Q{Y|EF^Oe%2X>kosnFoU-M|h2Q#RxkP zyvle-fx~85XfWypUaa(|zU5BT(;1~B6Py6j|2L6)CT4skG%b5~j4dd$xV{fr#_bcU z;Ms|J_E|sDV_ni22QP#O?u~d(dG2~!W+wtlK#Iv%vP+rchara90`^$-CTb9>X~mlV zTpd&W9`av!?3q{`os@(u;7Ko4o3r?fZDNm+EU+sjp*R7oj<*PVgs~}Jf3AE)d(VYc z+K^=w=)dmx$^LPA+)M&qVQuUy3BOlXk%gK=?q02l_0z9)9ZNLe9D7S@e|&tw5xW>` zZatr`;qbp{j~Jk&)zIFSbkL-UU}7(5H3{nz1sXvgh{XcaMv%8Vd zx_ymS$Ao_oT$x%wr;m$_w&?B1wAqU|noYMvn08WaV>)$T;3I7Rw=^`F&G(@Zj{}CD zNu@i~HH}#L^`b7}I|u~`oJ{OB@OQ;k_J~+6Vg+i^`Eo@svkUcQafcEkVxsi&SZZX| zJZl8L5dgbK!g*(w;cbPGfFXrF^xW#Pk==);&SUg<9@Zh0Gj;NbaHN^{0{+5jX%o6; z15Jntm+r1f0@kr84OAFSMZpAJot>{-7%!+ayh)ML7|H81xz+bl4M}@*e$@}1l!0!^ z`B`Wuh|=C3t?gf~uPC}aMMXQ3%Q3OlxX&HJR2M5JKA{JM&3~ZR@mZ`GOhw;+BCS63 zknCA?`zON&NR1r0K``MGaedx7zR>{}jGEZIlJCSQ0-_Wxxoc#7s5)VIBg?B^ex1La zO*1Uf?7#P2B&9`0oM{P>X1RTMCm%TSKo|}@POdX_f*llWY42R}v!1#pY8>5k4`Dwa ze_f4XlkSBZk$`QlKWd24{Y{C62bhVBky8+{D)~(C+L~N!k*_|^Jr<+Sh29)H-RdXZ z?c|J1wC1|dOgpsd!)<%kLq51@qrM@KEDr&btUfc^cWY{gca6!3(~B0$&S1m0_aj{K zpB?&7th&(E&F)8|#fRIJ>U|ml;_JKiFsk*KL-s^fwy{fh0~IdGIz|-`Pz+68`aQmu zTy~R%_b4Re4RbxIwjjLUp z1x@4!fdWcQ3G(1uR9|pFcNFyKjRcibRRnW%b2VDO{IGft9qqG_qgD8%otB8)bpZn$ zdlZ6@?oqwQRZi^~8h|ZFxmbuLt)Xd{jOl68#JWf9DoT8*=xwx6pTtk}@&m;GZNN zI{0;dBK!<-^HDWX;zMdtU!R(tP9n>2CVL&d&$GarQN@#tOc_?|Tyee5t}c&kfN-Em zoNEOdH}ClSl7>Jk{VMdi92ATRFVjL?x;4M+qvD67 ~Nvh~D=@9ARS#oVi~x7R+z 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%0A2OJ-@K{7M6{*i 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�8=-8{0Uhe8lV%#(} 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 Q8t{6^epLEUA!!`)fAjQ(rT_o{ diff --git a/packages/instabug_private_views/example/ios/Flutter/AppFrameworkInfo.plist b/packages/instabug_private_views/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 7c5696400..000000000 --- a/packages/instabug_private_views/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 12.0 - - diff --git a/packages/instabug_private_views/example/ios/Flutter/Debug.xcconfig b/packages/instabug_private_views/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index ec97fc6f3..000000000 --- a/packages/instabug_private_views/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/instabug_private_views/example/ios/Flutter/Release.xcconfig b/packages/instabug_private_views/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index c4855bfe2..000000000 --- a/packages/instabug_private_views/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/packages/instabug_private_views/example/ios/Podfile b/packages/instabug_private_views/example/ios/Podfile deleted file mode 100644 index 8621254c6..000000000 --- a/packages/instabug_private_views/example/ios/Podfile +++ /dev/null @@ -1,46 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '12.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/feature-flutter_user_steps-base/14.1.0/Instabug.podspec' - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - pod 'OCMock', '3.6' - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/packages/instabug_private_views/example/ios/Podfile.lock b/packages/instabug_private_views/example/ios/Podfile.lock deleted file mode 100644 index 900830c0c..000000000 --- a/packages/instabug_private_views/example/ios/Podfile.lock +++ /dev/null @@ -1,49 +0,0 @@ -PODS: - - Flutter (1.0.0) - - Instabug (14.1.0) - - instabug_flutter (14.0.0): - - Flutter - - Instabug (= 14.1.0) - - instabug_private_views (0.0.1): - - Flutter - - instabug_flutter - - OCMock (3.6) - - video_player_avfoundation (0.0.1): - - Flutter - - FlutterMacOS - -DEPENDENCIES: - - Flutter (from `Flutter`) - - Instabug (from `https://ios-releases.instabug.com/custom/feature-flutter_user_steps-base/14.1.0/Instabug.podspec`) - - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - - instabug_private_views (from `.symlinks/plugins/instabug_private_views/ios`) - - OCMock (= 3.6) - - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) - -SPEC REPOS: - trunk: - - OCMock - -EXTERNAL SOURCES: - Flutter: - :path: Flutter - Instabug: - :podspec: https://ios-releases.instabug.com/custom/feature-flutter_user_steps-base/14.1.0/Instabug.podspec - instabug_flutter: - :path: ".symlinks/plugins/instabug_flutter/ios" - instabug_private_views: - :path: ".symlinks/plugins/instabug_private_views/ios" - video_player_avfoundation: - :path: ".symlinks/plugins/video_player_avfoundation/darwin" - -SPEC CHECKSUMS: - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - Instabug: 8eb6f63f3ac66f062025c15293549ab67150e9f9 - instabug_flutter: a24751dfaedd29475da2af062d3e19d697438f72 - instabug_private_views: df53ff3f1cc842cb686d43e077099d3b36426a7f - OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 - video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 - -PODFILE CHECKSUM: af9cfc3aee253487693ebb906ba6b3358615392c - -COCOAPODS: 1.16.0 diff --git a/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.pbxproj b/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index ef3f7beed..000000000 --- a/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,761 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 4EA625EC1B1293615B30A623 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92C8C175664DB55D5FE2AE9D /* Pods_RunnerTests.framework */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 8115939F17BE56A387B25531 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15AA449B734113B9F4617C0E /* Pods_Runner.framework */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - BE133A632CD831A500FEADB5 /* PrivateViewHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BE133A622CD831A500FEADB5 /* PrivateViewHostApiTests.m */; }; - BE9F8D392CD5C068003ADA97 /* PrivateViewApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BE9F8D382CD5C068003ADA97 /* PrivateViewApiTests.m */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 97C146E61CF9000F007C117D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 97C146ED1CF9000F007C117D; - remoteInfo = Runner; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0303582970644CA58D276892 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 15AA449B734113B9F4617C0E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3F54E317D7EFCD6FA9EBC039 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 820D7973B5497175631FF34A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 8801EEBF9F9D8EE99D4ED5A2 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 92C8C175664DB55D5FE2AE9D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 99B4BB79D25D93036AAF6480 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - A1871ACDFF6D3EA7210660EF /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - BE133A622CD831A500FEADB5 /* PrivateViewHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PrivateViewHostApiTests.m; sourceTree = ""; }; - BE9F8D382CD5C068003ADA97 /* PrivateViewApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PrivateViewApiTests.m; sourceTree = ""; }; - BE9F8D3A2CD5C06A003ADA97 /* RunnerTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RunnerTests-Bridging-Header.h"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 8115939F17BE56A387B25531 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C7F1472ADA1CCAD68225BF65 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 4EA625EC1B1293615B30A623 /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - BE9F8D382CD5C068003ADA97 /* PrivateViewApiTests.m */, - BE9F8D3A2CD5C06A003ADA97 /* RunnerTests-Bridging-Header.h */, - BE133A622CD831A500FEADB5 /* PrivateViewHostApiTests.m */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 51A32382AC0867EEF3CF4501 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 15AA449B734113B9F4617C0E /* Pods_Runner.framework */, - 92C8C175664DB55D5FE2AE9D /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 940EE8988085F83C8461DB17 /* Pods */ = { - isa = PBXGroup; - children = ( - 820D7973B5497175631FF34A /* Pods-Runner.debug.xcconfig */, - 99B4BB79D25D93036AAF6480 /* Pods-Runner.release.xcconfig */, - 0303582970644CA58D276892 /* Pods-Runner.profile.xcconfig */, - 8801EEBF9F9D8EE99D4ED5A2 /* Pods-RunnerTests.debug.xcconfig */, - A1871ACDFF6D3EA7210660EF /* Pods-RunnerTests.release.xcconfig */, - 3F54E317D7EFCD6FA9EBC039 /* Pods-RunnerTests.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 331C8082294A63A400263BE5 /* RunnerTests */, - 940EE8988085F83C8461DB17 /* Pods */, - 51A32382AC0867EEF3CF4501 /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - 331C8081294A63A400263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C8080294A63A400263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 5D0C51123159955CBB75DD3C /* [CP] Check Pods Manifest.lock */, - 331C807D294A63A400263BE5 /* Sources */, - 331C807F294A63A400263BE5 /* Resources */, - C7F1472ADA1CCAD68225BF65 /* Frameworks */, - 40EB49289482643018B2EF40 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 331C8086294A63A400263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - FA0379807AF94B93BE4FA182 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 589206114E198C940A065FDE /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C8080294A63A400263BE5 = { - CreatedOnToolsVersion = 14.0; - LastSwiftMigration = 1600; - TestTargetID = 97C146ED1CF9000F007C117D; - }; - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - 331C8080294A63A400263BE5 /* RunnerTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C807F294A63A400263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 40EB49289482643018B2EF40 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 589206114E198C940A065FDE /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 5D0C51123159955CBB75DD3C /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - FA0379807AF94B93BE4FA182 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C807D294A63A400263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BE9F8D392CD5C068003ADA97 /* PrivateViewApiTests.m in Sources */, - BE133A632CD831A500FEADB5 /* PrivateViewHostApiTests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 97C146ED1CF9000F007C117D /* Runner */; - targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 4574PQBJA9; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.instabug.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 331C8088294A63A400263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8801EEBF9F9D8EE99D4ED5A2 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.instabug.example.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OBJC_BRIDGING_HEADER = "RunnerTests/RunnerTests-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Debug; - }; - 331C8089294A63A400263BE5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = A1871ACDFF6D3EA7210660EF /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.instabug.example.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "RunnerTests/RunnerTests-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Release; - }; - 331C808A294A63A400263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 3F54E317D7EFCD6FA9EBC039 /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.instabug.example.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "RunnerTests/RunnerTests-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 4574PQBJA9; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.instabug.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 4574PQBJA9; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.instabug.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C8088294A63A400263BE5 /* Debug */, - 331C8089294A63A400263BE5 /* Release */, - 331C808A294A63A400263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5e..000000000 --- a/packages/instabug_private_views/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/instabug_private_views/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/instabug_private_views/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 8e3ca5dfe..000000000 --- a/packages/instabug_private_views/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/instabug_private_views/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/instabug_private_views/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c..000000000 --- a/packages/instabug_private_views/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/packages/instabug_private_views/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/instabug_private_views/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/packages/instabug_private_views/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/packages/instabug_private_views/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/instabug_private_views/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5e..000000000 --- a/packages/instabug_private_views/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/instabug_private_views/example/ios/Runner/AppDelegate.swift b/packages/instabug_private_views/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 626664468..000000000 --- a/packages/instabug_private_views/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Flutter -import UIKit - -@main -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab2..000000000 --- a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 797d452e458972bab9d994556c8305db4c827017..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 6ed2d933e1120817fe9182483a228007b18ab6ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cd7b0099ca80c806f8fe495613e8d6c69460d76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index fe730945a01f64a61e2235dbe3f45b08f7729182..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 502f463a9bc882b461c96aadf492d1729e49e725..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 0ec303439225b78712f49115768196d8d76f6790..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index e9f5fea27c705180eb716271f41b582e76dcbd90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1674 zcmV;526g#~P){YQnis^a@{&-nmRmq)<&%Mztj67_#M}W?l>kYSliK<%xAp;0j{!}J0!o7b zE>q9${Lb$D&h7k=+4=!ek^n+`0zq>LL1O?lVyea53S5x`Nqqo2YyeuIrQrJj9XjOp z{;T5qbj3}&1vg1VK~#9!?b~^C5-}JC@Pyrv-6dSEqJqT}#j9#dJ@GzT@B8}x zU&J@bBI>f6w6en+CeI)3^kC*U?}X%OD8$Fd$H&LV$H&LV$H&LV#|K5~mLYf|VqzOc zkc7qL~0sOYuM{tG`rYEDV{DWY`Z8&)kW*hc2VkBuY+^Yx&92j&StN}Wp=LD zxoGxXw6f&8sB^u})h@b@z0RBeD`K7RMR9deyL(ZJu#39Z>rT)^>v}Khq8U-IbIvT> z?4pV9qGj=2)TNH3d)=De<+^w;>S7m_eFKTvzeaBeir45xY!^m!FmxnljbSS_3o=g( z->^wC9%qkR{kbGnW8MfFew_o9h3(r55Is`L$8KI@d+*%{=Nx+FXJ98L0PjFIu;rGnnfY zn1R5Qnp<{Jq0M1vX=X&F8gtLmcWv$1*M@4ZfF^9``()#hGTeKeP`1!iED ztNE(TN}M5}3Bbc*d=FIv`DNv&@|C6yYj{sSqUj5oo$#*0$7pu|Dd2TLI>t5%I zIa4Dvr(iayb+5x=j*Vum9&irk)xV1`t509lnPO0%skL8_1c#Xbamh(2@f?4yUI zhhuT5<#8RJhGz4%b$`PJwKPAudsm|at?u;*hGgnA zU1;9gnxVBC)wA(BsB`AW54N{|qmikJR*%x0c`{LGsSfa|NK61pYH(r-UQ4_JXd!Rsz)=k zL{GMc5{h138)fF5CzHEDM>+FqY)$pdN3}Ml+riTgJOLN0F*Vh?{9ESR{SVVg>*>=# zix;VJHPtvFFCRY$Ks*F;VX~%*r9F)W`PmPE9F!(&s#x07n2<}?S{(ygpXgX-&B&OM zONY&BRQ(#%0%jeQs?oJ4P!p*R98>qCy5p8w>_gpuh39NcOlp)(wOoz0sY-Qz55eB~ z7OC-fKBaD1sE3$l-6QgBJO!n?QOTza`!S_YK z_v-lm^7{VO^8Q@M_^8F)09Ki6%=s?2_5eupee(w1FB%aqSweusQ-T+CH0Xt{` zFjMvW{@C&TB)k25()nh~_yJ9coBRL(0oO@HK~z}7?bm5j;y@69;bvlHb2tf!$ReA~x{22wTq550 z?f?Hnw(;m3ip30;QzdV~7pi!wyMYhDtXW#cO7T>|f=bdFhu+F!zMZ2UFj;GUKX7tI z;hv3{q~!*pMj75WP_c}>6)IWvg5_yyg<9Op()eD1hWC19M@?_9_MHec{Z8n3FaF{8 z;u`Mw0ly(uE>*CgQYv{be6ab2LWhlaH1^iLIM{olnag$78^Fd}%dR7;JECQ+hmk|o z!u2&!3MqPfP5ChDSkFSH8F2WVOEf0(E_M(JL17G}Y+fg0_IuW%WQ zG(mG&u?|->YSdk0;8rc{yw2@2Z&GA}z{Wb91Ooz9VhA{b2DYE7RmG zjL}?eq#iX%3#k;JWMx_{^2nNax`xPhByFiDX+a7uTGU|otOvIAUy|dEKkXOm-`aWS z27pUzD{a)Ct<6p{{3)+lq@i`t@%>-wT4r?*S}k)58e09WZYP0{{R3FC5Sl00039P)t-s|Ns9~ z#rP?<_5oL$Q^olD{r_0T`27C={r>*`|Nj71npVa5OTzc(_WfbW_({R{p56NV{r*M2 z_xt?)2V0#0NsfV0u>{42ctGP(8vQj-Btk1n|O0ZD=YLwd&R{Ko41Gr9H= zY@z@@bOAMB5Ltl$E>bJJ{>JP30ZxkmI%?eW{k`b?Wy<&gOo;dS`~CR$Vwb@XWtR|N zi~t=w02?-0&j0TD{>bb6sNwsK*!p?V`RMQUl(*DVjk-9Cx+-z1KXab|Ka2oXhX5f% z`$|e!000AhNklrxs)5QTeTVRiEmz~MKK1WAjCw(c-JK6eox;2O)?`? zTG`AHia671e^vgmp!llKp|=5sVHk#C7=~epA~VAf-~%aPC=%Qw01h8mnSZ|p?hz91 z7p83F3%LVu9;S$tSI$C^%^yud1dfTM_6p2|+5Ejp$bd`GDvbR|xit>i!ZD&F>@CJrPmu*UjD&?DfZs=$@e3FQA(vNiU+$A*%a} z?`XcG2jDxJ_ZQ#Md`H{4Lpf6QBDp81_KWZ6Tk#yCy1)32zO#3<7>b`eT7UyYH1eGz z;O(rH$=QR*L%%ZcBpc=eGua?N55nD^K(8<#gl2+pN_j~b2MHs4#mcLmv%DkspS-3< zpI1F=^9siI0s-;IN_IrA;5xm~3?3!StX}pUv0vkxMaqm+zxrg7X7(I&*N~&dEd0kD z-FRV|g=|QuUsuh>-xCI}vD2imzYIOIdcCVV=$Bz@*u0+Bs<|L^)32nN*=wu3n%Ynw z@1|eLG>!8ruU1pFXUfb`j>(=Gy~?Rn4QJ-c3%3T|(Frd!bI`9u&zAnyFYTqlG#&J7 zAkD(jpw|oZLNiA>;>hgp1KX7-wxC~31II47gc zHcehD6Uxlf%+M^^uN5Wc*G%^;>D5qT{>=uxUhX%WJu^Z*(_Wq9y}npFO{Hhb>s6<9 zNi0pHXWFaVZnb)1+RS&F)xOv6&aeILcI)`k#0YE+?e)5&#r7J#c`3Z7x!LpTc01dx zrdC3{Z;joZ^KN&))zB_i)I9fWedoN>Zl-6_Iz+^G&*ak2jpF07*qoM6N<$f;w%0(f|Me diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 0467bf12aa4d28f374bb26596605a46dcbb3e7c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2fd..000000000 --- a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/packages/instabug_private_views/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/instabug_private_views/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/instabug_private_views/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7c..000000000 --- a/packages/instabug_private_views/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/instabug_private_views/example/ios/Runner/Base.lproj/Main.storyboard b/packages/instabug_private_views/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516f..000000000 --- a/packages/instabug_private_views/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/instabug_private_views/example/ios/Runner/Info.plist b/packages/instabug_private_views/example/ios/Runner/Info.plist deleted file mode 100644 index 5458fc418..000000000 --- a/packages/instabug_private_views/example/ios/Runner/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Example - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - diff --git a/packages/instabug_private_views/example/ios/Runner/Runner-Bridging-Header.h b/packages/instabug_private_views/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a560..000000000 --- a/packages/instabug_private_views/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/packages/instabug_private_views/example/ios/RunnerTests/PrivateViewApiTests.m b/packages/instabug_private_views/example/ios/RunnerTests/PrivateViewApiTests.m deleted file mode 100644 index 4d7aa8a65..000000000 --- a/packages/instabug_private_views/example/ios/RunnerTests/PrivateViewApiTests.m +++ /dev/null @@ -1,206 +0,0 @@ -#import -#import -#import -#import -#import "FlutterPluginRegistrar+FlutterEngine.h" - - -@interface MockFlutterPluginRegistrar : NSObject -@end - -@implementation MockFlutterPluginRegistrar - -@end - - -@interface PrivateViewApiTests : XCTestCase -@property (nonatomic, strong) PrivateViewApi *api; -@property (nonatomic, strong) id mockFlutterApi; -@property (nonatomic, strong) id mockRegistrar; -@property (nonatomic, strong) id mockFlutterViewController; -@property (nonatomic, strong) id mockEngine; - -@end - -@implementation PrivateViewApiTests - -#pragma mark - Setup / Teardown - -- (void)setUp { - [super setUp]; - - - self.mockFlutterApi = OCMClassMock([InstabugPrivateViewFlutterApi class]); - - - MockFlutterPluginRegistrar *mockRegistrar = [[MockFlutterPluginRegistrar alloc] init]; - - self.mockRegistrar = OCMPartialMock(mockRegistrar); - - self.mockEngine = OCMClassMock([FlutterEngine class]); - OCMStub([self.mockRegistrar flutterEngine]).andReturn(self.mockEngine); - - self.mockFlutterViewController = OCMClassMock([UIViewController class]); - - OCMStub([self.mockEngine viewController]).andReturn(_mockFlutterViewController); - - self.api = OCMPartialMock([[PrivateViewApi alloc] initWithFlutterApi:self.mockFlutterApi registrar: self.mockRegistrar]); -} - -- (void)tearDown { - [self.mockFlutterApi stopMocking]; - [self.mockRegistrar stopMocking]; - [self.mockFlutterViewController stopMocking]; - [self.mockEngine stopMocking]; - - self.api = nil; - - [super tearDown]; -} - -#pragma mark - Tests - -- (void)testMask_Success { - XCTestExpectation *expectation = [self expectationWithDescription:@"Mask method success"]; - - CGSize imageSize = CGSizeMake(100, 100); // 100x100 pixels - - // Step 2: Create the image using UIGraphicsImageRenderer - UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageSize]; - - UIImage *screenshot = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) { - // Draw a red rectangle as an example - [[UIColor redColor] setFill]; - CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height); - UIRectFill(rect); - }]; - - NSArray *rectangles = @[@10, @20, @30, @40]; - UIView *mockView = [[UIView alloc] initWithFrame:CGRectMake(10, 20, 30, 40)]; - - OCMStub([self.mockFlutterApi getPrivateViewsWithCompletion:([OCMArg invokeBlockWithArgs:rectangles, [NSNull null], nil])]); - - - - OCMStub([self.mockFlutterViewController view]).andReturn(mockView); - - - [self.api mask:screenshot completion:^(UIImage *result) { - XCTAssertNotNil(result, @"Masked image should be returned."); - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testMask_Error { - XCTestExpectation *expectation = [self expectationWithDescription:@"Mask method with error"]; - - UIImage *screenshot = [UIImage new]; - FlutterError *error = [FlutterError errorWithCode:@"ERROR" message:@"Test error" details:nil]; - - OCMStub([self.mockFlutterApi getPrivateViewsWithCompletion:([OCMArg invokeBlockWithArgs:[NSNull null], error, nil])]); - - [self.api mask:screenshot completion:^(UIImage *result) { - XCTAssertEqual(result, screenshot, @"Original screenshot should be returned on error."); - [expectation fulfill]; - }]; - - [self waitForExpectationsWithTimeout:1 handler:nil]; -} - -- (void)testGetFlutterViewOrigin_ValidView { - UIView *mockView = [[UIView alloc] initWithFrame:CGRectMake(10, 20, 100, 100)]; - - OCMStub([self.mockFlutterViewController view]).andReturn(mockView); - - UIWindow* testWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - [testWindow addSubview:mockView]; - - CGPoint origin = [self.api getFlutterViewOrigin]; - - XCTAssertEqual(origin.x, 10); - XCTAssertEqual(origin.y, 20); -} - -- (void)testGetFlutterViewOrigin_NilView { - - OCMStub([self.mockFlutterViewController view]).andReturn(nil); -// - CGPoint origin = [self.api getFlutterViewOrigin]; - - XCTAssertEqual(origin.x, 0); - XCTAssertEqual(origin.y, 0); -} - -- (void)testDrawMaskedImage { - CGSize size = CGSizeMake(100, 100); - UIGraphicsBeginImageContext(size); - UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - NSArray *privateViews = @[ - [NSValue valueWithCGRect:CGRectMake(10, 10, 20, 20)], - [NSValue valueWithCGRect:CGRectMake(30, 30, 10, 10)] - ]; - - UIImage *result = [self.api drawMaskedImage:screenshot withPrivateViews:privateViews]; - - XCTAssertNotNil(result); - XCTAssertEqual(result.size.width, 100); - XCTAssertEqual(result.size.height, 100); -} - -- (void)testConvertToRectangles_ValidInput { - NSArray *rectangles = @[@10, @20, @30, @40]; - UIView *mockView = [[UIView alloc] initWithFrame:CGRectMake(5, 5, 100, 100)]; - OCMStub([self.mockFlutterViewController view]).andReturn(mockView); - - - NSArray *converted = [self.api convertToRectangles:rectangles]; - - XCTAssertEqual(converted.count, 1); - CGRect rect = [converted[0] CGRectValue]; - XCTAssertTrue(CGRectEqualToRect(rect, CGRectMake(10, 20, 21, 21))); -} - -- (void)testConcurrentMaskCalls { - XCTestExpectation *expectation = [self expectationWithDescription:@"Handle concurrent calls"]; - - CGSize imageSize = CGSizeMake(100, 100); // 100x100 pixels - - // Step 2: Create the image using UIGraphicsImageRenderer - UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageSize]; - - UIImage *screenshot = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) { - // Draw a red rectangle as an example - [[UIColor redColor] setFill]; - CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height); - UIRectFill(rect); - }]; - - NSArray *rectangles = @[@10, @20, @30, @40]; - - - OCMStub([self.mockFlutterApi getPrivateViewsWithCompletion:([OCMArg invokeBlockWithArgs:rectangles, [NSNull null], nil])]); - - - dispatch_group_t group = dispatch_group_create(); - - for (int i = 0; i < 5; i++) { - dispatch_group_enter(group); - - [self.api mask:screenshot completion:^(UIImage *result) { - XCTAssertNotNil(result, @"Each call should return a valid image."); - dispatch_group_leave(group); - }]; - } - - dispatch_group_notify(group, dispatch_get_main_queue(), ^{ - [expectation fulfill]; - }); - - [self waitForExpectationsWithTimeout:2 handler:nil]; -} - -@end diff --git a/packages/instabug_private_views/example/ios/RunnerTests/PrivateViewHostApiTests.m b/packages/instabug_private_views/example/ios/RunnerTests/PrivateViewHostApiTests.m deleted file mode 100644 index 8cbe328ea..000000000 --- a/packages/instabug_private_views/example/ios/RunnerTests/PrivateViewHostApiTests.m +++ /dev/null @@ -1,57 +0,0 @@ -#import -#import -#import -#import "PrivateViewApi.h" -#import "instabug_flutter/InstabugApi.h" -#import "PrivateViewHostApi.h" - -@interface PrivateViewHostApiTests : XCTestCase - -@property (nonatomic, strong) PrivateViewHostApi *api; -@property (nonatomic, strong) id privateViewApiMock; - -@end - -@implementation PrivateViewHostApiTests - -- (void)setUp { - [super setUp]; - - // Set up a mock for PrivateViewApi - self.privateViewApiMock = OCMClassMock([PrivateViewApi class]); - - // Initialize the PrivateViewHostApi instance - self.api = [[PrivateViewHostApi alloc] init]; - self.api.privateViewApi = self.privateViewApiMock; -} - -- (void)tearDown { - self.api = nil; - self.privateViewApiMock = nil; - [super tearDown]; -} - -- (void)testInitWithError_setsScreenshotMaskingHandler { - // Define an expectation for the screenshot masking handler - UIImage *mockScreenshot = [[UIImage alloc] init]; - UIImage *mockMaskedImage = [[UIImage alloc] init]; - FlutterError *error = nil; - - - - OCMStub([self.privateViewApiMock mask:mockScreenshot completion:([OCMArg invokeBlockWithArgs:mockMaskedImage, nil])]); - - - // Call initWithError and set up the screenshot masking handler - [self.api initWithError:&error]; - - // Invoke the screenshot masking handler - void (^completionHandler)(UIImage * _Nullable) = ^(UIImage * _Nullable maskedImage) { - XCTAssertEqual(maskedImage, mockMaskedImage, @"The masked image should be returned by the completion handler."); - }; - [InstabugApi setScreenshotMaskingHandler:^(UIImage * _Nonnull screenshot, void (^ _Nonnull completion)(UIImage * _Nullable)) { - completionHandler(screenshot); - }]; -} - -@end diff --git a/packages/instabug_private_views/example/ios/RunnerTests/RunnerTests-Bridging-Header.h b/packages/instabug_private_views/example/ios/RunnerTests/RunnerTests-Bridging-Header.h deleted file mode 100644 index 1b2cb5d6d..000000000 --- a/packages/instabug_private_views/example/ios/RunnerTests/RunnerTests-Bridging-Header.h +++ /dev/null @@ -1,4 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - diff --git a/packages/instabug_private_views/example/lib/main.dart b/packages/instabug_private_views/example/lib/main.dart deleted file mode 100644 index b379ba005..000000000 --- a/packages/instabug_private_views/example/lib/main.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_private_views/instabug_private_view.dart'; - -import 'package:instabug_private_views_example/private_view_page.dart'; - -void main() { - runZonedGuarded( - () { - WidgetsFlutterBinding.ensureInitialized(); - - Instabug.init( - token: 'ed6f659591566da19b67857e1b9d40ab', - invocationEvents: [InvocationEvent.floatingButton], - debugLogsLevel: LogLevel.verbose, - ); - - FlutterError.onError = (FlutterErrorDetails details) { - Zone.current.handleUncaughtError(details.exception, details.stack!); - }; - - enableInstabugMaskingPrivateViews(); - runApp(const InstabugUserSteps(child:PrivateViewPage())); - }, - CrashReporting.reportCrash, - ); -} diff --git a/packages/instabug_private_views/example/lib/private_view_page.dart b/packages/instabug_private_views/example/lib/private_view_page.dart deleted file mode 100644 index 8f23969b3..000000000 --- a/packages/instabug_private_views/example/lib/private_view_page.dart +++ /dev/null @@ -1,389 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_private_views/instabug_private_view.dart'; -import 'package:instabug_private_views_example/widget/instabug_button.dart'; -import 'package:instabug_private_views_example/widget/section_title.dart'; -import 'package:video_player/video_player.dart'; - -class PrivateViewPage extends StatefulWidget { - const PrivateViewPage({Key? key}) : super(key: key); - - @override - _PrivateViewPageState createState() => _PrivateViewPageState(); -} - -class _PrivateViewPageState extends State { - late VideoPlayerController _controller; - double _currentSliderValue = 20.0; - - RangeValues _currentRangeValues = const RangeValues(40, 80); - - String? _sliderStatus; - - bool? isChecked = true; - - int? _selectedValue = 1; - - bool light = true; - double _scale = 1.0; // Initial scale of the image - - TextEditingController _controller2 = TextEditingController(); - - String _currentValue = ''; - List _items = List.generate(20, (index) => 'Item ${index + 1}'); - - @override - void initState() { - super.initState(); - _controller = VideoPlayerController.networkUrl( - Uri.parse( - 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4'), - )..initialize().then((_) { - setState(() {}); - }); - _controller2.addListener(() { - setState(() { - _currentValue = _controller2.text; - }); - }); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - void _handleRadioValueChanged(int? value) { - setState(() { - _selectedValue = value; - }); - } - - @override - Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - navigatorObservers: [InstabugNavigatorObserver()], - home: Scaffold( - appBar: AppBar(title: const Text("Private Views page")), - body: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 16), - InstabugPrivateView( - child: const Text( - 'Private TextView', - style: TextStyle(fontSize: 18), - textAlign: TextAlign.center, - ), - ), - const SizedBox(height: 16), - InstabugPrivateView( - child: ElevatedButton( - onPressed: () { - const snackBar = SnackBar( - content: Text('Hello, you clicked on a private button'), - ); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - }, - child: const Text('I am a private button'), - ), - ), - const SizedBox(height: 16), - BackButton(), - NotificationListener( - onNotification: (ScrollNotification notification) { - return false; - }, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: List.generate( - 100, - (_) => InkWell( - onTap: () {}, - child: Container( - width: 100, - height: 100, - color: Colors.red, - margin: EdgeInsets.all(8), - ), - ), - ), - ), - ), - ), - SectionTitle('Sliders'), - Slider( - value: _currentSliderValue, - max: 100, - divisions: 5, - label: _currentSliderValue.round().toString(), - onChanged: (double value) { - setState(() { - _currentSliderValue = value; - }); - }, - ), - RangeSlider( - values: _currentRangeValues, - max: 100, - divisions: 5, - labels: RangeLabels( - _currentRangeValues.start.round().toString(), - _currentRangeValues.end.round().toString(), - ), - onChanged: (RangeValues values) { - setState(() { - _currentRangeValues = values; - }); - }, - ), - SectionTitle('Images'), - Row( - children: [ - Image.asset( - 'assets/img.png', - height: 100, - ), - Image.network( - "https://t3.ftcdn.net/jpg/00/50/07/64/360_F_50076454_TCvZEw37VyB5ZhcwEjkJHddtuV1cFmKY.jpg", - height: 100, - ), - ], - ), - InstabugButton(text: "I'm a button"), - ElevatedButton(onPressed: () {}, child: Text("data")), - SectionTitle('Toggles'), - Row( - children: [ - Checkbox( - tristate: true, - value: isChecked, - onChanged: (bool? value) { - setState(() { - isChecked = value; - }); - }, - ), - Radio( - value: 0, - groupValue: _selectedValue, - onChanged: _handleRadioValueChanged, - ), - Switch( - value: light, - activeColor: Colors.red, - onChanged: (bool value) { - setState(() { - light = value; - }); - }, - ), - ], - ), - GestureDetector( - onScaleUpdate: (details) { - setState(() { - _scale = details.scale; - _scale = _scale.clamp(1.0, - 3.0); // Limit zoom between 1x and 3x// Update scale based on pinch gesture - }); - }, - onScaleEnd: (details) { - // You can add logic to reset or clamp the scale if needed - if (_scale < 1.0) { - _scale = 1.0; // Prevent shrinking below original size - } - }, - child: Transform.scale( - scale: _scale, // Apply the scale transformation - child: Image.asset( - "assets/img.png", - height: 300, - ), - ), - ), - SectionTitle('TextInput'), - Column( - children: [ - Padding( - padding: EdgeInsets.all(16.0), // Set the padding value - child: Column( - children: [ - TextField( - key: Key('text_field'), - controller: _controller2, - // Bind the controller to the TextField - decoration: InputDecoration( - labelText: "Type something in a text field with key", - border: OutlineInputBorder(), - ), - ), - InstabugPrivateView( - child: TextField( - controller: _controller2, - // Bind the controller to the TextField - decoration: InputDecoration( - labelText: "Private view", - border: OutlineInputBorder(), - ), - ), - ), - InstabugPrivateView( - child: TextField( - controller: _controller2, - // Bind the controller to the TextField - obscureText: true, - decoration: InputDecoration( - border: OutlineInputBorder(), - labelText: 'Password', - ), - ), - ), - TextFormField( - obscureText: true, - controller: _controller2, - // Bind the controller to the TextField - decoration: const InputDecoration( - icon: Icon(Icons.person), - hintText: 'What do people call you?', - labelText: 'Name *', - ), - onSaved: (String? value) { - // This optional block of code can be used to run - // code when the user saves the form. - }, - validator: (String? value) { - return (value != null && value.contains('@')) - ? 'Do not use the @ char.' - : null; - }, - ), - ], - ), - ), - ListView.builder( - itemCount: _items.length, - shrinkWrap: true, - itemBuilder: (context, index) { - return Dismissible( - key: Key(_items[index]), - // Unique key for each item - onDismissed: (direction) { - // Remove the item from the list - setState(() { - _items.removeAt(index); - }); - - // Show a snackbar or other UI feedback on dismissal - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Item dismissed')), - ); - }, - background: Container(color: Colors.red), - // Background color when swiped - direction: DismissDirection.endToStart, - // Swipe direction (left to right) - child: ListTile( - title: Text(_items[index]), - ), - ); - }, - ), - ], - ), - - InstabugPrivateView( - child: Image.asset( - 'assets/img.png', - // Add this image to your assets folder - height: 100, - ), - ), - const SizedBox(height: 33), - InstabugPrivateView( - child: const TextField( - obscureText: true, - decoration: InputDecoration( - hintText: 'password', - labelText: 'Password', - border: OutlineInputBorder(), - ), - ), - ), - const SizedBox(height: 16), - const TextField( - keyboardType: TextInputType.emailAddress, - decoration: InputDecoration( - hintText: 'Email', - labelText: 'Email', - border: OutlineInputBorder(), - ), - ), - const SizedBox(height: 16), - Column( - children: [ - InstabugPrivateView( - child: const Text( - 'Private TextView in column', - style: TextStyle(fontSize: 18), - textAlign: TextAlign.center, - ), - ), - SizedBox( - height: 10, - ), - const Text( - 'TextView in column', - style: TextStyle(fontSize: 18), - textAlign: TextAlign.center, - ), - ], - ), - const SizedBox(height: 24), - InstabugPrivateView( - child: Container( - height: 300, - child: _controller.value.isInitialized - ? AspectRatio( - aspectRatio: _controller.value.aspectRatio, - child: VideoPlayer(_controller), - ) - : const Center(child: CircularProgressIndicator()), - ), - ), - const SizedBox(height: 24), - const SizedBox(height: 24), - const SizedBox(height: 24), - SizedBox( - height: 200, - child: CustomScrollView( - slivers: [ - InstabugSliverPrivateView( - sliver: SliverToBoxAdapter( - child: Container( - color: Colors.red, - child: const Text( - "Private Sliver Widget", - style: TextStyle(fontSize: 18), - textAlign: TextAlign.center, - ), - ), - ), - ) - ], - ), - ) - ], - ), - ), - ), - ), - ); - } -} diff --git a/packages/instabug_private_views/example/lib/widget/instabug_button.dart b/packages/instabug_private_views/example/lib/widget/instabug_button.dart deleted file mode 100644 index 97e434061..000000000 --- a/packages/instabug_private_views/example/lib/widget/instabug_button.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:flutter/material.dart'; - -class InstabugButton extends StatelessWidget { - const InstabugButton({ - Key? key, - required this.text, - this.onPressed, - this.fontSize, - this.margin, - }) : super(key: key); - - const InstabugButton.smallFontSize({ - Key? key, - required this.text, - this.onPressed, - this.fontSize = 10.0, - this.margin, - }) : super(key: key); - - final String text; - final Function()? onPressed; - final double? fontSize; - - final EdgeInsetsGeometry? margin; - - @override - Widget build(BuildContext context) { - return Container( - width: double.infinity, - margin: margin ?? - const EdgeInsets.symmetric( - horizontal: 20.0, - ), - child: ElevatedButton( - onPressed: onPressed, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.lightBlue, - foregroundColor: Colors.white, - textStyle: Theme.of(context) - .textTheme - .labelLarge - ?.copyWith(fontSize: fontSize), - ), - child: Text(text), - ), - ); - } -} diff --git a/packages/instabug_private_views/example/lib/widget/instabug_text_field.dart b/packages/instabug_private_views/example/lib/widget/instabug_text_field.dart deleted file mode 100644 index 3d01cc623..000000000 --- a/packages/instabug_private_views/example/lib/widget/instabug_text_field.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; - -class InstabugTextField extends StatelessWidget { - const InstabugTextField({ - Key? key, - required this.label, - required this.controller, - this.labelStyle, - this.margin, - this.keyboardType, - this.validator, - }) : super(key: key); - - final String label; - final TextEditingController controller; - final EdgeInsetsGeometry? margin; - final TextStyle? labelStyle; - final TextInputType? keyboardType; - final FormFieldValidator? validator; - - @override - Widget build(BuildContext context) { - return Container( - margin: margin ?? - const EdgeInsets.symmetric( - horizontal: 20.0, - ), - child: TextFormField( - controller: controller, - keyboardType: keyboardType, - validator: validator, - decoration: InputDecoration( - labelText: label, - labelStyle: labelStyle ?? Theme.of(context).textTheme.labelLarge, - suffixIcon: IconButton( - onPressed: controller.clear, - iconSize: 12.0, - icon: const Icon( - Icons.clear, - ), - ), - ), - ), - ); - } -} diff --git a/packages/instabug_private_views/example/lib/widget/section_title.dart b/packages/instabug_private_views/example/lib/widget/section_title.dart deleted file mode 100644 index 2c0509fa8..000000000 --- a/packages/instabug_private_views/example/lib/widget/section_title.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:flutter/material.dart'; - -class SectionTitle extends StatelessWidget { - final String text; - - const SectionTitle(this.text, {Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - alignment: Alignment.centerLeft, - margin: const EdgeInsets.only(top: 20.0, left: 20.0), - child: Text( - text, - textAlign: TextAlign.left, - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - ); - } -} diff --git a/packages/instabug_private_views/example/pubspec.lock b/packages/instabug_private_views/example/pubspec.lock deleted file mode 100644 index 29e14f6c8..000000000 --- a/packages/instabug_private_views/example/pubspec.lock +++ /dev/null @@ -1,304 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - characters: - dependency: transitive - description: - name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - clock: - dependency: transitive - description: - name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" - source: hosted - version: "1.1.1" - collection: - dependency: transitive - description: - name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf - url: "https://pub.dev" - source: hosted - version: "1.19.0" - csslib: - dependency: transitive - description: - name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - html: - dependency: transitive - description: - name: html - sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" - url: "https://pub.dev" - source: hosted - version: "0.15.5" - instabug_flutter: - dependency: "direct main" - description: - path: "../../instabug_flutter" - relative: true - source: path - version: "14.0.0" - instabug_private_views: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "1.0.1" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" - url: "https://pub.dev" - source: hosted - version: "10.0.7" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" - url: "https://pub.dev" - source: hosted - version: "3.0.8" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - lints: - dependency: transitive - description: - name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb - url: "https://pub.dev" - source: hosted - version: "0.12.16+1" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 - url: "https://pub.dev" - source: hosted - version: "1.15.0" - path: - dependency: transitive - description: - name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" - url: "https://pub.dev" - source: hosted - version: "1.9.0" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" - url: "https://pub.dev" - source: hosted - version: "1.12.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 - url: "https://pub.dev" - source: hosted - version: "2.1.2" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" - url: "https://pub.dev" - source: hosted - version: "0.7.3" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - video_player: - dependency: "direct main" - description: - name: video_player - sha256: "4a8c3492d734f7c39c2588a3206707a05ee80cef52e8c7f3b2078d430c84bc17" - url: "https://pub.dev" - source: hosted - version: "2.9.2" - video_player_android: - dependency: transitive - description: - name: video_player_android - sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898" - url: "https://pub.dev" - source: hosted - version: "2.7.16" - video_player_avfoundation: - dependency: transitive - description: - name: video_player_avfoundation - sha256: "0b146e5d82e886ff43e5a46c6bcbe390761b802864a6e2503eb612d69a405dfa" - url: "https://pub.dev" - source: hosted - version: "2.6.3" - video_player_platform_interface: - dependency: transitive - description: - name: video_player_platform_interface - sha256: "229d7642ccd9f3dc4aba169609dd6b5f3f443bb4cc15b82f7785fcada5af9bbb" - url: "https://pub.dev" - source: hosted - version: "6.2.3" - video_player_web: - dependency: transitive - description: - name: video_player_web - sha256: "881b375a934d8ebf868c7fb1423b2bfaa393a0a265fa3f733079a86536064a10" - url: "https://pub.dev" - source: hosted - version: "2.3.3" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b - url: "https://pub.dev" - source: hosted - version: "14.3.0" - web: - dependency: transitive - description: - name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb - url: "https://pub.dev" - source: hosted - version: "1.1.0" -sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.24.0" diff --git a/packages/instabug_private_views/example/pubspec.yaml b/packages/instabug_private_views/example/pubspec.yaml deleted file mode 100644 index d387bb1ed..000000000 --- a/packages/instabug_private_views/example/pubspec.yaml +++ /dev/null @@ -1,70 +0,0 @@ -name: instabug_private_views_example -description: "Demonstrates how to use the instabug_private_views plugin." -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -environment: - sdk: ">=2.12.0 <4.0.0" - -dependencies: - flutter: - sdk: flutter - - instabug_flutter: - path: '../../instabug_flutter' - instabug_private_views: - path: '../' - - cupertino_icons: ^1.0.8 - video_player: - -dev_dependencies: - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^4.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - assets: - - assets/img.png - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package diff --git a/packages/instabug_private_views/example/pubspec_overrides.yaml b/packages/instabug_private_views/example/pubspec_overrides.yaml deleted file mode 100644 index 387b3324d..000000000 --- a/packages/instabug_private_views/example/pubspec_overrides.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# melos_managed_dependency_overrides: instabug_flutter,instabug_private_views -dependency_overrides: - instabug_flutter: - path: ../../instabug_flutter - instabug_private_views: - path: .. diff --git a/packages/instabug_private_views/ios/.gitignore b/packages/instabug_private_views/ios/.gitignore deleted file mode 100644 index 034771fc9..000000000 --- a/packages/instabug_private_views/ios/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -.idea/ -.vagrant/ -.sconsign.dblite -.svn/ - -.DS_Store -*.swp -profile - -DerivedData/ -build/ -GeneratedPluginRegistrant.h -GeneratedPluginRegistrant.m - -.generated/ - -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 - -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 - -xcuserdata - -*.moved-aside - -*.pyc -*sync/ -Icon? -.tags* - -/Flutter/Generated.xcconfig -/Flutter/ephemeral/ -/Flutter/flutter_export_environment.sh diff --git a/packages/instabug_private_views/ios/Assets/.gitkeep b/packages/instabug_private_views/ios/Assets/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/instabug_private_views/ios/Classes/InstabugPrivateViewsPlugin.h b/packages/instabug_private_views/ios/Classes/InstabugPrivateViewsPlugin.h deleted file mode 100644 index f1ab588ce..000000000 --- a/packages/instabug_private_views/ios/Classes/InstabugPrivateViewsPlugin.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -@interface InstabugPrivateViewsPlugin : NSObject -@end diff --git a/packages/instabug_private_views/ios/Classes/InstabugPrivateViewsPlugin.m b/packages/instabug_private_views/ios/Classes/InstabugPrivateViewsPlugin.m deleted file mode 100644 index 833cea6de..000000000 --- a/packages/instabug_private_views/ios/Classes/InstabugPrivateViewsPlugin.m +++ /dev/null @@ -1,13 +0,0 @@ -#import "InstabugPrivateViewsPlugin.h" -#import "PrivateViewApi.h" -#import "PrivateViewHostApi.h" -@implementation InstabugPrivateViewsPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - PrivateViewApi* privateViewApi = InitPrivateViewApi([registrar messenger],registrar); - InitPrivateViewApi([registrar messenger], registrar); - InitPrivateViewHostApi([registrar messenger], privateViewApi); - -} - - -@end diff --git a/packages/instabug_private_views/ios/Classes/instabug_private_views-Bridging-Header.h b/packages/instabug_private_views/ios/Classes/instabug_private_views-Bridging-Header.h deleted file mode 100644 index 1b2cb5d6d..000000000 --- a/packages/instabug_private_views/ios/Classes/instabug_private_views-Bridging-Header.h +++ /dev/null @@ -1,4 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - diff --git a/packages/instabug_private_views/ios/Resources/PrivacyInfo.xcprivacy b/packages/instabug_private_views/ios/Resources/PrivacyInfo.xcprivacy deleted file mode 100644 index a34b7e2e6..000000000 --- a/packages/instabug_private_views/ios/Resources/PrivacyInfo.xcprivacy +++ /dev/null @@ -1,14 +0,0 @@ - - - - - NSPrivacyTrackingDomains - - NSPrivacyAccessedAPITypes - - NSPrivacyCollectedDataTypes - - NSPrivacyTracking - - - diff --git a/packages/instabug_private_views/ios/instabug_private_views.podspec b/packages/instabug_private_views/ios/instabug_private_views.podspec deleted file mode 100644 index 39751464c..000000000 --- a/packages/instabug_private_views/ios/instabug_private_views.podspec +++ /dev/null @@ -1,30 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint instabug_private_views.podspec` to validate before publishing. -# -Pod::Spec.new do |s| - s.name = 'instabug_private_views' - s.version = '0.0.1' - s.summary = 'A new Flutter plugin project.' - s.description = <<-DESC -A new Flutter plugin project. - DESC - s.homepage = 'http://example.com' - s.license = { :file => '../LICENSE' } - s.author = { 'Your Company' => 'email@example.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - s.dependency 'instabug_flutter' - s.platform = :ios, '12.0' - - # Flutter.framework does not contain a i386 slice. - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } - - # If your plugin requires a privacy manifest, for example if it uses any - # required reason APIs, update the PrivacyInfo.xcprivacy file to describe your - # plugin's privacy impact, and then uncomment this line. For more information, - # see https://developer.apple.com/documentation/bundleresources/privacy_manifest_files - # s.resource_bundles = {'instabug_private_views_privacy' => ['Resources/PrivacyInfo.xcprivacy']} -end diff --git a/packages/instabug_private_views/lib/instabug_private_view.dart b/packages/instabug_private_views/lib/instabug_private_view.dart deleted file mode 100644 index 0be5a6278..000000000 --- a/packages/instabug_private_views/lib/instabug_private_view.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:instabug_private_views/src/generated/instabug_private_view.api.g.dart'; -import 'package:instabug_private_views/src/private_views_manager.dart'; - -export 'src/instabug_private_view.dart'; -export 'src/instabug_sliver_private_view.dart'; - -void enableInstabugMaskingPrivateViews() { - final api = InstabugPrivateViewHostApi(); - api.init(); - InstabugPrivateViewFlutterApi.setup(PrivateViewsManager.I); -} diff --git a/packages/instabug_private_views/lib/src/instabug_private_view.dart b/packages/instabug_private_views/lib/src/instabug_private_view.dart deleted file mode 100644 index 3d16ee1b1..000000000 --- a/packages/instabug_private_views/lib/src/instabug_private_view.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:instabug_private_views/src/private_views_manager.dart'; -import 'package:instabug_private_views/src/visibility_detector/visibility_detector.dart'; - -class InstabugPrivateView extends StatefulWidget { - final Widget child; - - // Making the constructor const prevents the VisibilityDetector from detecting changes in the view, - // ignore: prefer_const_constructors_in_immutables - InstabugPrivateView({required this.child}) : super(key: null); - - @override - State createState() => _InstabugPrivateViewState(); -} - -class _InstabugPrivateViewState extends State { - final GlobalKey _visibilityDetectorKey = GlobalKey(); - final GlobalKey _childKey = GlobalKey(); - - @override - void initState() { - _addPrivateView(); - super.initState(); - } - - @override - void dispose() { - _removePrivateView(); - super.dispose(); - } - - void _addPrivateView() { - PrivateViewsManager.I.mask(_childKey); - } - - void _removePrivateView() { - PrivateViewsManager.I.unMask(_childKey); - } - - void _onVisibilityChanged(bool isVisible) { - if (isVisible) { - _addPrivateView(); - } else { - _removePrivateView(); - } - } - - @override - Widget build(BuildContext context) { - return VisibilityDetector( - key: _visibilityDetectorKey, - onVisibilityChanged: _onVisibilityChanged, - child: KeyedSubtree(key: _childKey, child: widget.child), - ); - } -} diff --git a/packages/instabug_private_views/lib/src/instabug_sliver_private_view.dart b/packages/instabug_private_views/lib/src/instabug_sliver_private_view.dart deleted file mode 100644 index bc0237513..000000000 --- a/packages/instabug_private_views/lib/src/instabug_sliver_private_view.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:instabug_private_views/src/private_views_manager.dart'; -import 'package:instabug_private_views/src/visibility_detector/sliver_visibility_detector.dart'; - -class InstabugSliverPrivateView extends StatefulWidget { - final Widget sliver; - - // Making the constructor const prevents the VisibilityDetector from detecting changes in the view, - // ignore: prefer_const_constructors_in_immutables, use_super_parameters - InstabugSliverPrivateView({Key? key, required this.sliver}) : super(key: key); - - @override - State createState() => - _InstabugSliverPrivateViewState(); -} - -class _InstabugSliverPrivateViewState extends State { - final key = GlobalKey(); - final GlobalKey _childKey = GlobalKey(); - - @override - void dispose() { - _removePrivateView(); - super.dispose(); - } - - @override - void initState() { - _addPrivateView(); - super.initState(); - } - - void _addPrivateView() { - PrivateViewsManager.I.mask(_childKey); - } - - void _removePrivateView() { - PrivateViewsManager.I.unMask(_childKey); - } - - void _onVisibilityChanged(bool isVisible) { - if (isVisible) { - _addPrivateView(); - } else { - _removePrivateView(); - } - } - - @override - Widget build(BuildContext context) { - return SliverVisibilityDetector( - key: key, - onVisibilityChanged: _onVisibilityChanged, - sliver: KeyedSubtree(key: _childKey, child: widget.sliver), - ); - } -} diff --git a/packages/instabug_private_views/lib/src/private_views_manager.dart b/packages/instabug_private_views/lib/src/private_views_manager.dart deleted file mode 100644 index 50815fbe8..000000000 --- a/packages/instabug_private_views/lib/src/private_views_manager.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:instabug_private_views/src/generated/instabug_private_view.api.g.dart'; - -/// responsible for masking views -/// before they are sent to the native SDKs. -class PrivateViewsManager implements InstabugPrivateViewFlutterApi { - PrivateViewsManager._(); - - static PrivateViewsManager _instance = PrivateViewsManager._(); - - static PrivateViewsManager get instance => _instance; - - /// Shorthand for [instance] - static PrivateViewsManager get I => instance; - - final Set _keys = {}; - - @visibleForTesting - // ignore: use_setters_to_change_properties - static void setInstance(PrivateViewsManager instance) { - _instance = instance; - } - - Rect? getLayoutRectInfoFromKey(GlobalKey key) { - final renderObject = key.currentContext?.findRenderObject(); - - if (renderObject == null) { - return null; - } - - final globalOffset = _getRenderGlobalOffset(renderObject); - - if (renderObject is RenderProxyBox) { - if (renderObject.child == null) { - return null; - } - - return MatrixUtils.transformRect( - renderObject.child!.getTransformTo(renderObject), - Offset.zero & renderObject.child!.size, - ).shift(globalOffset); - } - - return renderObject.paintBounds.shift(globalOffset); - } - - // The is the same implementation used in RenderBox.localToGlobal (a subclass of RenderObject) - Offset _getRenderGlobalOffset(RenderObject renderObject) { - return MatrixUtils.transformPoint( - renderObject.getTransformTo(null), - Offset.zero, - ); - } - - void mask(GlobalKey key) { - _keys.add(key); - } - - void unMask(GlobalKey key) { - _keys.remove(key); - } - - @override - List getPrivateViews() { - final result = []; - - for (final view in _keys) { - final rect = getLayoutRectInfoFromKey(view); - - if (rect == null) continue; - - result.addAll([ - rect.left, - rect.top, - rect.right, - rect.bottom, - ]); - } - - return result; - } -} diff --git a/packages/instabug_private_views/lib/src/visibility_detector/base_render_visibility_detector.dart b/packages/instabug_private_views/lib/src/visibility_detector/base_render_visibility_detector.dart deleted file mode 100644 index 46b901235..000000000 --- a/packages/instabug_private_views/lib/src/visibility_detector/base_render_visibility_detector.dart +++ /dev/null @@ -1,266 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:instabug_private_views/src/visibility_detector/visibillity_utils.dart'; - -typedef VisibilityChangedCallback = void Function(bool isVisible); - -mixin RenderVisibilityDetectorBase on RenderObject { - static int? get debugUpdateCount { - if (!kDebugMode) { - return null; - } - return _updates.length; - } - - static Duration updateInterval = const Duration(milliseconds: 500); - static final Map _updates = {}; - static final Map _lastVisibility = {}; - - static void forget(Key key) { - _updates.remove(key); - _lastVisibility.remove(key); - - if (_updates.isEmpty) { - _timer?.cancel(); - _timer = null; - } - } - - static Timer? _timer; - - static void _handleTimer() { - _timer = null; - // Ensure that work is done between frames so that calculations are - // performed from a consistent state. We use `scheduleTask` here instead - // of `addPostFrameCallback` or `scheduleFrameCallback` so that work will - // be done even if a new frame isn't scheduled and without unnecessarily - // scheduling a new frame. - SchedulerBinding.instance.scheduleTask( - _processCallbacks, - Priority.touch, - ); - } - - /// Executes visibility callbacks for all updated instances. - static void _processCallbacks() { - for (final callback in _updates.values) { - callback(); - } - - _updates.clear(); - } - - void _fireCallback(ContainerLayer? layer, Rect bounds) { - final oldInfo = _lastVisibility[key]; - final visible = _determineVisibility(layer, bounds); - - if (visible == oldInfo) { - return; - } - - if (visible) { - _lastVisibility[key] = visible; - } else { - // Track only visible items so that the map does not grow unbounded. - if (oldInfo != null) { - _lastVisibility.remove(key); - } - } - - onVisibilityChanged?.call(visible); - } - - /// The key for the corresponding [VisibilityDetector] widget. - Key get key; - - VoidCallback? _compositionCallbackCanceller; - - VisibilityChangedCallback? _onVisibilityChanged; - - // ignore: use_setters_to_change_properties - void init({required VisibilityChangedCallback? visibilityChangedCallback}) { - _onVisibilityChanged = visibilityChangedCallback; - } - - VisibilityChangedCallback? get onVisibilityChanged => _onVisibilityChanged; - - set onVisibilityChanged(VisibilityChangedCallback? value) { - _compositionCallbackCanceller?.call(); - _compositionCallbackCanceller = null; - _onVisibilityChanged = value; - - if (value == null) { - forget(key); - } else { - markNeedsPaint(); - // If an update is happening and some ancestor no longer paints this RO, - // the markNeedsPaint above will never cause the composition callback to - // fire and we could miss a hide event. This schedule will get - // over-written by subsequent updates in paint, if paint is called. - _scheduleUpdate(); - } - } - - int _debugScheduleUpdateCount = 0; - - /// The number of times the schedule update callback has been invoked from - /// [Layer.addCompositionCallback]. - /// - /// This is used for testing, and always returns null outside of debug mode. - @visibleForTesting - int? get debugScheduleUpdateCount { - if (kDebugMode) { - return _debugScheduleUpdateCount; - } - return null; - } - - void _scheduleUpdate([ContainerLayer? layer]) { - if (kDebugMode) { - _debugScheduleUpdateCount += 1; - } - final isFirstUpdate = _updates.isEmpty; - _updates[key] = () { - if (bounds == null) { - return; - } - _fireCallback(layer, bounds!); - }; - - if (updateInterval == Duration.zero) { - if (isFirstUpdate) { - // We're about to render a frame, so a post-frame callback is guaranteed - // to fire and will give us the better immediacy than `scheduleTask`. - SchedulerBinding.instance.addPostFrameCallback((timeStamp) { - _processCallbacks(); - }); - } - } else if (_timer == null) { - // We use a normal [Timer] instead of a [RestartableTimer] so that changes - // to the update duration will be picked up automatically. - _timer = Timer(updateInterval, _handleTimer); - } else { - assert(_timer!.isActive); - } - } - - bool _determineVisibility(ContainerLayer? layer, Rect bounds) { - if (_disposed || layer == null || layer.attached == false || !attached) { - // layer is detached and thus invisible. - return false; - } - final transform = Matrix4.identity(); - - // Check if any ancestors decided to skip painting this RenderObject. - if (parent != null) { - // ignore: unnecessary_cast - var ancestor = parent! as RenderObject; - RenderObject child = this; - while (ancestor.parent != null) { - if (!ancestor.paintsChild(child)) { - return false; - } - child = ancestor; - // ignore: unnecessary_cast - ancestor = ancestor.parent! as RenderObject; - } - } - - // Create a list of Layers from layer to the root, excluding the root - // since that has the DPR transform and we want to work with logical pixels. - // Add one extra leaf layer so that we can apply the transform of `layer` - // to the matrix. - ContainerLayer? ancestor = layer; - final ancestors = [ContainerLayer()]; - while (ancestor != null && ancestor.parent != null) { - ancestors.add(ancestor); - ancestor = ancestor.parent; - } - - var clip = Rect.largest; - for (var index = ancestors.length - 1; index > 0; index -= 1) { - final parent = ancestors[index]; - final child = ancestors[index - 1]; - final parentClip = parent.describeClipBounds(); - if (parentClip != null) { - clip = clip.intersect(MatrixUtils.transformRect(transform, parentClip)); - } - parent.applyTransform(child, transform); - } - - // Apply whatever transform/clip was on the canvas when painting. - if (_lastPaintClipBounds != null) { - clip = clip.intersect( - MatrixUtils.transformRect( - transform, - _lastPaintClipBounds!, - ), - ); - } - if (_lastPaintTransform != null) { - transform.multiply(_lastPaintTransform!); - } - return isWidgetVisible( - MatrixUtils.transformRect(transform, bounds), - clip, - ); - } - - /// Used to get the bounds of the render object when it is time to update - /// clients about visibility. - /// - /// A null value means bounds are not available. - Rect? get bounds; - - Matrix4? _lastPaintTransform; - Rect? _lastPaintClipBounds; - - @override - void paint(PaintingContext context, Offset offset) { - if (onVisibilityChanged != null) { - _lastPaintClipBounds = context.canvas.getLocalClipBounds(); - _lastPaintTransform = - Matrix4.fromFloat64List(context.canvas.getTransform()) - ..translate(offset.dx, offset.dy); - - _compositionCallbackCanceller?.call(); - _compositionCallbackCanceller = - context.addCompositionCallback((Layer layer) { - assert(!debugDisposed!); - final container = layer is ContainerLayer ? layer : layer.parent; - _scheduleUpdate(container); - }); - } - super.paint(context, offset); - } - - bool _disposed = false; - - @override - void dispose() { - _compositionCallbackCanceller?.call(); - _compositionCallbackCanceller = null; - _disposed = true; - super.dispose(); - } -} - -class RenderVisibilityDetector extends RenderProxyBox - with RenderVisibilityDetectorBase { - RenderVisibilityDetector({ - RenderBox? child, - required this.key, - required VisibilityChangedCallback? onVisibilityChanged, - }) : super(child) { - _onVisibilityChanged = onVisibilityChanged; - } - - @override - final Key key; - - @override - Rect? get bounds => hasSize ? semanticBounds : null; -} diff --git a/packages/instabug_private_views/lib/src/visibility_detector/sliver_visibility_detector.dart b/packages/instabug_private_views/lib/src/visibility_detector/sliver_visibility_detector.dart deleted file mode 100644 index facdd68d1..000000000 --- a/packages/instabug_private_views/lib/src/visibility_detector/sliver_visibility_detector.dart +++ /dev/null @@ -1,85 +0,0 @@ -import 'dart:math' as math; - -import 'package:flutter/rendering.dart'; -import 'package:flutter/widgets.dart'; - -import 'package:instabug_private_views/src/visibility_detector/base_render_visibility_detector.dart'; - -class RenderSliverVisibilityDetector extends RenderProxySliver - with RenderVisibilityDetectorBase { - RenderSliverVisibilityDetector({ - RenderSliver? sliver, - required this.key, - required VisibilityChangedCallback? onVisibilityChanged, - }) : super(sliver) { - init(visibilityChangedCallback: onVisibilityChanged); - } - - @override - final Key key; - - @override - Rect? get bounds { - if (geometry == null) { - return null; - } - - Size widgetSize; - Offset widgetOffset; - switch (applyGrowthDirectionToAxisDirection( - constraints.axisDirection, - constraints.growthDirection, - )) { - case AxisDirection.down: - widgetOffset = Offset(0, -constraints.scrollOffset); - widgetSize = Size(constraints.crossAxisExtent, geometry!.scrollExtent); - break; - case AxisDirection.up: - final startOffset = geometry!.paintExtent + - constraints.scrollOffset - - geometry!.scrollExtent; - widgetOffset = Offset(0, math.min(startOffset, 0)); - widgetSize = Size(constraints.crossAxisExtent, geometry!.scrollExtent); - break; - case AxisDirection.right: - widgetOffset = Offset(-constraints.scrollOffset, 0); - widgetSize = Size(geometry!.scrollExtent, constraints.crossAxisExtent); - break; - case AxisDirection.left: - final startOffset = geometry!.paintExtent + - constraints.scrollOffset - - geometry!.scrollExtent; - widgetOffset = Offset(math.min(startOffset, 0), 0); - widgetSize = Size(geometry!.scrollExtent, constraints.crossAxisExtent); - break; - } - return widgetOffset & widgetSize; - } -} - -class SliverVisibilityDetector extends SingleChildRenderObjectWidget { - const SliverVisibilityDetector({ - required Key key, - required Widget sliver, - required this.onVisibilityChanged, - }) : super(key: key, child: sliver); - - final VisibilityChangedCallback? onVisibilityChanged; - - @override - RenderSliverVisibilityDetector createRenderObject(BuildContext context) { - return RenderSliverVisibilityDetector( - key: key!, - onVisibilityChanged: onVisibilityChanged, - ); - } - - @override - void updateRenderObject( - BuildContext context, - RenderSliverVisibilityDetector renderObject, - ) { - assert(renderObject.key == key); - renderObject.onVisibilityChanged = onVisibilityChanged; - } -} diff --git a/packages/instabug_private_views/lib/src/visibility_detector/visibility_detector.dart b/packages/instabug_private_views/lib/src/visibility_detector/visibility_detector.dart deleted file mode 100644 index 16b83b025..000000000 --- a/packages/instabug_private_views/lib/src/visibility_detector/visibility_detector.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/rendering.dart'; -import 'package:flutter/widgets.dart'; - -import 'package:instabug_private_views/src/visibility_detector/base_render_visibility_detector.dart'; - -class RenderVisibilityDetector extends RenderProxyBox - with RenderVisibilityDetectorBase { - RenderVisibilityDetector({ - RenderBox? child, - required this.key, - required VisibilityChangedCallback? onVisibilityChanged, - }) : super(child) { - init(visibilityChangedCallback: onVisibilityChanged); - } - - @override - final Key key; - - @override - Rect? get bounds => hasSize ? semanticBounds : null; -} - -class VisibilityDetector extends SingleChildRenderObjectWidget { - const VisibilityDetector({ - required Key key, - required Widget child, - required this.onVisibilityChanged, - }) : super(key: key, child: child); - - /// The callback to invoke when this widget's visibility changes. - final VisibilityChangedCallback? onVisibilityChanged; - - @override - RenderVisibilityDetector createRenderObject(BuildContext context) { - return RenderVisibilityDetector( - key: key!, - onVisibilityChanged: onVisibilityChanged, - ); - } - - @override - void updateRenderObject( - BuildContext context, - RenderVisibilityDetector renderObject, - ) { - assert(renderObject.key == key); - renderObject.onVisibilityChanged = onVisibilityChanged; - } -} diff --git a/packages/instabug_private_views/lib/src/visibility_detector/visibillity_utils.dart b/packages/instabug_private_views/lib/src/visibility_detector/visibillity_utils.dart deleted file mode 100644 index 855f625cf..000000000 --- a/packages/instabug_private_views/lib/src/visibility_detector/visibillity_utils.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:math'; - -import 'package:flutter/widgets.dart'; - -bool isWidgetVisible( - Rect widgetBounds, - Rect clipRect, -) { - final overlaps = widgetBounds.overlaps(clipRect); - // Compute the intersection in the widget's local coordinates. - final visibleBounds = overlaps - ? widgetBounds.intersect(clipRect).shift(-widgetBounds.topLeft) - : Rect.zero; - final visibleArea = _area(visibleBounds.size); - final maxVisibleArea = _area(widgetBounds.size); - - if (_floatNear(maxVisibleArea, 0)) { - return false; - } - - final visibleFraction = visibleArea / maxVisibleArea; - - if (_floatNear(visibleFraction, 0)) { - return false; - } else if (_floatNear(visibleFraction, 1)) { - return true; - } - - return true; -} - -/// Computes the area of a rectangle of the specified dimensions. -double _area(Size size) { - assert(size.width >= 0); - assert(size.height >= 0); - return size.width * size.height; -} - -/// Returns whether two floating-point values are approximately equal. -bool _floatNear(double f1, double f2) { - final absDiff = (f1 - f2).abs(); - return absDiff <= _kDefaultTolerance || - (absDiff / max(f1.abs(), f2.abs()) <= _kDefaultTolerance); -} - -const _kDefaultTolerance = 0.01; diff --git a/packages/instabug_private_views/pubspec.lock b/packages/instabug_private_views/pubspec.lock deleted file mode 100644 index 76aedff0e..000000000 --- a/packages/instabug_private_views/pubspec.lock +++ /dev/null @@ -1,716 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a - url: "https://pub.dev" - source: hosted - version: "61.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 - url: "https://pub.dev" - source: hosted - version: "5.13.0" - args: - dependency: transitive - description: - name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 - url: "https://pub.dev" - source: hosted - version: "2.6.0" - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - build: - dependency: transitive - description: - name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - build_config: - dependency: transitive - description: - name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 - url: "https://pub.dev" - source: hosted - version: "1.1.1" - build_daemon: - dependency: transitive - description: - name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - build_runner: - dependency: "direct dev" - description: - name: build_runner - sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" - url: "https://pub.dev" - source: hosted - version: "2.4.13" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 - url: "https://pub.dev" - source: hosted - version: "7.3.2" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb - url: "https://pub.dev" - source: hosted - version: "8.9.2" - characters: - dependency: transitive - description: - name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff - url: "https://pub.dev" - source: hosted - version: "2.0.3" - cli_util: - dependency: transitive - description: - name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.dev" - source: hosted - version: "0.4.2" - clock: - dependency: transitive - description: - name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" - source: hosted - version: "1.1.1" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" - url: "https://pub.dev" - source: hosted - version: "4.10.1" - collection: - dependency: transitive - description: - name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a - url: "https://pub.dev" - source: hosted - version: "1.18.0" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - coverage: - dependency: transitive - description: - name: coverage - sha256: "88b0fddbe4c92910fefc09cc0248f5e7f0cd23e450ded4c28f16ab8ee8f83268" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - csslib: - dependency: transitive - description: - name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - fake_async: - dependency: "direct dev" - description: - name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - graphs: - dependency: transitive - description: - name: graphs - sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - html: - dependency: transitive - description: - name: html - sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" - url: "https://pub.dev" - source: hosted - version: "0.15.5" - http: - dependency: transitive - description: - name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 - url: "https://pub.dev" - source: hosted - version: "1.2.2" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - instabug_flutter: - dependency: "direct main" - description: - path: "../instabug_flutter" - relative: true - source: path - version: "14.0.0" - io: - dependency: transitive - description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - js: - dependency: transitive - description: - name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf - url: "https://pub.dev" - source: hosted - version: "0.7.1" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" - url: "https://pub.dev" - source: hosted - version: "10.0.5" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" - url: "https://pub.dev" - source: hosted - version: "3.0.5" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - lint: - dependency: "direct dev" - description: - name: lint - sha256: "4a539aa34ec5721a2c7574ae2ca0336738ea4adc2a34887d54b7596310b33c85" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - lints: - dependency: transitive - description: - name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 - url: "https://pub.dev" - source: hosted - version: "3.0.0" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - markdown: - dependency: transitive - description: - name: markdown - sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 - url: "https://pub.dev" - source: hosted - version: "7.2.2" - matcher: - dependency: transitive - description: - name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb - url: "https://pub.dev" - source: hosted - version: "0.12.16+1" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 - url: "https://pub.dev" - source: hosted - version: "1.15.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - mockito: - dependency: "direct dev" - description: - name: mockito - sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917" - url: "https://pub.dev" - source: hosted - version: "5.4.4" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - pana: - dependency: "direct dev" - description: - name: pana - sha256: "3fc3fe8e7a9fd4827fa4d625a423eec95d305b2bc3538a3adf7fd6c49217af97" - url: "https://pub.dev" - source: hosted - version: "0.21.45" - path: - dependency: transitive - description: - name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" - url: "https://pub.dev" - source: hosted - version: "1.9.0" - pigeon: - dependency: "direct dev" - description: - name: pigeon - sha256: "6eb9702acc25d5ec340bd1b751e511e2982189dfc40c12e2d69db6e05bab03be" - url: "https://pub.dev" - source: hosted - version: "10.1.5" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - retry: - dependency: transitive - description: - name: retry - sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc" - url: "https://pub.dev" - source: hosted - version: "3.1.2" - safe_url_check: - dependency: transitive - description: - name: safe_url_check - sha256: "49a3e060a7869cbafc8f4845ca1ecbbaaa53179980a32f4fdfeab1607e90f41d" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - shelf: - dependency: transitive - description: - name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 - url: "https://pub.dev" - source: hosted - version: "1.4.1" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 - url: "https://pub.dev" - source: hosted - version: "1.1.3" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" - url: "https://pub.dev" - source: hosted - version: "1.5.0" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b - url: "https://pub.dev" - source: hosted - version: "2.1.2" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" - url: "https://pub.dev" - source: hosted - version: "0.10.12" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" - url: "https://pub.dev" - source: hosted - version: "1.11.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 - url: "https://pub.dev" - source: hosted - version: "2.1.2" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - tar: - dependency: transitive - description: - name: tar - sha256: "22f67e2d77b51050436620b2a5de521c58ca6f0b75af1d9ab3c8cae2eae58fcd" - url: "https://pub.dev" - source: hosted - version: "1.0.5" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test: - dependency: transitive - description: - name: test - sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" - url: "https://pub.dev" - source: hosted - version: "1.25.7" - test_api: - dependency: transitive - description: - name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" - url: "https://pub.dev" - source: hosted - version: "0.7.2" - test_core: - dependency: transitive - description: - name: test_core - sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" - url: "https://pub.dev" - source: hosted - version: "0.6.4" - timing: - dependency: transitive - description: - name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" - url: "https://pub.dev" - source: hosted - version: "14.2.5" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" - url: "https://pub.dev" - source: hosted - version: "0.1.6" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" - url: "https://pub.dev" - source: hosted - version: "3.1.2" -sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/instabug_private_views/pubspec.yaml b/packages/instabug_private_views/pubspec.yaml deleted file mode 100644 index 60288d069..000000000 --- a/packages/instabug_private_views/pubspec.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: instabug_private_views -description: "An extension for the Instabug Flutter SDK that enables support for masking private views during screen capturing." -version: 1.0.1 -homepage: https://www.instabug.com -repository: https://github.com/Instabug/Instabug-Flutter -documentation: https://docs.instabug.com/docs/flutter-overview - -environment: - sdk: ">=2.14.0 <4.0.0" - flutter: '>=3.3.0' - -dependencies: - flutter: - sdk: flutter - instabug_flutter: - -dev_dependencies: - build_runner: ^2.0.3 - fake_async: '>=1.2.0 <1.4.0' - flutter_test: - sdk: flutter - lint: ^1.0.0 - # mockito v5.2.0 is needed for running Flutter 2 tests on CI - mockito: '>=5.2.0 <5.5.0' - pana: ^0.21.0 - # pigeon v3.0.0 is needed for running Flutter 2 tests on CI - pigeon: '>=3.0.0 <=10.1.5' - -flutter: - plugin: - platforms: - android: - package: com.instabug.instabug_private_views - pluginClass: InstabugPrivateViewsPlugin - ios: - pluginClass: InstabugPrivateViewsPlugin \ No newline at end of file diff --git a/packages/instabug_private_views/pubspec_overrides.yaml b/packages/instabug_private_views/pubspec_overrides.yaml deleted file mode 100644 index 1f0beaf62..000000000 --- a/packages/instabug_private_views/pubspec_overrides.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# melos_managed_dependency_overrides: instabug_flutter -dependency_overrides: - instabug_flutter: - path: ../instabug_flutter diff --git a/packages/instabug_private_views/release.sh b/packages/instabug_private_views/release.sh deleted file mode 100755 index b30831736..000000000 --- a/packages/instabug_private_views/release.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -VERSION=$(egrep -o "version: ([0-9]-*.*)+[0-9]" pubspec.yaml | cut -d ":" -f 2) -if [ ! "${VERSION}" ] || [ -z "${VERSION}" ];then - echo "Instabug: err: Version Number not found." - exit 1 -else - mkdir -p $HOME/.config/dart - cat < $HOME/.config/dart/pub-credentials.json - ${PUB_CREDENTIALS} - -EOF - flutter packages pub publish -f -fi \ No newline at end of file diff --git a/packages/instabug_private_views/scripts/pigeon.sh b/packages/instabug_private_views/scripts/pigeon.sh deleted file mode 100644 index 5c7fb79b6..000000000 --- a/packages/instabug_private_views/scripts/pigeon.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -DIR_DART="lib/src/generated" -DIR_IOS="ios/Classes/Generated" -DIR_ANDROID="android/src/main/java/com/instabug/instabug_private_views/generated" -PKG_ANDROID="com.instabug.instabug_private_views.generated" - -mkdir -p $DIR_DART -mkdir -p $DIR_IOS -mkdir -p $DIR_ANDROID - -generate_pigeon() { - name_file=$1 - name_snake=$(basename $name_file .api.dart) - name_pascal=$(echo "$name_snake" | perl -pe 's/(^|_)./uc($&)/ge;s/_//g') - - dart run pigeon \ - --input "pigeons/$name_snake.api.dart" \ - --dart_out "$DIR_DART/$name_snake.api.g.dart" \ - --objc_header_out "$DIR_IOS/${name_pascal}Pigeon.h" \ - --objc_source_out "$DIR_IOS/${name_pascal}Pigeon.m" \ - --java_out "$DIR_ANDROID/${name_pascal}Pigeon.java" \ - --java_package $PKG_ANDROID || exit 1; - - echo "Generated $name_snake pigeon" - - # Generated files are not formatted by default, - # this affects pacakge score. - dart format "$DIR_DART/$name_snake.api.g.dart" -} - -for file in pigeons/** -do - generate_pigeon $file -done diff --git a/packages/instabug_private_views/test/instabug_private_view_test.dart b/packages/instabug_private_views/test/instabug_private_view_test.dart deleted file mode 100644 index 7f55c8c61..000000000 --- a/packages/instabug_private_views/test/instabug_private_view_test.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:instabug_private_views/src/instabug_private_view.dart'; -import 'package:instabug_private_views/src/private_views_manager.dart'; -import 'package:instabug_private_views/src/visibility_detector/base_render_visibility_detector.dart'; -import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; -import 'instabug_private_view_test.mocks.dart'; - -@GenerateMocks([PrivateViewsManager]) -void main() { - testWidgets('should mask the view when it is visible', (tester) async { - await tester.runAsync(() async { - final mock = MockPrivateViewsManager(); - RenderVisibilityDetectorBase.updateInterval = Duration.zero; - PrivateViewsManager.setInstance(mock); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: InstabugPrivateView( - child: const Text('Text invisible'), - ), - ), - ), - ); - - verify( - mock.mask(any), - ).called( - 2, - ); // one for initState and the other for visibility is shown is true - }); - }); - - testWidgets("should un-mask the view when it is invisible", (tester) async { - await tester.runAsync(() async { - final mock = MockPrivateViewsManager(); - RenderVisibilityDetectorBase.updateInterval = Duration.zero; - PrivateViewsManager.setInstance(mock); - var isVisible = true; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return ListView( - children: [ - Visibility( - visible: isVisible, - maintainState: true, - child: InstabugPrivateView( - child: const SizedBox( - width: 40, - height: 40, - ), - ), - ), - ElevatedButton( - onPressed: () { - setState(() { - isVisible = false; // make the widget invisible - }); - }, - child: const Text('Make invisible'), - ), - ], - ); - }, - ), - ), - ), - ); - await tester.tap(find.text('Make invisible')); - await tester.pump(const Duration(seconds: 1)); - verify( - mock.unMask(any), - ).called( - 1, - ); - }); - }); -} diff --git a/packages/instabug_private_views/test/instabug_sliver_private_view_test.dart b/packages/instabug_private_views/test/instabug_sliver_private_view_test.dart deleted file mode 100644 index 4e8bdab2b..000000000 --- a/packages/instabug_private_views/test/instabug_sliver_private_view_test.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:instabug_private_views/src/instabug_sliver_private_view.dart'; -import 'package:instabug_private_views/src/private_views_manager.dart'; -import 'package:instabug_private_views/src/visibility_detector/base_render_visibility_detector.dart'; -import 'package:mockito/mockito.dart'; - -import 'instabug_private_view_test.mocks.dart'; - -void main() { - testWidgets('should mask sliver view when it is visible', (tester) async { - await tester.runAsync(() async { - final mock = MockPrivateViewsManager(); - RenderVisibilityDetectorBase.updateInterval = Duration.zero; - PrivateViewsManager.setInstance(mock); - - await tester.pumpWidget( - MaterialApp( - home: CustomScrollView( - slivers: [ - InstabugSliverPrivateView( - sliver: const SliverToBoxAdapter( - child: SizedBox( - width: 20, - height: 40, - ), - ), - ), - ], - ), - ), - ); - - verify( - mock.mask(any), - ).called( - 2, - ); // one for initState and the other for visibility is shown is true - }); - }); - - testWidgets('should un-mask the sliver view when it is invisible', - (tester) async { - await tester.runAsync(() async { - final mock = MockPrivateViewsManager(); - RenderVisibilityDetectorBase.updateInterval = Duration.zero; - PrivateViewsManager.setInstance(mock); - var isVisible = true; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: SafeArea( - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return CustomScrollView( - slivers: [ - SliverToBoxAdapter( - child: ElevatedButton( - onPressed: () { - setState(() { - isVisible = false; // make the widget invisible - }); - }, - child: const Text('Make invisible'), - ), - ), - SliverVisibility( - visible: isVisible, - maintainState: true, - sliver: InstabugSliverPrivateView( - sliver: const SliverToBoxAdapter( - child: SizedBox( - width: 40, - height: 40, - ), - ), - ), - ), - ], - ); - }, - ), - ), - ), - ), - ); - - await tester.tap(find.text('Make invisible')); - await tester.pump(const Duration(milliseconds: 300)); - - verify( - mock.unMask(any), - ).called( - 1, - ); - }); - }); -} From 7b7f9e3f83797072aff061b5190e528e1ed2bb0a Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Thu, 27 Feb 2025 20:39:18 +0200 Subject: [PATCH 02/16] fix: e2e test --- .../lib/instabug_dio_interceptor.dart | 3 +- .../instabug_flutter/android/build.gradle | 2 +- .../BoundryScreenshotCaptorTest.java | 77 +++++++ .../PixelCopyScreenshotCaptorTest.java | 91 +++++++++ .../private_views/PrivateViewManagerTest.java | 146 +++++++++++++ .../ios/InstabugTests/PrivateViewApiTests.m | 191 ++++++++++++++++++ .../InstabugTests/PrivateViewHostApiTests.m | 57 ++++++ .../ios/Runner.xcodeproj/project.pbxproj | 8 + .../instabug_flutter/example/lib/main.dart | 6 +- .../example/lib/src/screens/my_home_page.dart | 2 +- .../lib/src/screens/private_view_page.dart | 18 +- .../ios/Classes/Modules/PrivateViewApi.m | 2 - .../lib/src/modules/instabug.dart | 4 +- .../private_views/instabug_private_view.dart | 3 +- .../private_views/private_views_manager.dart | 4 +- .../utils/user_steps/instabug_user_steps.dart | 1 - .../src/utils/user_steps/widget_utils.dart | 3 +- .../pigeons/instabug.api.dart | 2 +- .../pigeons/instabug_private_view.api.dart | 1 - .../instabug_flutter/test/instabug_test.dart | 4 +- .../instabug_navigator_observer_test.dart | 29 +-- .../lib/instabug_http_client.dart | 11 +- .../lib/instabug_http_logger.dart | 7 +- .../test/instabug_http_client_test.dart | 32 +-- 24 files changed, 645 insertions(+), 59 deletions(-) create mode 100644 packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/BoundryScreenshotCaptorTest.java create mode 100644 packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/PixelCopyScreenshotCaptorTest.java create mode 100644 packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/PrivateViewManagerTest.java create mode 100644 packages/instabug_flutter/example/ios/InstabugTests/PrivateViewApiTests.m create mode 100644 packages/instabug_flutter/example/ios/InstabugTests/PrivateViewHostApiTests.m diff --git a/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart b/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart index 2210e9986..72b8af3ae 100644 --- a/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart +++ b/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart @@ -84,7 +84,8 @@ class InstabugDioInterceptor extends Interceptor { var responseBodySize = 0; if (responseHeaders.containsKey('content-length')) { // ignore: avoid_dynamic_calls - responseBodySize = int.parse((responseHeaders['content-length'][0]) ?? '0'); + responseBodySize = + int.parse((responseHeaders['content-length'][0]) ?? '0'); } else if (response.data != null) { responseBodySize = response.data.toString().length; } diff --git a/packages/instabug_flutter/android/build.gradle b/packages/instabug_flutter/android/build.gradle index dd0ff1fc0..a081feeee 100644 --- a/packages/instabug_flutter/android/build.gradle +++ b/packages/instabug_flutter/android/build.gradle @@ -56,7 +56,7 @@ dependencies { testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-inline:3.12.1" testImplementation "io.mockk:mockk:1.13.13" - + testImplementation "org.robolectric:robolectric:4.12.2" } // add upload_symbols task diff --git a/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/BoundryScreenshotCaptorTest.java b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/BoundryScreenshotCaptorTest.java new file mode 100644 index 000000000..a555345e0 --- /dev/null +++ b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/BoundryScreenshotCaptorTest.java @@ -0,0 +1,77 @@ +package com.instabug.flutter.util.private_views; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.os.Looper; + +import com.instabug.flutter.model.ScreenshotResult; +import com.instabug.flutter.modules.capturing.BoundryCaptureManager; +import com.instabug.flutter.modules.capturing.CaptureManager; +import com.instabug.flutter.modules.capturing.ScreenshotResultCallback; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatcher; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import io.flutter.embedding.engine.renderer.FlutterRenderer; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = {28}, manifest = Config.NONE) +public class BoundryScreenshotCaptorTest { + private Activity activityMock; + private Bitmap bitmap; + private CaptureManager captureManager; + + @Before + public void setUp() { + FlutterRenderer rendererMock = mock(FlutterRenderer.class); + activityMock = spy(Robolectric.buildActivity(Activity.class).setup().create().start().resume().get()); + bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); + when(rendererMock.getBitmap()).thenReturn(bitmap); + captureManager = new BoundryCaptureManager(rendererMock); + } + + @Test + public void testCaptureGivenEmptyActivity() { + ScreenshotResultCallback mockCallback = mock(ScreenshotResultCallback.class); + + captureManager.capture(null, mockCallback); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mockCallback).onError(); + verify(mockCallback, never()).onScreenshotResult(any(ScreenshotResult.class)); + + } + + @Test + public void testCapture() { + ScreenshotResultCallback mockCallback = mock(ScreenshotResultCallback.class); + captureManager.capture(activityMock, mockCallback); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mockCallback, never()).onError(); + verify(mockCallback).onScreenshotResult(argThat(new ArgumentMatcher() { + @Override + public boolean matches(ScreenshotResult argument) { + return (Math.abs(activityMock.getResources().getDisplayMetrics().density - argument.getPixelRatio()) < 0.01)&& + bitmap == argument.getScreenshot(); + + } + })); + } + + +} diff --git a/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/PixelCopyScreenshotCaptorTest.java b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/PixelCopyScreenshotCaptorTest.java new file mode 100644 index 000000000..868712312 --- /dev/null +++ b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/PixelCopyScreenshotCaptorTest.java @@ -0,0 +1,91 @@ +package com.instabug.flutter.util.private_views; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.os.Looper; +import android.view.SurfaceView; + +import com.instabug.flutter.model.ScreenshotResult; +import com.instabug.flutter.modules.capturing.CaptureManager; +import com.instabug.flutter.modules.capturing.PixelCopyCaptureManager; +import com.instabug.flutter.modules.capturing.ScreenshotResultCallback; +import com.instabug.library.util.memory.MemoryUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockedStatic; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.android.FlutterView; +import io.flutter.embedding.engine.renderer.FlutterRenderer; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = {28}, manifest = Config.NONE) +public class PixelCopyScreenshotCaptorTest { + private Activity activityMock; + private Bitmap bitmap; + private CaptureManager captureManager; + + @Before + public void setUp() { + FlutterRenderer rendererMock = mock(FlutterRenderer.class); + activityMock = spy(Robolectric.buildActivity(Activity.class).setup().create().start().resume().get()); + bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); + when(rendererMock.getBitmap()).thenReturn(bitmap); + captureManager = new PixelCopyCaptureManager(); + } + + @Test + public void testCaptureWithPixelCopyGivenEmptyView() { + + ScreenshotResultCallback mockScreenshotResultCallback = mock(ScreenshotResultCallback.class); + when(activityMock.findViewById(FlutterActivity.FLUTTER_VIEW_ID)).thenReturn(null); + captureManager.capture(activityMock,mockScreenshotResultCallback); + + verify(mockScreenshotResultCallback).onError(); + } + + @Test + public void testCaptureWithPixelCopy() { + try (MockedStatic mockedStatic = mockStatic(MemoryUtils.class)) { + mockedStatic.when(() -> MemoryUtils.getFreeMemory(any())).thenReturn(Long.MAX_VALUE); + + mockFlutterViewInPixelCopy(); + + ScreenshotResultCallback mockScreenshotResultCallback = mock(ScreenshotResultCallback.class); + + + captureManager.capture(activityMock, mockScreenshotResultCallback); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mockScreenshotResultCallback, timeout(1000)).onScreenshotResult(any(ScreenshotResult.class)); // PixelCopy success + + } + } + + + private void mockFlutterViewInPixelCopy() { + + SurfaceView mockSurfaceView = mock(SurfaceView.class); + FlutterView flutterView = mock(FlutterView.class); + when(flutterView.getChildAt(0)).thenReturn(mockSurfaceView); + when(flutterView.getChildCount()).thenReturn(1); + + when(activityMock.findViewById(FlutterActivity.FLUTTER_VIEW_ID)).thenReturn(flutterView); + when(mockSurfaceView.getWidth()).thenReturn(100); + when(mockSurfaceView.getHeight()).thenReturn(100); + } +} diff --git a/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/PrivateViewManagerTest.java b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/PrivateViewManagerTest.java new file mode 100644 index 000000000..a996fb8a2 --- /dev/null +++ b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/util/private_views/PrivateViewManagerTest.java @@ -0,0 +1,146 @@ +package com.instabug.flutter.util.private_views; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.os.Build; +import android.os.Looper; +import android.view.SurfaceView; + +import com.instabug.flutter.generated.InstabugPrivateViewPigeon; +import com.instabug.flutter.model.ScreenshotResult; +import com.instabug.flutter.modules.PrivateViewManager; +import com.instabug.flutter.modules.capturing.BoundryCaptureManager; +import com.instabug.flutter.modules.capturing.CaptureManager; +import com.instabug.flutter.modules.capturing.PixelCopyCaptureManager; +import com.instabug.flutter.util.privateViews.ScreenshotCaptor; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.Arrays; +import java.util.List; + +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.android.FlutterView; +import io.flutter.embedding.engine.renderer.FlutterRenderer; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = {28}, manifest = Config.NONE) +public class PrivateViewManagerTest { + + private PrivateViewManager privateViewManager; + private InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi InstabugPrivateViewFlutterApiMock; + private Activity activityMock; + private Bitmap bitmap; + private CaptureManager pixelCopyScreenCaptor, boundryScreenCaptor; + + @Before + public void setUp() { + InstabugPrivateViewFlutterApiMock = mock(InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi.class); + FlutterRenderer rendererMock = mock(FlutterRenderer.class); + activityMock = spy(Robolectric.buildActivity(Activity.class).setup().create().start().resume().get()); + bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); + when(rendererMock.getBitmap()).thenReturn(bitmap); + pixelCopyScreenCaptor = spy(new PixelCopyCaptureManager()); + boundryScreenCaptor = spy(new BoundryCaptureManager(rendererMock)); + privateViewManager = spy(new PrivateViewManager(InstabugPrivateViewFlutterApiMock, pixelCopyScreenCaptor, boundryScreenCaptor)); + privateViewManager.setActivity(activityMock); + + } + + + @Test + public void testMaskGivenEmptyActivity() { + com.instabug.flutter.util.privateViews.ScreenshotCaptor.CapturingCallback capturingCallbackMock = mock(ScreenshotCaptor.CapturingCallback.class); + privateViewManager.setActivity(null); + privateViewManager.mask(capturingCallbackMock); + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Throwable.class); + verify(capturingCallbackMock).onCapturingFailure(argumentCaptor.capture()); + assertEquals( PrivateViewManager.EXCEPTION_MESSAGE, argumentCaptor.getValue().getMessage()); + } + + @Test + public void testMask() throws InterruptedException { + com.instabug.flutter.util.privateViews.ScreenshotCaptor.CapturingCallback capturingCallbackMock = mock(com.instabug.flutter.util.privateViews.ScreenshotCaptor.CapturingCallback.class); + doAnswer(invocation -> { + InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi.Reply> callback = invocation.getArgument(0); // Get the callback + callback.reply(Arrays.asList(10.0, 20.0, 100.0, 200.0)); // Trigger the success callback + return null; + }).when(InstabugPrivateViewFlutterApiMock).getPrivateViews(any(InstabugPrivateViewPigeon.InstabugPrivateViewFlutterApi.Reply.class)); // Mock the method call + + + // Trigger the mask operation + privateViewManager.mask(capturingCallbackMock); + // Mock that latch.await() has been called + shadowOf(Looper.getMainLooper()).idle(); + + // Simulate a successful bitmap capture + verify(capturingCallbackMock, timeout(1000)).onCapturingSuccess(bitmap); + } + + + private void mockFlutterViewInPixelCopy() { + SurfaceView mockSurfaceView = mock(SurfaceView.class); + FlutterView flutterView = mock(FlutterView.class); + when(flutterView.getChildAt(0)).thenReturn(mockSurfaceView); + when(flutterView.getChildCount()).thenReturn(1); + + when(activityMock.findViewById(FlutterActivity.FLUTTER_VIEW_ID)).thenReturn(flutterView); + when(mockSurfaceView.getWidth()).thenReturn(100); + when(mockSurfaceView.getHeight()).thenReturn(100); + } + + + @Test + public void testMaskPrivateViews() { + ScreenshotResult mockResult = mock(ScreenshotResult.class); + when(mockResult.getScreenshot()).thenReturn(Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888)); + when(mockResult.getPixelRatio()).thenReturn(2.0f); + + List privateViews = Arrays.asList(10.0, 20.0, 100.0, 200.0); + + privateViewManager.maskPrivateViews(mockResult, privateViews); + + assertNotNull(mockResult.getScreenshot()); + } + + @Test + @Config(sdk = {Build.VERSION_CODES.M}) + public void testMaskShouldGetScreenshotWhenAPIVersionLessThan28() { + ScreenshotCaptor.CapturingCallback capturingCallbackMock = mock(ScreenshotCaptor.CapturingCallback.class); + privateViewManager.mask(capturingCallbackMock); + shadowOf(Looper.getMainLooper()).idle(); + + verify(boundryScreenCaptor).capture(any(), any()); + + } + + @Test + public void testMaskShouldCallPixelCopyWhenAPIVersionMoreThan28() { + com.instabug.flutter.util.privateViews.ScreenshotCaptor.CapturingCallback capturingCallbackMock = mock(com.instabug.flutter.util.privateViews.ScreenshotCaptor.CapturingCallback.class); + mockFlutterViewInPixelCopy(); + privateViewManager.mask(capturingCallbackMock); + shadowOf(Looper.getMainLooper()).idle(); + verify(boundryScreenCaptor, never()).capture(any(), any()); + verify(pixelCopyScreenCaptor).capture(any(), any()); + + + } +} \ No newline at end of file diff --git a/packages/instabug_flutter/example/ios/InstabugTests/PrivateViewApiTests.m b/packages/instabug_flutter/example/ios/InstabugTests/PrivateViewApiTests.m new file mode 100644 index 000000000..ac3f17efc --- /dev/null +++ b/packages/instabug_flutter/example/ios/InstabugTests/PrivateViewApiTests.m @@ -0,0 +1,191 @@ +#import +#import +#import +#import +#import "FlutterPluginRegistrar+FlutterEngine.h" + + +@interface MockFlutterPluginRegistrar : NSObject +@end + +@implementation MockFlutterPluginRegistrar + +@end + + +@interface PrivateViewApiTests : XCTestCase +@property (nonatomic, strong) PrivateViewApi *api; +@property (nonatomic, strong) id mockFlutterApi; +@property (nonatomic, strong) id mockRegistrar; +@property (nonatomic, strong) id mockFlutterViewController; +@property (nonatomic, strong) id mockEngine; + +@end + +@implementation PrivateViewApiTests + +#pragma mark - Setup / Teardown + +- (void)setUp { + [super setUp]; + + + self.mockFlutterApi = OCMClassMock([InstabugPrivateViewFlutterApi class]); + + + MockFlutterPluginRegistrar *mockRegistrar = [[MockFlutterPluginRegistrar alloc] init]; + + self.mockRegistrar = OCMPartialMock(mockRegistrar); + + self.mockEngine = OCMClassMock([FlutterEngine class]); + OCMStub([self.mockRegistrar flutterEngine]).andReturn(self.mockEngine); + + self.mockFlutterViewController = OCMClassMock([UIViewController class]); + + OCMStub([self.mockEngine viewController]).andReturn(_mockFlutterViewController); + + self.api = OCMPartialMock([[PrivateViewApi alloc] initWithFlutterApi:self.mockFlutterApi registrar: self.mockRegistrar]); +} + +- (void)tearDown { + [self.mockFlutterApi stopMocking]; + [self.mockRegistrar stopMocking]; + [self.mockFlutterViewController stopMocking]; + [self.mockEngine stopMocking]; + + self.api = nil; + + [super tearDown]; +} + +#pragma mark - Tests + +- (void)testMask_Success { + XCTestExpectation *expectation = [self expectationWithDescription:@"Mask method success"]; + + CGSize imageSize = CGSizeMake(100, 100); // 100x100 pixels + + // Step 2: Create the image using UIGraphicsImageRenderer + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageSize]; + + UIImage *screenshot = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) { + // Draw a red rectangle as an example + [[UIColor redColor] setFill]; + CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height); + UIRectFill(rect); + }]; + + NSArray *rectangles = @[@10, @20, @30, @40]; + UIView *mockView = [[UIView alloc] initWithFrame:CGRectMake(10, 20, 30, 40)]; + + OCMStub([self.mockFlutterApi getPrivateViewsWithCompletion:([OCMArg invokeBlockWithArgs:rectangles, [NSNull null], nil])]); + + + + OCMStub([self.mockFlutterViewController view]).andReturn(mockView); + + + [self.api mask:screenshot completion:^(UIImage *result) { + XCTAssertNotNil(result, @"Masked image should be returned."); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + + +- (void)testGetFlutterViewOrigin_ValidView { + UIView *mockView = [[UIView alloc] initWithFrame:CGRectMake(10, 20, 100, 100)]; + + OCMStub([self.mockFlutterViewController view]).andReturn(mockView); + + UIWindow* testWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + [testWindow addSubview:mockView]; + + CGPoint origin = [self.api getFlutterViewOrigin]; + + XCTAssertEqual(origin.x, 10); + XCTAssertEqual(origin.y, 20); +} + +- (void)testGetFlutterViewOrigin_NilView { + + OCMStub([self.mockFlutterViewController view]).andReturn(nil); +// + CGPoint origin = [self.api getFlutterViewOrigin]; + + XCTAssertEqual(origin.x, 0); + XCTAssertEqual(origin.y, 0); +} + +- (void)testDrawMaskedImage { + CGSize size = CGSizeMake(100, 100); + UIGraphicsBeginImageContext(size); + UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + NSArray *privateViews = @[ + [NSValue valueWithCGRect:CGRectMake(10, 10, 20, 20)], + [NSValue valueWithCGRect:CGRectMake(30, 30, 10, 10)] + ]; + + UIImage *result = [self.api drawMaskedImage:screenshot withPrivateViews:privateViews]; + + XCTAssertNotNil(result); + XCTAssertEqual(result.size.width, 100); + XCTAssertEqual(result.size.height, 100); +} + +- (void)testConvertToRectangles_ValidInput { + NSArray *rectangles = @[@10, @20, @30, @40]; + UIView *mockView = [[UIView alloc] initWithFrame:CGRectMake(5, 5, 100, 100)]; + OCMStub([self.mockFlutterViewController view]).andReturn(mockView); + + + NSArray *converted = [self.api convertToRectangles:rectangles]; + + XCTAssertEqual(converted.count, 1); + CGRect rect = [converted[0] CGRectValue]; + XCTAssertTrue(CGRectEqualToRect(rect, CGRectMake(10, 20, 21, 21))); +} + +- (void)testConcurrentMaskCalls { + XCTestExpectation *expectation = [self expectationWithDescription:@"Handle concurrent calls"]; + + CGSize imageSize = CGSizeMake(100, 100); // 100x100 pixels + + // Step 2: Create the image using UIGraphicsImageRenderer + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageSize]; + + UIImage *screenshot = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) { + // Draw a red rectangle as an example + [[UIColor redColor] setFill]; + CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height); + UIRectFill(rect); + }]; + + NSArray *rectangles = @[@10, @20, @30, @40]; + + + OCMStub([self.mockFlutterApi getPrivateViewsWithCompletion:([OCMArg invokeBlockWithArgs:rectangles, [NSNull null], nil])]); + + + dispatch_group_t group = dispatch_group_create(); + + for (int i = 0; i < 5; i++) { + dispatch_group_enter(group); + + [self.api mask:screenshot completion:^(UIImage *result) { + XCTAssertNotNil(result, @"Each call should return a valid image."); + dispatch_group_leave(group); + }]; + } + + dispatch_group_notify(group, dispatch_get_main_queue(), ^{ + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:2 handler:nil]; +} + +@end diff --git a/packages/instabug_flutter/example/ios/InstabugTests/PrivateViewHostApiTests.m b/packages/instabug_flutter/example/ios/InstabugTests/PrivateViewHostApiTests.m new file mode 100644 index 000000000..27b2599ec --- /dev/null +++ b/packages/instabug_flutter/example/ios/InstabugTests/PrivateViewHostApiTests.m @@ -0,0 +1,57 @@ +#import +#import +#import +#import "PrivateViewApi.h" +#import "InstabugApi.h" +#import "PrivateViewHostApi.h" + +@interface PrivateViewHostApiTests : XCTestCase + +@property (nonatomic, strong) PrivateViewHostApi *api; +@property (nonatomic, strong) id privateViewApiMock; + +@end + +@implementation PrivateViewHostApiTests + +- (void)setUp { + [super setUp]; + + // Set up a mock for PrivateViewApi + self.privateViewApiMock = OCMClassMock([PrivateViewApi class]); + + // Initialize the PrivateViewHostApi instance + self.api = [[PrivateViewHostApi alloc] init]; + self.api.privateViewApi = self.privateViewApiMock; +} + +- (void)tearDown { + self.api = nil; + self.privateViewApiMock = nil; + [super tearDown]; +} + +- (void)testInitWithError_setsScreenshotMaskingHandler { + // Define an expectation for the screenshot masking handler + UIImage *mockScreenshot = [[UIImage alloc] init]; + UIImage *mockMaskedImage = [[UIImage alloc] init]; + FlutterError *error = nil; + + + + OCMStub([self.privateViewApiMock mask:mockScreenshot completion:([OCMArg invokeBlockWithArgs:mockMaskedImage, nil])]); + + + // Call initWithError and set up the screenshot masking handler + [self.api initWithError:&error]; + + // Invoke the screenshot masking handler + void (^completionHandler)(UIImage * _Nullable) = ^(UIImage * _Nullable maskedImage) { + XCTAssertEqual(maskedImage, mockMaskedImage, @"The masked image should be returned by the completion handler."); + }; + [InstabugApi setScreenshotMaskingHandler:^(UIImage * _Nonnull screenshot, void (^ _Nonnull completion)(UIImage * _Nullable)) { + completionHandler(screenshot); + }]; +} + +@end diff --git a/packages/instabug_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/instabug_flutter/example/ios/Runner.xcodeproj/project.pbxproj index 89e630a84..a6306d879 100644 --- a/packages/instabug_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/instabug_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -17,6 +17,8 @@ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 9D381ECFBB01BD0E978EBDF2 /* Pods_InstabugTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71679BEC094CFF3474195C2E /* Pods_InstabugTests.framework */; }; + BE2C04382D70E1BE00C40E47 /* PrivateViewHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BE2C04372D70E1BE00C40E47 /* PrivateViewHostApiTests.m */; }; + BE2C04392D70E1BE00C40E47 /* PrivateViewApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BE2C04362D70E1BE00C40E47 /* PrivateViewApiTests.m */; }; CC080E112937B7DB0041170A /* InstabugApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC080E102937B7DB0041170A /* InstabugApiTests.m */; }; CC198C61293E1A21007077C8 /* SurveysApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC198C60293E1A21007077C8 /* SurveysApiTests.m */; }; CC359DB92937720C0067A924 /* ApmApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC359DB82937720C0067A924 /* ApmApiTests.m */; }; @@ -78,6 +80,8 @@ B03C8370EEFE061BDDDA1DA1 /* Pods-InstabugUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InstabugUITests.debug.xcconfig"; path = "Target Support Files/Pods-InstabugUITests/Pods-InstabugUITests.debug.xcconfig"; sourceTree = ""; }; BA5633844585BB93FE7BCCE7 /* Pods-InstabugTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InstabugTests.profile.xcconfig"; path = "Target Support Files/Pods-InstabugTests/Pods-InstabugTests.profile.xcconfig"; sourceTree = ""; }; BE26C80C2BD55575009FECCF /* IBGCrashReporting+CP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IBGCrashReporting+CP.h"; sourceTree = ""; }; + BE2C04362D70E1BE00C40E47 /* PrivateViewApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PrivateViewApiTests.m; sourceTree = ""; }; + BE2C04372D70E1BE00C40E47 /* PrivateViewHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PrivateViewHostApiTests.m; sourceTree = ""; }; BF9025BBD0A6FD7B193E903A /* Pods-InstabugTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InstabugTests.debug.xcconfig"; path = "Target Support Files/Pods-InstabugTests/Pods-InstabugTests.debug.xcconfig"; sourceTree = ""; }; C090017925D9A030006F3DAE /* InstabugTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InstabugTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C090017D25D9A031006F3DAE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -194,6 +198,8 @@ C090017A25D9A031006F3DAE /* InstabugTests */ = { isa = PBXGroup; children = ( + BE2C04362D70E1BE00C40E47 /* PrivateViewApiTests.m */, + BE2C04372D70E1BE00C40E47 /* PrivateViewHostApiTests.m */, CC198C60293E1A21007077C8 /* SurveysApiTests.m */, CC78720A2938D1C5008CB2A5 /* Util */, CC080E102937B7DB0041170A /* InstabugApiTests.m */, @@ -457,6 +463,8 @@ CC080E112937B7DB0041170A /* InstabugApiTests.m in Sources */, CC198C61293E1A21007077C8 /* SurveysApiTests.m in Sources */, CCADBDD8293CFED300AE5EB8 /* BugReportingApiTests.m in Sources */, + BE2C04382D70E1BE00C40E47 /* PrivateViewHostApiTests.m in Sources */, + BE2C04392D70E1BE00C40E47 /* PrivateViewApiTests.m in Sources */, CC9925D9293DFD7F001FD3EE /* RepliesApiTests.m in Sources */, 206286ED2ABD0A1F00925509 /* SessionReplayApiTests.m in Sources */, CC9925D2293DEB0B001FD3EE /* CrashReportingApiTests.m in Sources */, diff --git a/packages/instabug_flutter/example/lib/main.dart b/packages/instabug_flutter/example/lib/main.dart index fcaec264b..aee5a4676 100644 --- a/packages/instabug_flutter/example/lib/main.dart +++ b/packages/instabug_flutter/example/lib/main.dart @@ -68,7 +68,11 @@ void main() { }; runApp( - const InstabugWidget(automasking: [AutoMasking.labels,AutoMasking.textInputs,AutoMasking.media], child: MyApp()), + const InstabugWidget(automasking: [ + AutoMasking.labels, + AutoMasking.textInputs, + AutoMasking.media + ], child: MyApp()), ); }, CrashReporting.reportCrash, diff --git a/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart b/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart index 081269d83..98375b968 100644 --- a/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart +++ b/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart @@ -60,7 +60,7 @@ class _MyHomePageState extends State { } void reportScreenChange() { - Instabug.reportScreenChange(null,screenNameController.text); + Instabug.reportScreenChange(null, screenNameController.text); } void sendBugReport() { diff --git a/packages/instabug_flutter/example/lib/src/screens/private_view_page.dart b/packages/instabug_flutter/example/lib/src/screens/private_view_page.dart index 585d7cc78..a6cca918c 100644 --- a/packages/instabug_flutter/example/lib/src/screens/private_view_page.dart +++ b/packages/instabug_flutter/example/lib/src/screens/private_view_page.dart @@ -62,16 +62,16 @@ class _PrivateViewPageState extends State { } int count = 200; - final list=List.generate( + final list = List.generate( 20, - (_) => InstabugPrivateView( - child: Container( - margin: const EdgeInsets.all(2), - width: 4, - height: 4, - color: Colors.red, - ), - )); + (_) => InstabugPrivateView( + child: Container( + margin: const EdgeInsets.all(2), + width: 4, + height: 4, + color: Colors.red, + ), + )); @override Widget build(BuildContext context) { return Scaffold( diff --git a/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m index 3bebca63b..07edb9905 100644 --- a/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m +++ b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m @@ -29,8 +29,6 @@ - (void)mask:(UIImage *)screenshot __weak typeof(self) weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - - currentTimeMillis = (long long)([[NSDate date] timeIntervalSince1970] * 1000); [self.flutterApi getPrivateViewsWithCompletion:^(NSArray *rectangles, FlutterError *error) { UIImage *capturedScreenshot = [self captureScreenshot]; diff --git a/packages/instabug_flutter/lib/src/modules/instabug.dart b/packages/instabug_flutter/lib/src/modules/instabug.dart index ee862826d..dd2065ceb 100644 --- a/packages/instabug_flutter/lib/src/modules/instabug.dart +++ b/packages/instabug_flutter/lib/src/modules/instabug.dart @@ -406,7 +406,9 @@ class Instabug { /// Reports that the screen has been changed (repro steps) /// [screenName] String containing the screen name static Future reportScreenChange( - Uint8List? image, String screenName,) async { + Uint8List? image, + String screenName, + ) async { return _host.reportScreenChange(image, screenName); } diff --git a/packages/instabug_flutter/lib/src/utils/private_views/instabug_private_view.dart b/packages/instabug_flutter/lib/src/utils/private_views/instabug_private_view.dart index 997407426..6903bd47b 100644 --- a/packages/instabug_flutter/lib/src/utils/private_views/instabug_private_view.dart +++ b/packages/instabug_flutter/lib/src/utils/private_views/instabug_private_view.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; - class InstabugPrivateView extends StatelessWidget { final Widget child; - const InstabugPrivateView({required this.child, Key? key}):super(key: key); + const InstabugPrivateView({required this.child, Key? key}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart b/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart index 1aba259df..c6e285f48 100644 --- a/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart +++ b/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart @@ -37,7 +37,7 @@ class PrivateViewsManager implements InstabugPrivateViewFlutterApi { late List _viewChecks; void addAutoMasking(List masking) { - _viewChecks= List.of([isPrivateWidget]); + _viewChecks = List.of([isPrivateWidget]); if (masking.contains(AutoMasking.none) == false) { _viewChecks.addAll(masking.map((e) => e.hides()).toList()); } @@ -87,7 +87,7 @@ class PrivateViewsManager implements InstabugPrivateViewFlutterApi { void findPrivateViews(Element element) { final widget = element.widget; - final isPrivate = _viewChecks.any((e)=>e.call(widget)); + final isPrivate = _viewChecks.any((e) => e.call(widget)); if (isPrivate) { final renderObject = element.findRenderObject(); if (renderObject is RenderBox && diff --git a/packages/instabug_flutter/lib/src/utils/user_steps/instabug_user_steps.dart b/packages/instabug_flutter/lib/src/utils/user_steps/instabug_user_steps.dart index 15799c5fd..891cd78e2 100644 --- a/packages/instabug_flutter/lib/src/utils/user_steps/instabug_user_steps.dart +++ b/packages/instabug_flutter/lib/src/utils/user_steps/instabug_user_steps.dart @@ -1,5 +1,4 @@ import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; diff --git a/packages/instabug_flutter/lib/src/utils/user_steps/widget_utils.dart b/packages/instabug_flutter/lib/src/utils/user_steps/widget_utils.dart index 7c4718586..939aa4660 100644 --- a/packages/instabug_flutter/lib/src/utils/user_steps/widget_utils.dart +++ b/packages/instabug_flutter/lib/src/utils/user_steps/widget_utils.dart @@ -121,9 +121,10 @@ bool isVideoPlayerWidget(Widget widget) { return videoPlayerTypes.contains(widget.runtimeType.toString()); } -bool isMedia(Widget widget){ +bool isMedia(Widget widget) { return isImageWidget(widget) || isVideoPlayerWidget(widget); } + /// Checks if a widget is toggleable (e.g., switch, checkbox, etc.). bool isToggleableWidget(Widget widget) { return widget is Checkbox || diff --git a/packages/instabug_flutter/pigeons/instabug.api.dart b/packages/instabug_flutter/pigeons/instabug.api.dart index dd6b9f088..183787b8d 100644 --- a/packages/instabug_flutter/pigeons/instabug.api.dart +++ b/packages/instabug_flutter/pigeons/instabug.api.dart @@ -87,7 +87,7 @@ abstract class InstabugHostApi { String? crashMode, String? sessionReplayMode, ); - void reportScreenChange(Uint8List? image,String screenName); + void reportScreenChange(Uint8List? image, String screenName); void setCustomBrandingImage(String light, String dark); diff --git a/packages/instabug_flutter/pigeons/instabug_private_view.api.dart b/packages/instabug_flutter/pigeons/instabug_private_view.api.dart index 76a84b101..9a84a63f3 100644 --- a/packages/instabug_flutter/pigeons/instabug_private_view.api.dart +++ b/packages/instabug_flutter/pigeons/instabug_private_view.api.dart @@ -3,7 +3,6 @@ import 'package:pigeon/pigeon.dart'; @FlutterApi() abstract class InstabugPrivateViewFlutterApi { List getPrivateViews(); - } @HostApi() diff --git a/packages/instabug_flutter/test/instabug_test.dart b/packages/instabug_flutter/test/instabug_test.dart index e1b0de4a0..c20884060 100644 --- a/packages/instabug_flutter/test/instabug_test.dart +++ b/packages/instabug_flutter/test/instabug_test.dart @@ -419,10 +419,10 @@ void main() { test('[reportScreenChange] should call host method', () async { const screen = "home"; - await Instabug.reportScreenChange(null,screen); + await Instabug.reportScreenChange(null, screen); verify( - mHost.reportScreenChange(null,screen), + mHost.reportScreenChange(null, screen), ).called(1); }); diff --git a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart index 6ab79a950..dd7e4fa81 100644 --- a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart +++ b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart @@ -43,15 +43,16 @@ void main() { test('should report screen change when a route is pushed', () { fakeAsync((async) { observer.didPush(route, previousRoute); - - async.elapse(const Duration(milliseconds: 1000)); + WidgetsBinding.instance.handleBeginFrame(Duration.zero); + WidgetsBinding.instance.handleDrawFrame(); + async.elapse(const Duration(milliseconds: 2000)); verify( mScreenLoadingManager.startUiTrace(screen, screen), ).called(1); verify( - mHost.reportScreenChange(null,screen), + mHost.reportScreenChange(null, screen), ).called(1); }); }); @@ -61,7 +62,8 @@ void main() { () { fakeAsync((async) { observer.didPop(route, previousRoute); - + WidgetsBinding.instance.handleBeginFrame(Duration.zero); + WidgetsBinding.instance.handleDrawFrame(); async.elapse(const Duration(milliseconds: 1000)); verify( @@ -69,7 +71,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(null,previousScreen), + mHost.reportScreenChange(null, previousScreen), ).called(1); }); }); @@ -79,7 +81,8 @@ void main() { () { fakeAsync((async) { observer.didPop(route, null); - + WidgetsBinding.instance.handleBeginFrame(Duration.zero); + WidgetsBinding.instance.handleDrawFrame(); async.elapse(const Duration(milliseconds: 1000)); verifyNever( @@ -87,7 +90,7 @@ void main() { ); verifyNever( - mHost.reportScreenChange(null,any), + mHost.reportScreenChange(null, any), ); }); }); @@ -98,7 +101,8 @@ void main() { const fallback = 'N/A'; observer.didPush(route, previousRoute); - + WidgetsBinding.instance.handleBeginFrame(Duration.zero); + WidgetsBinding.instance.handleDrawFrame(); async.elapse(const Duration(milliseconds: 1000)); verify( @@ -106,7 +110,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(null,fallback), + mHost.reportScreenChange(null, fallback), ).called(1); }); }); @@ -118,15 +122,16 @@ void main() { fakeAsync((async) { observer.didPush(route, previousRoute); - - async.elapse(const Duration(milliseconds: 1000)); + WidgetsBinding.instance.handleBeginFrame(Duration.zero); + WidgetsBinding.instance.handleDrawFrame(); + async.elapse(const Duration(milliseconds: 2000)); verify( mScreenLoadingManager.startUiTrace(maskedScreen, screen), ).called(1); verify( - mHost.reportScreenChange(null,maskedScreen), + mHost.reportScreenChange(any, maskedScreen), ).called(1); }); }); diff --git a/packages/instabug_http_client/lib/instabug_http_client.dart b/packages/instabug_http_client/lib/instabug_http_client.dart index 3acb08fd9..f32ed5f60 100644 --- a/packages/instabug_http_client/lib/instabug_http_client.dart +++ b/packages/instabug_http_client/lib/instabug_http_client.dart @@ -47,7 +47,9 @@ class InstabugHttpClient extends InstabugHttpLogger implements http.Client { } Future getW3cHeader( - Map requestHeader, DateTime startTime,) async { + Map requestHeader, + DateTime startTime, + ) async { final w3cHeader = await _networklogger.getW3CHeader( requestHeader, startTime.millisecondsSinceEpoch, @@ -156,8 +158,11 @@ class InstabugHttpClient extends InstabugHttpLogger implements http.Client { (http.StreamedResponse streamedResponse) => http.Response.fromStream(streamedResponse) .then((http.Response response) { - logger.onLogger(response, - startTime: startTime, w3CHeader: w3cHeader,); + logger.onLogger( + response, + startTime: startTime, + w3CHeader: w3cHeader, + ); // Need to return new StreamedResponse, as body only can be listened once return http.StreamedResponse( Stream>.value(response.bodyBytes), diff --git a/packages/instabug_http_client/lib/instabug_http_logger.dart b/packages/instabug_http_client/lib/instabug_http_logger.dart index 4da358730..fc97a831a 100644 --- a/packages/instabug_http_client/lib/instabug_http_logger.dart +++ b/packages/instabug_http_client/lib/instabug_http_logger.dart @@ -4,8 +4,11 @@ import 'package:http/http.dart' as http; import 'package:instabug_flutter/instabug_flutter.dart'; class InstabugHttpLogger { - void onLogger(http.Response response, - {DateTime? startTime, W3CHeader? w3CHeader,}) { + void onLogger( + http.Response response, { + DateTime? startTime, + W3CHeader? w3CHeader, + }) { final networkLogger = NetworkLogger(); final requestHeaders = {}; diff --git a/packages/instabug_http_client/test/instabug_http_client_test.dart b/packages/instabug_http_client/test/instabug_http_client_test.dart index 3467d443c..73014020b 100644 --- a/packages/instabug_http_client/test/instabug_http_client_test.dart +++ b/packages/instabug_http_client/test/instabug_http_client_test.dart @@ -55,8 +55,8 @@ Future main() async { test('expect instabug http client GET to return response', () async { when( - instabugHttpClient.client.get(url, headers: anyNamed('headers')),) - .thenAnswer((_) async => mockedResponse); + instabugHttpClient.client.get(url, headers: anyNamed('headers')), + ).thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.get(url); expect(result, isInstanceOf()); expect(result, mockedResponse); @@ -68,8 +68,8 @@ Future main() async { test('expect instabug http client HEAD to return response', () async { when( - instabugHttpClient.client.head(url, headers: anyNamed('headers')),) - .thenAnswer((_) async => mockedResponse); + instabugHttpClient.client.head(url, headers: anyNamed('headers')), + ).thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.head(url); expect(result, isInstanceOf()); expect(result, mockedResponse); @@ -81,8 +81,8 @@ Future main() async { test('expect instabug http client DELETE to return response', () async { when( - instabugHttpClient.client.delete(url, headers: anyNamed('headers')),) - .thenAnswer((_) async => mockedResponse); + instabugHttpClient.client.delete(url, headers: anyNamed('headers')), + ).thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.delete(url); expect(result, isInstanceOf()); expect(result, mockedResponse); @@ -94,8 +94,8 @@ Future main() async { test('expect instabug http client PATCH to return response', () async { when( - instabugHttpClient.client.patch(url, headers: anyNamed('headers')),) - .thenAnswer((_) async => mockedResponse); + instabugHttpClient.client.patch(url, headers: anyNamed('headers')), + ).thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.patch(url); expect(result, isInstanceOf()); expect(result, mockedResponse); @@ -107,8 +107,8 @@ Future main() async { test('expect instabug http client POST to return response', () async { when( - instabugHttpClient.client.post(url, headers: anyNamed('headers')),) - .thenAnswer((_) async => mockedResponse); + instabugHttpClient.client.post(url, headers: anyNamed('headers')), + ).thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.post(url); expect(result, isInstanceOf()); expect(result, mockedResponse); @@ -120,8 +120,8 @@ Future main() async { test('expect instabug http client PUT to return response', () async { when( - instabugHttpClient.client.put(url, headers: anyNamed('headers')),) - .thenAnswer((_) async => mockedResponse); + instabugHttpClient.client.put(url, headers: anyNamed('headers')), + ).thenAnswer((_) async => mockedResponse); final result = await instabugHttpClient.put(url); expect(result, isInstanceOf()); expect(result.body, mockedResponse.body); @@ -134,8 +134,8 @@ Future main() async { test('expect instabug http client READ to return response', () async { const response = 'Some response string'; when( - instabugHttpClient.client.read(url, headers: anyNamed('headers')),) - .thenAnswer((_) async => response); + instabugHttpClient.client.read(url, headers: anyNamed('headers')), + ).thenAnswer((_) async => response); final result = await instabugHttpClient.read(url); expect(result, isInstanceOf()); @@ -194,8 +194,8 @@ Future main() async { test('stress test for GET method', () async { when( - instabugHttpClient.client.get(url, headers: anyNamed('headers')),) - .thenAnswer((_) async => mockedResponse); + instabugHttpClient.client.get(url, headers: anyNamed('headers')), + ).thenAnswer((_) async => mockedResponse); for (var i = 0; i < 10000; i++) { await instabugHttpClient.get(url); } From 94ddeb6865fde4eccd40bc1c8286f23154cf433b Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 00:39:19 +0200 Subject: [PATCH 03/16] fix test 2.10.0 --- .../instabug/flutter/modules/InstabugApi.java | 2 +- .../com/instabug/flutter/InstabugApiTest.java | 2 +- .../ios/InstabugTests/InstabugApiTests.m | 2 +- .../ios/Classes/Modules/InstabugApi.m | 2 +- .../utils/instabug_navigator_observer.dart | 2 +- .../private_views/private_views_manager.dart | 3 +- .../screen_loading/screenshot_pipeline.dart | 154 ------------------ .../pigeons/instabug.api.dart | 2 +- .../instabug_navigator_observer_test.dart | 20 +-- 9 files changed, 17 insertions(+), 172 deletions(-) delete mode 100644 packages/instabug_flutter/lib/src/utils/screen_loading/screenshot_pipeline.dart diff --git a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index ffe874919..79904ad71 100644 --- a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -412,7 +412,7 @@ public void setReproStepsConfig(@Nullable String bugMode, @Nullable String crash } @Override - public void reportScreenChange(byte[] image, @NonNull String screenName) { + public void reportScreenChange(@NonNull String screenName) { try { Method method = Reflection.getMethod(Class.forName("com.instabug.library.Instabug"), "reportScreenChange", Bitmap.class, String.class); diff --git a/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/InstabugApiTest.java b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/InstabugApiTest.java index d7b3e36fd..762e9bf86 100644 --- a/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/InstabugApiTest.java +++ b/packages/instabug_flutter/android/src/test/java/com/instabug/flutter/InstabugApiTest.java @@ -478,7 +478,7 @@ public void testSetReproStepsConfig() { public void testReportScreenChange() { String screenName = "HomeScreen"; - api.reportScreenChange(null,screenName); + api.reportScreenChange(screenName); reflected.verify(() -> MockReflected.reportScreenChange(null, screenName)); } diff --git a/packages/instabug_flutter/example/ios/InstabugTests/InstabugApiTests.m b/packages/instabug_flutter/example/ios/InstabugTests/InstabugApiTests.m index c4b61064c..755ce9113 100644 --- a/packages/instabug_flutter/example/ios/InstabugTests/InstabugApiTests.m +++ b/packages/instabug_flutter/example/ios/InstabugTests/InstabugApiTests.m @@ -333,7 +333,7 @@ - (void)testReportScreenChange { NSString *screenName = @"HomeScreen"; FlutterError *error; - [self.api reportScreenChangeImage:nil screenName:screenName error:&error]; + [self.api reportScreenChangeScreenName:screenName error:&error]; OCMVerify([self.mInstabug logViewDidAppearEvent:screenName]); } diff --git a/packages/instabug_flutter/ios/Classes/Modules/InstabugApi.m b/packages/instabug_flutter/ios/Classes/Modules/InstabugApi.m index e22f03453..f61688876 100644 --- a/packages/instabug_flutter/ios/Classes/Modules/InstabugApi.m +++ b/packages/instabug_flutter/ios/Classes/Modules/InstabugApi.m @@ -209,7 +209,7 @@ - (void)setCustomBrandingImageLight:(NSString *)light dark:(NSString *)dark erro } } -- (void)reportScreenChangeImage:(nullable FlutterStandardTypedData *)image screenName:(nonnull NSString *)screenName error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { +- (void)reportScreenChangeScreenName:(NSString *)screenName error:(FlutterError *_Nullable *_Nonnull)error { SEL setPrivateApiSEL = NSSelectorFromString(@"logViewDidAppearEvent:"); if ([[Instabug class] respondsToSelector:setPrivateApiSEL]) { NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[Instabug class] methodSignatureForSelector:setPrivateApiSEL]]; diff --git a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart index 7f8b93c4e..0aedab597 100644 --- a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart +++ b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart @@ -24,7 +24,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { name: maskedScreenName, ); - WidgetsBinding.instance.addPostFrameCallback((_) async { + WidgetsBinding.instance?.addPostFrameCallback((_) async { // Starts a the new UI trace which is exclusive to screen loading ScreenLoadingManager.I.startUiTrace(maskedScreenName, screenName); // If there is a step that hasn't been pushed yet diff --git a/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart b/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart index c6e285f48..2450efc48 100644 --- a/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart +++ b/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart @@ -91,8 +91,7 @@ class PrivateViewsManager implements InstabugPrivateViewFlutterApi { if (isPrivate) { final renderObject = element.findRenderObject(); if (renderObject is RenderBox && - renderObject.attached && - element.mounted) { + renderObject.attached) { final isElementInCurrentScreen = isElementInCurrentRoute(element); final rect = getLayoutRectInfoFromRenderObject(renderObject); if (rect != null && diff --git a/packages/instabug_flutter/lib/src/utils/screen_loading/screenshot_pipeline.dart b/packages/instabug_flutter/lib/src/utils/screen_loading/screenshot_pipeline.dart deleted file mode 100644 index 015951b1f..000000000 --- a/packages/instabug_flutter/lib/src/utils/screen_loading/screenshot_pipeline.dart +++ /dev/null @@ -1,154 +0,0 @@ -import 'dart:typed_data'; -import 'dart:ui' as ui; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:instabug_flutter/instabug_flutter.dart'; -import 'package:instabug_flutter/src/utils/user_steps/widget_utils.dart'; - -enum AutoMasking { labels, textInputs, media, none } - -extension ValidationMethod on AutoMasking { - bool Function(Widget) hides() { - switch (this) { - case AutoMasking.labels: - return isTextWidget; - case AutoMasking.textInputs: - return isTextInputWidget; - case AutoMasking.media: - return isMedia; - case AutoMasking.none: - return (_) => false; - } - } -} - -class ScreenshotPipeLine { - ScreenshotPipeLine._internal(); - - static final viewChecks = List.of([_isPrivate]); - - static void addAutoMasking(List masking) { - viewChecks.addAll(masking.map((e) => e.hides()).toList()); - } - - static Future getScreenShot() async { - await Future.delayed(const Duration(milliseconds: 300)); - - final context = instabugWidgetKey.currentContext; - - final renderObject = context?.findRenderObject() as RenderRepaintBoundary?; - if (context == null || renderObject == null) { - return null; - } - - final image = renderObject.toImageSync(); - final rects = _getRectsOfPrivateViews(); - // Create a new canvas to draw on - final recorder = ui.PictureRecorder(); - final canvas = Canvas(recorder); - - // Draw the original image on the canvas - final imagePaint = Paint(); - - canvas.drawImage(image, Offset.zero, imagePaint); - - // Draw rectangles with black color - final rectPaint = Paint() - ..color = Colors.black - ..style = PaintingStyle.fill - ..strokeWidth = 1; // Adjust stroke width if needed - - for (final rect in rects) { - canvas.drawRect(rect, rectPaint); - } - - // Convert canvas to image - final finalImage = recorder.endRecording().toImageSync( - image.width, - image.height, - ); - - final data = await finalImage.toByteData(format: ui.ImageByteFormat.png); - final imageBytes = data!.buffer.asUint8List(); - return imageBytes; - } - - static List _getRectsOfPrivateViews() { - final context = instabugWidgetKey.currentContext; - if (context == null) return []; - - final rootRenderObject = - context.findRenderObject() as RenderRepaintBoundary?; - if (rootRenderObject is! RenderBox) return []; - - final bounds = Offset.zero & rootRenderObject!.size; - - final rects = []; - - void findPrivateViews(Element element) { - final widget = element.widget; - - final isPrivate = viewChecks.any((e) => e.call(widget)); - // final isText = isTextWidget(widget); - if (isPrivate) { - final renderObject = element.findRenderObject(); - if (renderObject is RenderBox && - renderObject.attached && - element.mounted) { - final isElementInCurrentScreen = _isElementInCurrentRoute(element); - final rect = _getLayoutRectInfoFromRenderObject(renderObject); - if (rect != null && - rect.overlaps(bounds) && - isElementInCurrentScreen) { - rects.add(rect); - } - } - } else { - element.visitChildElements(findPrivateViews); - } - } - - rects.clear(); - context.visitChildElements(findPrivateViews); - - return rects; - } - - static bool _isPrivate(Widget widget) { - return widget.runtimeType.toString() == 'InstabugPrivateView' || - widget.runtimeType.toString() == 'InstabugSliverPrivateView'; - } - - static bool _isElementInCurrentRoute(Element element) { - final modalRoute = ModalRoute.of(element); - return modalRoute?.isCurrent ?? false; - } - - static Rect? _getLayoutRectInfoFromRenderObject(RenderObject? renderObject) { - if (renderObject == null) { - return null; - } - - final globalOffset = _getRenderGlobalOffset(renderObject); - - if (renderObject is RenderProxyBox) { - if (renderObject.child == null) { - return null; - } - - return MatrixUtils.transformRect( - renderObject.child!.getTransformTo(renderObject), - Offset.zero & renderObject.child!.size, - ).shift(globalOffset); - } - - return renderObject.paintBounds.shift(globalOffset); - } - - static Offset _getRenderGlobalOffset(RenderObject renderObject) { - return MatrixUtils.transformPoint( - renderObject.getTransformTo(null), - Offset.zero, - ); - } -} diff --git a/packages/instabug_flutter/pigeons/instabug.api.dart b/packages/instabug_flutter/pigeons/instabug.api.dart index 183787b8d..854df229b 100644 --- a/packages/instabug_flutter/pigeons/instabug.api.dart +++ b/packages/instabug_flutter/pigeons/instabug.api.dart @@ -87,7 +87,7 @@ abstract class InstabugHostApi { String? crashMode, String? sessionReplayMode, ); - void reportScreenChange(Uint8List? image, String screenName); + void reportScreenChange(String screenName); void setCustomBrandingImage(String light, String dark); diff --git a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart index dd7e4fa81..057b1a952 100644 --- a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart +++ b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart @@ -43,8 +43,8 @@ void main() { test('should report screen change when a route is pushed', () { fakeAsync((async) { observer.didPush(route, previousRoute); - WidgetsBinding.instance.handleBeginFrame(Duration.zero); - WidgetsBinding.instance.handleDrawFrame(); + WidgetsBinding.instance?.handleBeginFrame(Duration.zero); + WidgetsBinding.instance?.handleDrawFrame(); async.elapse(const Duration(milliseconds: 2000)); verify( @@ -62,8 +62,8 @@ void main() { () { fakeAsync((async) { observer.didPop(route, previousRoute); - WidgetsBinding.instance.handleBeginFrame(Duration.zero); - WidgetsBinding.instance.handleDrawFrame(); + WidgetsBinding.instance?.handleBeginFrame(Duration.zero); + WidgetsBinding.instance?.handleDrawFrame(); async.elapse(const Duration(milliseconds: 1000)); verify( @@ -81,8 +81,8 @@ void main() { () { fakeAsync((async) { observer.didPop(route, null); - WidgetsBinding.instance.handleBeginFrame(Duration.zero); - WidgetsBinding.instance.handleDrawFrame(); + WidgetsBinding.instance?.handleBeginFrame(Duration.zero); + WidgetsBinding.instance?.handleDrawFrame(); async.elapse(const Duration(milliseconds: 1000)); verifyNever( @@ -101,8 +101,8 @@ void main() { const fallback = 'N/A'; observer.didPush(route, previousRoute); - WidgetsBinding.instance.handleBeginFrame(Duration.zero); - WidgetsBinding.instance.handleDrawFrame(); + WidgetsBinding.instance?.handleBeginFrame(Duration.zero); + WidgetsBinding.instance?.handleDrawFrame(); async.elapse(const Duration(milliseconds: 1000)); verify( @@ -122,8 +122,8 @@ void main() { fakeAsync((async) { observer.didPush(route, previousRoute); - WidgetsBinding.instance.handleBeginFrame(Duration.zero); - WidgetsBinding.instance.handleDrawFrame(); + WidgetsBinding.instance?.handleBeginFrame(Duration.zero); + WidgetsBinding.instance?.handleDrawFrame(); async.elapse(const Duration(milliseconds: 2000)); verify( From 67721463f89ae37d6e588cad88837313f9cdd86c Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 00:54:54 +0200 Subject: [PATCH 04/16] fix test 2.10.0 --- .../lib/instabug_dio_interceptor.dart | 1 + .../instabug_flutter/example/ios/Podfile.lock | 7 +- .../instabug_flutter/example/pubspec.lock | 52 ++-- .../lib/instabug_flutter.dart | 2 +- .../utils/instabug_navigator_observer.dart | 2 +- .../private_views/private_views_manager.dart | 22 +- packages/instabug_flutter/pubspec.lock | 252 ++++++------------ .../instabug_navigator_observer_test.dart | 2 + 8 files changed, 127 insertions(+), 213 deletions(-) diff --git a/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart b/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart index 72b8af3ae..36d2c9e01 100644 --- a/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart +++ b/packages/instabug_dio_interceptor/lib/instabug_dio_interceptor.dart @@ -85,6 +85,7 @@ class InstabugDioInterceptor extends Interceptor { if (responseHeaders.containsKey('content-length')) { // ignore: avoid_dynamic_calls responseBodySize = + // ignore: avoid_dynamic_calls int.parse((responseHeaders['content-length'][0]) ?? '0'); } else if (response.data != null) { responseBodySize = response.data.toString().length; diff --git a/packages/instabug_flutter/example/ios/Podfile.lock b/packages/instabug_flutter/example/ios/Podfile.lock index 6b1fb5687..496e1bd6a 100644 --- a/packages/instabug_flutter/example/ios/Podfile.lock +++ b/packages/instabug_flutter/example/ios/Podfile.lock @@ -7,14 +7,13 @@ PODS: - OCMock (3.6) - video_player_avfoundation (0.0.1): - Flutter - - FlutterMacOS DEPENDENCIES: - Flutter (from `Flutter`) - Instabug (from `https://ios-releases.instabug.com/custom/feature-flutter_user_steps-base/14.1.0/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) - - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) + - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) SPEC REPOS: trunk: @@ -28,14 +27,14 @@ EXTERNAL SOURCES: instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" video_player_avfoundation: - :path: ".symlinks/plugins/video_player_avfoundation/darwin" + :path: ".symlinks/plugins/video_player_avfoundation/ios" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Instabug: 8eb6f63f3ac66f062025c15293549ab67150e9f9 instabug_flutter: a24751dfaedd29475da2af062d3e19d697438f72 OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 - video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 + video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff PODFILE CHECKSUM: 87a326d297554318d9004349a35d82ffe3f0c228 diff --git a/packages/instabug_flutter/example/pubspec.lock b/packages/instabug_flutter/example/pubspec.lock index 33aec3774..319796b95 100644 --- a/packages/instabug_flutter/example/pubspec.lock +++ b/packages/instabug_flutter/example/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "0.17.2" fake_async: dependency: transitive description: @@ -102,18 +102,18 @@ packages: dependency: transitive description: name: html - sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" + sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 url: "https://pub.dev" source: hosted - version: "0.15.5" + version: "0.15.1" http: dependency: "direct main" description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" url: "https://pub.dev" source: hosted - version: "0.13.6" + version: "0.13.5" http_parser: dependency: transitive description: @@ -212,10 +212,10 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a url: "https://pub.dev" source: hosted - version: "2.1.8" + version: "2.1.3" process: dependency: transitive description: @@ -289,10 +289,10 @@ packages: dependency: transitive description: name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" vector_math: dependency: transitive description: @@ -305,42 +305,42 @@ packages: dependency: "direct main" description: name: video_player - sha256: "4a8c3492d734f7c39c2588a3206707a05ee80cef52e8c7f3b2078d430c84bc17" + sha256: "59f7f31c919c59cbedd37c617317045f5f650dc0eeb568b0b0de9a36472bdb28" url: "https://pub.dev" source: hosted - version: "2.9.2" + version: "2.5.1" video_player_android: dependency: transitive description: name: video_player_android - sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898" + sha256: "984388511230bac63feb53b2911a70e829fe0976b6b2213f5c579c4e0a882db3" url: "https://pub.dev" source: hosted - version: "2.7.16" + version: "2.3.10" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: "33224c19775fd244be2d6e3dbd8e1826ab162877bd61123bf71890772119a2b7" + sha256: d9f7a46d6a77680adb03ec05a381025d6e890ebe636637c6c3014cc3926b97e9 url: "https://pub.dev" source: hosted - version: "2.6.5" + version: "2.3.8" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - sha256: "229d7642ccd9f3dc4aba169609dd6b5f3f443bb4cc15b82f7785fcada5af9bbb" + sha256: "42bb75de5e9b79e1f20f1d95f688fac0f95beac4d89c6eb2cd421724d4432dae" url: "https://pub.dev" source: hosted - version: "6.2.3" + version: "6.0.1" video_player_web: dependency: transitive description: name: video_player_web - sha256: "881b375a934d8ebf868c7fb1423b2bfaa393a0a265fa3f733079a86536064a10" + sha256: b649b07b8f8f553bee4a97a0a53d0fe78a70b115eafaf0105b612b32b05ddb99 url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.0.13" vm_service: dependency: transitive description: @@ -349,14 +349,6 @@ packages: url: "https://pub.dev" source: hosted version: "14.3.0" - web: - dependency: transitive - description: - name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb - url: "https://pub.dev" - source: hosted - version: "1.1.0" webdriver: dependency: transitive description: @@ -366,5 +358,5 @@ packages: source: hosted version: "3.0.4" sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.24.0" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/instabug_flutter/lib/instabug_flutter.dart b/packages/instabug_flutter/lib/instabug_flutter.dart index 25a3d6ffc..42c49fc26 100644 --- a/packages/instabug_flutter/lib/instabug_flutter.dart +++ b/packages/instabug_flutter/lib/instabug_flutter.dart @@ -21,8 +21,8 @@ export 'src/utils/instabug_navigator_observer.dart'; export 'src/utils/instabug_widget.dart'; export 'src/utils/private_views/instabug_private_view.dart'; export 'src/utils/private_views/instabug_sliver_private_view.dart'; +export 'src/utils/private_views/private_views_manager.dart' show AutoMasking; export 'src/utils/screen_loading/instabug_capture_screen_loading.dart'; export 'src/utils/screen_loading/route_matcher.dart'; -export 'src/utils/screen_loading/screenshot_pipeline.dart' show AutoMasking; export 'src/utils/screen_name_masker.dart' show ScreenNameMaskingCallback; export 'src/utils/user_steps/instabug_user_steps.dart'; diff --git a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart index 0aedab597..0dab7fd3e 100644 --- a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart +++ b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart @@ -23,7 +23,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { route: newRoute, name: maskedScreenName, ); - + //ignore: invalid_null_aware_operator WidgetsBinding.instance?.addPostFrameCallback((_) async { // Starts a the new UI trace which is exclusive to screen loading ScreenLoadingManager.I.startUiTrace(maskedScreenName, screenName); diff --git a/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart b/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart index 2450efc48..9b3708e37 100644 --- a/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart +++ b/packages/instabug_flutter/lib/src/utils/private_views/private_views_manager.dart @@ -4,7 +4,24 @@ import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter/src/generated/instabug.api.g.dart'; import 'package:instabug_flutter/src/generated/instabug_private_view.api.g.dart'; import 'package:instabug_flutter/src/utils/enum_converter.dart'; -import 'package:instabug_flutter/src/utils/screen_loading/screenshot_pipeline.dart'; +import 'package:instabug_flutter/src/utils/user_steps/widget_utils.dart'; + +enum AutoMasking { labels, textInputs, media, none } + +extension ValidationMethod on AutoMasking { + bool Function(Widget) hides() { + switch (this) { + case AutoMasking.labels: + return isTextWidget; + case AutoMasking.textInputs: + return isTextInputWidget; + case AutoMasking.media: + return isMedia; + case AutoMasking.none: + return (_) => false; + } + } +} /// responsible for masking views /// before they are sent to the native SDKs. @@ -90,8 +107,7 @@ class PrivateViewsManager implements InstabugPrivateViewFlutterApi { final isPrivate = _viewChecks.any((e) => e.call(widget)); if (isPrivate) { final renderObject = element.findRenderObject(); - if (renderObject is RenderBox && - renderObject.attached) { + if (renderObject is RenderBox && renderObject.attached) { final isElementInCurrentScreen = isElementInCurrentRoute(element); final rect = getLayoutRectInfoFromRenderObject(renderObject); if (rect != null && diff --git a/packages/instabug_flutter/pubspec.lock b/packages/instabug_flutter/pubspec.lock index 346b5865d..9e44d7fdf 100644 --- a/packages/instabug_flutter/pubspec.lock +++ b/packages/instabug_flutter/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.3.1" async: dependency: transitive description: @@ -61,18 +61,18 @@ packages: dependency: transitive description: name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.0.0" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.2.1" build_runner: dependency: "direct dev" description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: build_runner_core - sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 + sha256: f4d6244cc071ba842c296cb1c4ee1b31596b9f924300647ac7a1445493471a3f url: "https://pub.dev" source: hosted - version: "7.3.2" + version: "7.2.3" built_collection: dependency: transitive description: @@ -101,10 +101,10 @@ packages: dependency: transitive description: name: built_value - sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + sha256: "69acb7007eb2a31dc901512bfe0f7b767168be34cb734835d54c070bfa74c1b2" url: "https://pub.dev" source: hosted - version: "8.9.2" + version: "8.8.0" characters: dependency: transitive description: @@ -117,18 +117,18 @@ packages: dependency: transitive description: name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659 url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.1" cli_util: dependency: transitive description: name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" url: "https://pub.dev" source: hosted - version: "0.4.2" + version: "0.3.5" clock: dependency: transitive description: @@ -157,34 +157,26 @@ packages: dependency: transitive description: name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - coverage: - dependency: transitive - description: - name: coverage - sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 + sha256: "1be13198012c1d5bc042dc40ad1d7f16cbd522350984c0c1abf471d6d7e305c6" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "3.1.0" crypto: dependency: transitive description: name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.0.2" csslib: dependency: transitive description: name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "0.17.2" dart_style: dependency: transitive description: @@ -205,18 +197,18 @@ packages: dependency: transitive description: name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "6.1.4" fixnum: dependency: transitive description: name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.0.1" flutter: dependency: "direct main" description: flutter @@ -239,42 +231,42 @@ packages: dependency: transitive description: name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" graphs: dependency: transitive description: name: graphs - sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.2.0" html: dependency: transitive description: name: html - sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" + sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 url: "https://pub.dev" source: hosted - version: "0.15.5" + version: "0.15.1" http: dependency: transitive description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server - sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" url: "https://pub.dev" source: hosted - version: "3.2.2" + version: "3.2.1" http_parser: dependency: transitive description: @@ -287,26 +279,26 @@ packages: dependency: transitive description: name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.4" js: dependency: transitive description: name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "0.6.5" json_annotation: dependency: transitive description: name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + sha256: cb314f00b2488de7bc575207e54402cd2f92363f333a7933fd1b0631af226baa url: "https://pub.dev" source: hosted - version: "4.9.0" + version: "4.6.0" leak_tracker: dependency: transitive description: @@ -335,34 +327,26 @@ packages: dependency: "direct dev" description: name: lint - sha256: "4a539aa34ec5721a2c7574ae2ca0336738ea4adc2a34887d54b7596310b33c85" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - lints: - dependency: transitive - description: - name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "6c77824cc90657bfd850a160b699ed9f3454447b9baff778b01447e8f77c4595" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "1.9.0" logging: dependency: transitive description: name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.1.0" markdown: dependency: transitive description: name: markdown - sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + sha256: c2b81e184067b41d0264d514f7cdaa2c02d38511e39d6521a1ccc238f6d7b3f2 url: "https://pub.dev" source: hosted - version: "7.2.2" + version: "6.0.1" matcher: dependency: transitive description: @@ -391,10 +375,10 @@ packages: dependency: transitive description: name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + sha256: "52e38f7e1143ef39daf532117d6b8f8f617bf4bcd6044ed8c29040d20d269630" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "1.0.3" mockito: dependency: "direct dev" description: @@ -403,30 +387,22 @@ packages: url: "https://pub.dev" source: hosted version: "5.4.4" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" package_config: dependency: transitive description: name: package_config - sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.0" pana: dependency: "direct dev" description: name: pana - sha256: "3fc3fe8e7a9fd4827fa4d625a423eec95d305b2bc3538a3adf7fd6c49217af97" + sha256: b29dcbe0664c7d1633fc4cfd20d30ef654d12b9e9312a75a205b3bed5ba0b5fe url: "https://pub.dev" source: hosted - version: "0.21.45" + version: "0.21.18" path: dependency: transitive description: @@ -455,66 +431,50 @@ packages: dependency: transitive description: name: pub_semver - sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" + sha256: b959af0a045c3484c4a8f4997731f5bfe4cac60d732fd8ce35b351f2d6a459fe url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.1.2" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.1" retry: dependency: transitive description: name: retry - sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc" + sha256: a8a1e475a100a0bdc73f529ca8ea1e9c9c76bec8ad86a1f47780139a34ce7aea url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.1" safe_url_check: dependency: transitive description: name: safe_url_check - sha256: "49a3e060a7869cbafc8f4845ca1ecbbaaa53179980a32f4fdfeab1607e90f41d" + sha256: b85685b48d74dcd9659e1f2228f900b9fb37cd3b4ba085ca4f593d06c00c36a6 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" shelf: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 - url: "https://pub.dev" - source: hosted - version: "1.4.1" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + sha256: "8ec607599dd0a78931a5114cdac7d609b6dbbf479a38acc9a6dba024b2a30ea0" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.3.2" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 + sha256: "6db16374bc3497d21aa0eebe674d3db9fdf82082aac0f04dc7b44e4af5b08afc" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "1.0.2" sky_engine: dependency: transitive description: flutter @@ -528,22 +488,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b - url: "https://pub.dev" - source: hosted - version: "2.1.2" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" - url: "https://pub.dev" - source: hosted - version: "0.10.13" source_span: dependency: transitive description: @@ -572,10 +516,10 @@ packages: dependency: transitive description: name: stream_transform - sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.0" string_scanner: dependency: transitive description: @@ -588,10 +532,10 @@ packages: dependency: transitive description: name: tar - sha256: "22f67e2d77b51050436620b2a5de521c58ca6f0b75af1d9ab3c8cae2eae58fcd" + sha256: "85ffd53e277f2bac8afa2885e6b195e26937e9c402424c3d88d92fd920b56de9" url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "0.5.6" term_glyph: dependency: transitive description: @@ -600,14 +544,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" - test: - dependency: transitive - description: - name: test - sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" - url: "https://pub.dev" - source: hosted - version: "1.25.8" test_api: dependency: transitive description: @@ -616,30 +552,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.3" - test_core: - dependency: transitive - description: - name: test_core - sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" - url: "https://pub.dev" - source: hosted - version: "0.6.5" timing: dependency: transitive description: name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.1" typed_data: dependency: transitive description: name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" vector_math: dependency: transitive description: @@ -660,50 +588,26 @@ packages: dependency: transitive description: name: watcher - sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web: - dependency: transitive - description: - name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" url: "https://pub.dev" source: hosted - version: "0.1.6" + version: "1.0.2" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "2.4.0" yaml: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.1" sdks: dart: ">=3.5.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart index 057b1a952..e880d494c 100644 --- a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart +++ b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart @@ -1,3 +1,5 @@ +// ignore_for_file: invalid_null_aware_operator + import 'package:fake_async/fake_async.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; From b648f8f9f9e9574c9c696d4714257e6b9226c830 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 01:04:43 +0200 Subject: [PATCH 05/16] fix test 2.10.0 --- packages/instabug_flutter/pubspec.lock | 262 +++++++++++++++++-------- 1 file changed, 179 insertions(+), 83 deletions(-) diff --git a/packages/instabug_flutter/pubspec.lock b/packages/instabug_flutter/pubspec.lock index 9e44d7fdf..3134942db 100644 --- a/packages/instabug_flutter/pubspec.lock +++ b/packages/instabug_flutter/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: args - sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.6.0" async: dependency: transitive description: @@ -53,26 +53,26 @@ packages: 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: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.4" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.4.2" build_runner: dependency: "direct dev" description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: build_runner_core - sha256: f4d6244cc071ba842c296cb1c4ee1b31596b9f924300647ac7a1445493471a3f + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 url: "https://pub.dev" source: hosted - version: "7.2.3" + version: "7.3.2" built_collection: dependency: transitive description: @@ -101,10 +101,10 @@ packages: dependency: transitive description: name: built_value - sha256: "69acb7007eb2a31dc901512bfe0f7b767168be34cb734835d54c070bfa74c1b2" + sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61" url: "https://pub.dev" source: hosted - version: "8.8.0" + version: "8.9.4" characters: dependency: transitive description: @@ -117,18 +117,18 @@ packages: dependency: transitive description: name: checked_yaml - sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659 + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" cli_util: dependency: transitive description: name: cli_util - sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c url: "https://pub.dev" source: hosted - version: "0.3.5" + version: "0.4.2" clock: dependency: transitive description: @@ -157,26 +157,34 @@ packages: dependency: transitive description: name: convert - sha256: "1be13198012c1d5bc042dc40ad1d7f16cbd522350984c0c1abf471d6d7e305c6" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "1.11.1" crypto: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.6" csslib: dependency: transitive description: name: csslib - sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" url: "https://pub.dev" source: hosted - version: "0.17.2" + version: "1.0.2" dart_style: dependency: transitive description: @@ -197,18 +205,18 @@ packages: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -231,74 +239,74 @@ packages: dependency: transitive description: name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.3" graphs: dependency: transitive description: name: graphs - sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.2" html: dependency: transitive description: name: html - sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" url: "https://pub.dev" source: hosted - version: "0.15.1" + version: "0.15.5" http: dependency: transitive description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "1.3.0" http_multi_server: 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: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" io: dependency: transitive description: name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" js: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.7.1" json_annotation: dependency: transitive description: name: json_annotation - sha256: cb314f00b2488de7bc575207e54402cd2f92363f333a7933fd1b0631af226baa + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.6.0" + version: "4.9.0" leak_tracker: dependency: transitive description: @@ -327,26 +335,34 @@ packages: dependency: "direct dev" description: name: lint - sha256: "6c77824cc90657bfd850a160b699ed9f3454447b9baff778b01447e8f77c4595" + sha256: "4a539aa34ec5721a2c7574ae2ca0336738ea4adc2a34887d54b7596310b33c85" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.10.0" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" logging: dependency: transitive description: name: logging - sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.3.0" markdown: dependency: transitive description: name: markdown - sha256: c2b81e184067b41d0264d514f7cdaa2c02d38511e39d6521a1ccc238f6d7b3f2 + sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1" url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "7.3.0" matcher: dependency: transitive description: @@ -375,10 +391,10 @@ packages: dependency: transitive description: name: mime - sha256: "52e38f7e1143ef39daf532117d6b8f8f617bf4bcd6044ed8c29040d20d269630" + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "2.0.0" mockito: dependency: "direct dev" description: @@ -387,22 +403,30 @@ packages: url: "https://pub.dev" source: hosted version: "5.4.4" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" package_config: dependency: transitive description: name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" pana: dependency: "direct dev" description: name: pana - sha256: b29dcbe0664c7d1633fc4cfd20d30ef654d12b9e9312a75a205b3bed5ba0b5fe + sha256: "3fc3fe8e7a9fd4827fa4d625a423eec95d305b2bc3538a3adf7fd6c49217af97" url: "https://pub.dev" source: hosted - version: "0.21.18" + version: "0.21.45" path: dependency: transitive description: @@ -431,50 +455,66 @@ packages: dependency: transitive description: name: pub_semver - sha256: b959af0a045c3484c4a8f4997731f5bfe4cac60d732fd8ce35b351f2d6a459fe + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.5" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.5.0" retry: dependency: transitive description: name: retry - sha256: a8a1e475a100a0bdc73f529ca8ea1e9c9c76bec8ad86a1f47780139a34ce7aea + sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" safe_url_check: dependency: transitive description: name: safe_url_check - sha256: b85685b48d74dcd9659e1f2228f900b9fb37cd3b4ba085ca4f593d06c00c36a6 + sha256: "49a3e060a7869cbafc8f4845ca1ecbbaaa53179980a32f4fdfeab1607e90f41d" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" shelf: dependency: transitive description: name: shelf - sha256: "8ec607599dd0a78931a5114cdac7d609b6dbbf479a38acc9a6dba024b2a30ea0" + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: "6db16374bc3497d21aa0eebe674d3db9fdf82082aac0f04dc7b44e4af5b08afc" + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "2.0.1" sky_engine: dependency: transitive description: flutter @@ -488,6 +528,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" source_span: dependency: transitive description: @@ -516,10 +572,10 @@ 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: @@ -532,10 +588,10 @@ packages: dependency: transitive description: name: tar - sha256: "85ffd53e277f2bac8afa2885e6b195e26937e9c402424c3d88d92fd920b56de9" + sha256: "22f67e2d77b51050436620b2a5de521c58ca6f0b75af1d9ab3c8cae2eae58fcd" url: "https://pub.dev" source: hosted - version: "0.5.6" + version: "1.0.5" term_glyph: dependency: transitive description: @@ -544,6 +600,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + test: + dependency: transitive + description: + name: test + sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" + url: "https://pub.dev" + source: hosted + version: "1.25.8" test_api: dependency: transitive description: @@ -552,22 +616,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.3" + test_core: + dependency: transitive + description: + name: test_core + sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" + url: "https://pub.dev" + source: hosted + version: "0.6.5" timing: 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: name: typed_data - sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" vector_math: dependency: transitive description: @@ -588,26 +660,50 @@ packages: dependency: transitive description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "3.0.2" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" yaml: dependency: transitive description: name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.3" sdks: - dart: ">=3.5.0 <4.0.0" + dart: ">=3.6.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" From af5276da3de6f9993103455b61ae1e7135cde064 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 01:12:35 +0200 Subject: [PATCH 06/16] fix test 2.10.0 --- .../instabug_flutter/example/ios/Podfile.lock | 7 ++- .../instabug_flutter/example/pubspec.lock | 56 +++++++++++-------- .../lib/src/modules/instabug.dart | 3 +- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/packages/instabug_flutter/example/ios/Podfile.lock b/packages/instabug_flutter/example/ios/Podfile.lock index 496e1bd6a..6b1fb5687 100644 --- a/packages/instabug_flutter/example/ios/Podfile.lock +++ b/packages/instabug_flutter/example/ios/Podfile.lock @@ -7,13 +7,14 @@ PODS: - OCMock (3.6) - video_player_avfoundation (0.0.1): - Flutter + - FlutterMacOS DEPENDENCIES: - Flutter (from `Flutter`) - Instabug (from `https://ios-releases.instabug.com/custom/feature-flutter_user_steps-base/14.1.0/Instabug.podspec`) - instabug_flutter (from `.symlinks/plugins/instabug_flutter/ios`) - OCMock (= 3.6) - - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) + - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) SPEC REPOS: trunk: @@ -27,14 +28,14 @@ EXTERNAL SOURCES: instabug_flutter: :path: ".symlinks/plugins/instabug_flutter/ios" video_player_avfoundation: - :path: ".symlinks/plugins/video_player_avfoundation/ios" + :path: ".symlinks/plugins/video_player_avfoundation/darwin" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Instabug: 8eb6f63f3ac66f062025c15293549ab67150e9f9 instabug_flutter: a24751dfaedd29475da2af062d3e19d697438f72 OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 - video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff + video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 PODFILE CHECKSUM: 87a326d297554318d9004349a35d82ffe3f0c228 diff --git a/packages/instabug_flutter/example/pubspec.lock b/packages/instabug_flutter/example/pubspec.lock index 319796b95..2aaee436d 100644 --- a/packages/instabug_flutter/example/pubspec.lock +++ b/packages/instabug_flutter/example/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: csslib - sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" url: "https://pub.dev" source: hosted - version: "0.17.2" + version: "1.0.2" fake_async: dependency: transitive description: @@ -102,26 +102,26 @@ packages: dependency: transitive description: name: html - sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" url: "https://pub.dev" source: hosted - version: "0.15.1" + version: "0.15.5" http: dependency: "direct main" description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "0.13.6" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" instabug_flutter: dependency: "direct main" description: @@ -212,10 +212,10 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.8" process: dependency: transitive description: @@ -289,10 +289,10 @@ packages: dependency: transitive description: name: typed_data - sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" vector_math: dependency: transitive description: @@ -305,42 +305,42 @@ packages: dependency: "direct main" description: name: video_player - sha256: "59f7f31c919c59cbedd37c617317045f5f650dc0eeb568b0b0de9a36472bdb28" + sha256: "48941c8b05732f9582116b1c01850b74dbee1d8520cd7e34ad4609d6df666845" url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.9.3" video_player_android: dependency: transitive description: name: video_player_android - sha256: "984388511230bac63feb53b2911a70e829fe0976b6b2213f5c579c4e0a882db3" + sha256: "7018dbcb395e2bca0b9a898e73989e67c0c4a5db269528e1b036ca38bcca0d0b" url: "https://pub.dev" source: hosted - version: "2.3.10" + version: "2.7.17" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: d9f7a46d6a77680adb03ec05a381025d6e890ebe636637c6c3014cc3926b97e9 + sha256: "84b4752745eeccb6e75865c9aab39b3d28eb27ba5726d352d45db8297fbd75bc" url: "https://pub.dev" source: hosted - version: "2.3.8" + version: "2.7.0" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - sha256: "42bb75de5e9b79e1f20f1d95f688fac0f95beac4d89c6eb2cd421724d4432dae" + sha256: df534476c341ab2c6a835078066fc681b8265048addd853a1e3c78740316a844 url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.3.0" video_player_web: dependency: transitive description: name: video_player_web - sha256: b649b07b8f8f553bee4a97a0a53d0fe78a70b115eafaf0105b612b32b05ddb99 + sha256: "3ef40ea6d72434edbfdba4624b90fd3a80a0740d260667d91e7ecd2d79e13476" url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.3.4" vm_service: dependency: transitive description: @@ -349,6 +349,14 @@ packages: url: "https://pub.dev" source: hosted version: "14.3.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" webdriver: dependency: transitive description: @@ -358,5 +366,5 @@ packages: source: hosted version: "3.0.4" sdks: - dart: ">=3.4.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.6.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/packages/instabug_flutter/lib/src/modules/instabug.dart b/packages/instabug_flutter/lib/src/modules/instabug.dart index dd2065ceb..aa9e83132 100644 --- a/packages/instabug_flutter/lib/src/modules/instabug.dart +++ b/packages/instabug_flutter/lib/src/modules/instabug.dart @@ -406,10 +406,9 @@ class Instabug { /// Reports that the screen has been changed (repro steps) /// [screenName] String containing the screen name static Future reportScreenChange( - Uint8List? image, String screenName, ) async { - return _host.reportScreenChange(image, screenName); + return _host.reportScreenChange( screenName); } /// Changes the font of Instabug's UI. From 54d4655ba6c6f1cd0f0e706c4e65ce9384f19aed Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 01:26:52 +0200 Subject: [PATCH 07/16] fix test 2.10.0 --- .../instabug_flutter/lib/src/modules/instabug.dart | 2 +- .../test/utils/instabug_navigator_observer_test.dart | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/instabug_flutter/lib/src/modules/instabug.dart b/packages/instabug_flutter/lib/src/modules/instabug.dart index aa9e83132..3f9d14770 100644 --- a/packages/instabug_flutter/lib/src/modules/instabug.dart +++ b/packages/instabug_flutter/lib/src/modules/instabug.dart @@ -408,7 +408,7 @@ class Instabug { static Future reportScreenChange( String screenName, ) async { - return _host.reportScreenChange( screenName); + return _host.reportScreenChange(screenName); } /// Changes the font of Instabug's UI. diff --git a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart index e880d494c..5f138ac8f 100644 --- a/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart +++ b/packages/instabug_flutter/test/utils/instabug_navigator_observer_test.dart @@ -54,7 +54,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(null, screen), + mHost.reportScreenChange(screen), ).called(1); }); }); @@ -73,7 +73,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(null, previousScreen), + mHost.reportScreenChange(previousScreen), ).called(1); }); }); @@ -92,7 +92,7 @@ void main() { ); verifyNever( - mHost.reportScreenChange(null, any), + mHost.reportScreenChange(any), ); }); }); @@ -112,7 +112,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(null, fallback), + mHost.reportScreenChange(fallback), ).called(1); }); }); @@ -133,7 +133,7 @@ void main() { ).called(1); verify( - mHost.reportScreenChange(any, maskedScreen), + mHost.reportScreenChange(maskedScreen), ).called(1); }); }); From e5cf53fca787c3dd5959015366dd428a59bad773 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 01:45:57 +0200 Subject: [PATCH 08/16] fix test 2.10.0 --- .../lib/src/utils/instabug_navigator_observer.dart | 4 ++-- packages/instabug_flutter/pigeons/instabug.api.dart | 1 + packages/instabug_flutter/test/instabug_test.dart | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart index 0dab7fd3e..66a19630b 100644 --- a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart +++ b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart @@ -32,7 +32,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { if (IBGBuildInfo.instance.isIOS) { await Future.delayed(const Duration(milliseconds: 100)); } - Instabug.reportScreenChange(null, _steps.last.name); + Instabug.reportScreenChange(_steps.last.name); // Report the last step and remove it from the list _steps.removeLast(); @@ -46,7 +46,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { if (IBGBuildInfo.instance.isIOS) { await Future.delayed(const Duration(milliseconds: 100)); } - Instabug.reportScreenChange(null, route.name); + Instabug.reportScreenChange(route.name); _steps.remove(route); } }); diff --git a/packages/instabug_flutter/pigeons/instabug.api.dart b/packages/instabug_flutter/pigeons/instabug.api.dart index 854df229b..337f8a642 100644 --- a/packages/instabug_flutter/pigeons/instabug.api.dart +++ b/packages/instabug_flutter/pigeons/instabug.api.dart @@ -87,6 +87,7 @@ abstract class InstabugHostApi { String? crashMode, String? sessionReplayMode, ); + void reportScreenChange(String screenName); void setCustomBrandingImage(String light, String dark); diff --git a/packages/instabug_flutter/test/instabug_test.dart b/packages/instabug_flutter/test/instabug_test.dart index c20884060..1ee67a9d3 100644 --- a/packages/instabug_flutter/test/instabug_test.dart +++ b/packages/instabug_flutter/test/instabug_test.dart @@ -419,10 +419,10 @@ void main() { test('[reportScreenChange] should call host method', () async { const screen = "home"; - await Instabug.reportScreenChange(null, screen); + await Instabug.reportScreenChange(screen); verify( - mHost.reportScreenChange(null, screen), + mHost.reportScreenChange(screen), ).called(1); }); From 3d7d43cb91cd2fec9f91331f13f21529d920738c Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 01:56:00 +0200 Subject: [PATCH 09/16] fix test 2.10.0 --- .../instabug_flutter/example/lib/src/screens/my_home_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart b/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart index 98375b968..ae5d36399 100644 --- a/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart +++ b/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart @@ -60,7 +60,7 @@ class _MyHomePageState extends State { } void reportScreenChange() { - Instabug.reportScreenChange(null, screenNameController.text); + Instabug.reportScreenChange( screenNameController.text); } void sendBugReport() { From b6839209088726701ed8dd115636c6f80b183531 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 15:18:08 +0200 Subject: [PATCH 10/16] feat: enhance private view --- .../instabug_flutter/example/ios/Podfile.lock | 2 +- .../private_views_manager_test.dart | 152 ++++++++++++++++++ 2 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart diff --git a/packages/instabug_flutter/example/ios/Podfile.lock b/packages/instabug_flutter/example/ios/Podfile.lock index 6b1fb5687..4d0647f67 100644 --- a/packages/instabug_flutter/example/ios/Podfile.lock +++ b/packages/instabug_flutter/example/ios/Podfile.lock @@ -39,4 +39,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 87a326d297554318d9004349a35d82ffe3f0c228 -COCOAPODS: 1.16.2 +COCOAPODS: 1.14.3 diff --git a/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart new file mode 100644 index 000000000..2aa2a3635 --- /dev/null +++ b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart @@ -0,0 +1,152 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:instabug_flutter/instabug_flutter.dart'; +import 'package:instabug_flutter/src/utils/private_views/private_views_manager.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + WidgetsFlutterBinding.ensureInitialized(); + + group('PrivateViewsManager Tests', () { + late PrivateViewsManager manager; + + setUp(() { + manager = PrivateViewsManager.instance; + }); + + test('isPrivateWidget detects InstabugPrivateView', () { + final widget = InstabugPrivateView(child: Container()); + expect(PrivateViewsManager.isPrivateWidget(widget), isTrue); + }); + + test('isPrivateWidget detects InstabugSliverPrivateView', () { + final widget = InstabugSliverPrivateView(sliver: Container()); + expect(PrivateViewsManager.isPrivateWidget(widget), isTrue); + }); + + test('isPrivateWidget returns false for other widgets', () { + expect(PrivateViewsManager.isPrivateWidget(Container()), isFalse); + expect(PrivateViewsManager.isPrivateWidget(const Text('Hello')), isFalse); + }); + + testWidgets('getRectsOfPrivateViews detects masked views', (tester) async { + await tester.pumpWidget( + const InstabugWidget( + child: MaterialApp( + home: Scaffold( + body: Column( + children: [ + SizedBox(width: 100, height: 100), + InstabugPrivateView(child: TextField()), + ], + ), + ), + ), + ), + ); + + final rects = manager.getRectsOfPrivateViews(); + expect(rects.length, 1); + }); + + testWidgets('getRectsOfPrivateViews detects masked labels', (tester) async { + await tester.pumpWidget( + const InstabugWidget( + automasking: [AutoMasking.labels], + child: MaterialApp( + home: Scaffold( + body: Column( + children: [ + SizedBox(width: 100, height: 100), + Text("Test 1"), + Text("Test 2"), + ], + ), + ), + ), + ), + ); + + final rects = manager.getRectsOfPrivateViews(); + expect(rects.length, 2); + }); + + testWidgets( + 'getPrivateViews returns correct list of masked view coordinates', + (tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Scaffold( + body: Column( + children: [ + InstabugPrivateView( + child: SizedBox(width: 50, height: 50), + ), + ], + ), + ), + ), + ); + + final privateViews = manager.getPrivateViews(); + expect(privateViews.length % 4, + 0,); // Ensure coordinates come in sets of four + }); + + testWidgets('getRectsOfPrivateViews detects masked Media', (tester) async { + final fakeImage = Uint8List.fromList([ + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // PNG header + 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, // IHDR chunk + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, // 1x1 size + 0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, // More PNG data + 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, 0x41, + 0x54, 0x78, 0xDA, 0x63, 0x00, 0x01, 0x00, 0x00, + 0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, + ]); + await tester.pumpWidget( + InstabugWidget( + automasking: const [AutoMasking.media], + child: MaterialApp( + home: Scaffold( + body: Column( + children: [ + const SizedBox(width: 100, height: 100), + Image.memory( + fakeImage, + ), + ], + ), + ), + ), + ), + ); + + final rects = manager.getRectsOfPrivateViews(); + expect(rects.length, 1); + }); + + testWidgets('getRectsOfPrivateViews detects masked textInputs', + (tester) async { + await tester.pumpWidget( + const InstabugWidget( + automasking: [AutoMasking.textInputs], + child: MaterialApp( + home: Scaffold( + body: Column( + children: [ + SizedBox(width: 100, height: 100), + TextField(), + ], + ), + ), + ), + ), + ); + + final rects = manager.getRectsOfPrivateViews(); + expect(rects.length, 1); + }); + }); +} From 7898cc694cfcd57ee01c474ab56289d95f26c378 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 15:51:45 +0200 Subject: [PATCH 11/16] fix test --- .../example/lib/src/screens/my_home_page.dart | 2 +- .../private_views_manager_test.dart | 56 +++++++++++-------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart b/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart index ae5d36399..c3651c5c5 100644 --- a/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart +++ b/packages/instabug_flutter/example/lib/src/screens/my_home_page.dart @@ -60,7 +60,7 @@ class _MyHomePageState extends State { } void reportScreenChange() { - Instabug.reportScreenChange( screenNameController.text); + Instabug.reportScreenChange(screenNameController.text); } void sendBugReport() { diff --git a/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart index 2aa2a3635..9904ccf82 100644 --- a/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart +++ b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart @@ -1,9 +1,23 @@ +import 'dart:ui' as ui; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:instabug_flutter/src/utils/private_views/private_views_manager.dart'; +Future createTestImage() async { + // Create an empty 1x1 image + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final paint = Paint()..color = Color(0xFFFF0000); // Red pixel + canvas.drawRect(Rect.fromLTWH(0, 0, 1, 1), paint); + + final img = await recorder.endRecording().toImage(1, 1); + final byteData = await img.toByteData(format: ui.ImageByteFormat.png); + return byteData!.buffer.asUint8List(); +} + void main() { TestWidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized(); @@ -27,16 +41,16 @@ void main() { test('isPrivateWidget returns false for other widgets', () { expect(PrivateViewsManager.isPrivateWidget(Container()), isFalse); - expect(PrivateViewsManager.isPrivateWidget(const Text('Hello')), isFalse); + expect(PrivateViewsManager.isPrivateWidget(Text('Hello')), isFalse); }); testWidgets('getRectsOfPrivateViews detects masked views', (tester) async { await tester.pumpWidget( - const InstabugWidget( + InstabugWidget( child: MaterialApp( home: Scaffold( body: Column( - children: [ + children: const [ SizedBox(width: 100, height: 100), InstabugPrivateView(child: TextField()), ], @@ -52,12 +66,12 @@ void main() { testWidgets('getRectsOfPrivateViews detects masked labels', (tester) async { await tester.pumpWidget( - const InstabugWidget( - automasking: [AutoMasking.labels], + InstabugWidget( + automasking: const [AutoMasking.labels], child: MaterialApp( home: Scaffold( body: Column( - children: [ + children: const [ SizedBox(width: 100, height: 100), Text("Test 1"), Text("Test 2"), @@ -76,8 +90,8 @@ void main() { 'getPrivateViews returns correct list of masked view coordinates', (tester) async { await tester.pumpWidget( - const MaterialApp( - home: Scaffold( + MaterialApp( + home: const Scaffold( body: Column( children: [ InstabugPrivateView( @@ -90,21 +104,15 @@ void main() { ); final privateViews = manager.getPrivateViews(); - expect(privateViews.length % 4, - 0,); // Ensure coordinates come in sets of four + expect( + privateViews.length % 4, + 0, + ); // Ensure coordinates come in sets of four }); testWidgets('getRectsOfPrivateViews detects masked Media', (tester) async { - final fakeImage = Uint8List.fromList([ - 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // PNG header - 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, // IHDR chunk - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, // 1x1 size - 0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, // More PNG data - 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44, 0x41, - 0x54, 0x78, 0xDA, 0x63, 0x00, 0x01, 0x00, 0x00, - 0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00, - 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, - ]); + final validImage = await tester.runAsync(() => createTestImage()); + await tester.pumpWidget( InstabugWidget( automasking: const [AutoMasking.media], @@ -114,7 +122,7 @@ void main() { children: [ const SizedBox(width: 100, height: 100), Image.memory( - fakeImage, + validImage!, ), ], ), @@ -130,11 +138,11 @@ void main() { testWidgets('getRectsOfPrivateViews detects masked textInputs', (tester) async { await tester.pumpWidget( - const InstabugWidget( - automasking: [AutoMasking.textInputs], + InstabugWidget( + automasking: const [AutoMasking.textInputs], child: MaterialApp( home: Scaffold( - body: Column( + body: const Column( children: [ SizedBox(width: 100, height: 100), TextField(), From e234e81a94ebf6f4db541b9155538ea7dd61dcd4 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 15:56:53 +0200 Subject: [PATCH 12/16] fix test --- .../test/utils/private_views/private_views_manager_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart index 9904ccf82..ca39cd311 100644 --- a/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart +++ b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart @@ -1,3 +1,4 @@ +import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; From 1300399eaa6e5d8ee37af04a803b5c8a2b9461f8 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 16:00:56 +0200 Subject: [PATCH 13/16] fix test --- .../test/utils/private_views/private_views_manager_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart index ca39cd311..fb3910e49 100644 --- a/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart +++ b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart @@ -92,7 +92,7 @@ void main() { (tester) async { await tester.pumpWidget( MaterialApp( - home: const Scaffold( + home: Scaffold( body: Column( children: [ InstabugPrivateView( @@ -143,7 +143,7 @@ void main() { automasking: const [AutoMasking.textInputs], child: MaterialApp( home: Scaffold( - body: const Column( + body: Column( children: [ SizedBox(width: 100, height: 100), TextField(), From 011065335fadeafa93e144e6a2ad85aae7e5c71d Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 2 Mar 2025 16:13:19 +0200 Subject: [PATCH 14/16] fix test --- .../private_views_manager_test.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart index fb3910e49..ba9b1d5d7 100644 --- a/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart +++ b/packages/instabug_flutter/test/utils/private_views/private_views_manager_test.dart @@ -11,8 +11,8 @@ Future createTestImage() async { // Create an empty 1x1 image final recorder = ui.PictureRecorder(); final canvas = Canvas(recorder); - final paint = Paint()..color = Color(0xFFFF0000); // Red pixel - canvas.drawRect(Rect.fromLTWH(0, 0, 1, 1), paint); + final paint = Paint()..color = const Color(0xFFFF0000); // Red pixel + canvas.drawRect(const Rect.fromLTWH(0, 0, 1, 1), paint); final img = await recorder.endRecording().toImage(1, 1); final byteData = await img.toByteData(format: ui.ImageByteFormat.png); @@ -42,7 +42,7 @@ void main() { test('isPrivateWidget returns false for other widgets', () { expect(PrivateViewsManager.isPrivateWidget(Container()), isFalse); - expect(PrivateViewsManager.isPrivateWidget(Text('Hello')), isFalse); + expect(PrivateViewsManager.isPrivateWidget(const Text('Hello')), isFalse); }); testWidgets('getRectsOfPrivateViews detects masked views', (tester) async { @@ -50,7 +50,7 @@ void main() { InstabugWidget( child: MaterialApp( home: Scaffold( - body: Column( + body: ListView( children: const [ SizedBox(width: 100, height: 100), InstabugPrivateView(child: TextField()), @@ -71,7 +71,7 @@ void main() { automasking: const [AutoMasking.labels], child: MaterialApp( home: Scaffold( - body: Column( + body: ListView( children: const [ SizedBox(width: 100, height: 100), Text("Test 1"), @@ -93,8 +93,8 @@ void main() { await tester.pumpWidget( MaterialApp( home: Scaffold( - body: Column( - children: [ + body: ListView( + children: const [ InstabugPrivateView( child: SizedBox(width: 50, height: 50), ), @@ -143,8 +143,8 @@ void main() { automasking: const [AutoMasking.textInputs], child: MaterialApp( home: Scaffold( - body: Column( - children: [ + body: ListView( + children: const [ SizedBox(width: 100, height: 100), TextField(), ], From 2f1b94f6e1fb3bdaec5e8c66248ee01d5343236a Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Wed, 5 Mar 2025 15:17:15 +0200 Subject: [PATCH 15/16] fix test --- .../ios/Classes/Modules/PrivateViewApi.m | 2 +- .../utils/instabug_navigator_observer.dart | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m index 07edb9905..be3e988a4 100644 --- a/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m +++ b/packages/instabug_flutter/ios/Classes/Modules/PrivateViewApi.m @@ -28,10 +28,10 @@ - (void)mask:(UIImage *)screenshot completion:(void (^)(UIImage *))completion { __weak typeof(self) weakSelf = self; + // Wait for the Cupertino animation to complete dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.flutterApi getPrivateViewsWithCompletion:^(NSArray *rectangles, FlutterError *error) { UIImage *capturedScreenshot = [self captureScreenshot]; - [weakSelf handlePrivateViewsResult:rectangles error:error screenshot:capturedScreenshot diff --git a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart index 66a19630b..35d211180 100644 --- a/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart +++ b/packages/instabug_flutter/lib/src/utils/instabug_navigator_observer.dart @@ -29,11 +29,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { ScreenLoadingManager.I.startUiTrace(maskedScreenName, screenName); // If there is a step that hasn't been pushed yet if (_steps.isNotEmpty) { - if (IBGBuildInfo.instance.isIOS) { - await Future.delayed(const Duration(milliseconds: 100)); - } - Instabug.reportScreenChange(_steps.last.name); - + await reportScreenChange(_steps.last.name); // Report the last step and remove it from the list _steps.removeLast(); } @@ -43,10 +39,7 @@ class InstabugNavigatorObserver extends NavigatorObserver { // If this route is in the array, report it and remove it from the list if (_steps.contains(route)) { - if (IBGBuildInfo.instance.isIOS) { - await Future.delayed(const Duration(milliseconds: 100)); - } - Instabug.reportScreenChange(route.name); + await reportScreenChange(route.name); _steps.remove(route); } }); @@ -56,6 +49,14 @@ class InstabugNavigatorObserver extends NavigatorObserver { } } + Future reportScreenChange(String name) async { + if (IBGBuildInfo.instance.isIOS) { + // Wait for the Cupertino animation to complete + await Future.delayed(const Duration(milliseconds: 100)); + } + Instabug.reportScreenChange(name); + } + @override void didPop(Route route, Route? previousRoute) { if (previousRoute != null) { From 4bef4064473cf494e76241afbd9f184268135448 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Wed, 5 Mar 2025 16:30:46 +0200 Subject: [PATCH 16/16] fix: PR comments --- .../src/main/java/com/instabug/flutter/modules/InstabugApi.java | 2 +- .../java/com/instabug/flutter/modules/InstabugPrivateView.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java index 79904ad71..1e1617df0 100644 --- a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugApi.java @@ -155,7 +155,7 @@ public void enableAutoMasking(@NonNull List autoMasking) { autoMaskingArray[i] = ArgsRegistry.autoMasking.get(key); } - Instabug.setAutoMaskScreenshotsTypes(Arrays.copyOfRange(autoMaskingArray, 0, autoMaskingArray.length)); + Instabug.setAutoMaskScreenshotsTypes(Arrays.copyOf(autoMaskingArray, autoMaskingArray.length)); } @Override diff --git a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugPrivateView.java b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugPrivateView.java index b0a41cfcd..53ed0ac23 100644 --- a/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugPrivateView.java +++ b/packages/instabug_flutter/android/src/main/java/com/instabug/flutter/modules/InstabugPrivateView.java @@ -35,8 +35,6 @@ public void capture(CapturingCallback listener) { @Override public void run() { time = System.currentTimeMillis(); - -// time = System.currentTimeMillis(); privateViewManager.mask(listener); }