From 97d0a55d2d9abab6ad9a2bb77bcdeb95e9ed6526 Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Sun, 13 Apr 2025 15:23:49 -0400 Subject: [PATCH 01/11] progress --- README.md | 21 +- analysis_options.yaml | 2 +- example/.gitignore | 120 --- example/.metadata | 30 - example/README.md | 8 - example/analysis_options.yaml | 12 - example/android/.gitignore | 11 - example/android/app/build.gradle | 71 -- .../android/app/src/debug/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 42 - .../com/example/example/MainActivity.kt | 6 - .../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 | 16 - example/android/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.properties | 6 - example/android/settings.gradle | 24 - example/devtools_options.yaml | 3 - example/ios/.gitignore | 34 - example/ios/Flutter/AppFrameworkInfo.plist | 26 - example/ios/Flutter/Debug.xcconfig | 2 - example/ios/Flutter/Release.xcconfig | 2 - example/ios/Runner.xcodeproj/project.pbxproj | 731 --------------- .../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 - example/ios/Runner/Base.lproj/Main.storyboard | 26 - example/ios/Runner/Info.plist | 51 - example/ios/Runner/Runner-Bridging-Header.h | 1 - example/ios/RunnerTests/RunnerTests.swift | 12 - example/lib/app/app.dart | 375 -------- example/lib/app/theme.dart | 20 - example/lib/main.dart | 6 - example/pubspec.yaml | 61 -- example/test/widget_test.dart | 16 - example/web/favicon.png | Bin 917 -> 0 bytes example/web/icons/Icon-192.png | Bin 5292 -> 0 bytes example/web/icons/Icon-512.png | Bin 8252 -> 0 bytes example/web/index.html | 10 - example/web/manifest.json | 23 - lib/chewie.dart | 3 - lib/src/chewie_player.dart | 10 +- lib/src/cupertino/cupertino_controls.dart | 872 ------------------ lib/src/cupertino/cupertino_progress_bar.dart | 39 - .../widgets/cupertino_options_dialog.dart | 40 - lib/src/helpers/adaptive_controls.dart | 28 - lib/src/helpers/utils.dart | 39 +- lib/src/material/color_compat_extensions.dart | 2 +- lib/src/material/material_controls.dart | 706 -------------- .../material/material_desktop_controls.dart | 672 -------------- lib/src/material/material_progress_bar.dart | 4 +- lib/src/omni_video_controller.dart | 219 +++++ lib/src/player_with_controls.dart | 73 +- lib/src/progress_bar.dart | 146 ++- pubspec.yaml | 15 +- test/uninitialized_controls_state_test.dart | 210 ++--- 91 files changed, 451 insertions(+), 4819 deletions(-) delete mode 100644 example/.gitignore delete mode 100644 example/.metadata delete mode 100644 example/README.md delete mode 100644 example/analysis_options.yaml delete mode 100644 example/android/.gitignore delete mode 100644 example/android/app/build.gradle delete mode 100644 example/android/app/src/debug/AndroidManifest.xml delete mode 100644 example/android/app/src/main/AndroidManifest.xml delete mode 100644 example/android/app/src/main/kotlin/com/example/example/MainActivity.kt delete mode 100644 example/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 example/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/values-night/styles.xml delete mode 100644 example/android/app/src/main/res/values/styles.xml delete mode 100644 example/android/app/src/profile/AndroidManifest.xml delete mode 100644 example/android/build.gradle delete mode 100644 example/android/gradle.properties delete mode 100644 example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 example/android/settings.gradle delete mode 100644 example/devtools_options.yaml delete mode 100644 example/ios/.gitignore delete mode 100644 example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 example/ios/Flutter/Debug.xcconfig delete mode 100644 example/ios/Flutter/Release.xcconfig delete mode 100644 example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 example/ios/Runner/AppDelegate.swift delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 example/ios/Runner/Info.plist delete mode 100644 example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 example/ios/RunnerTests/RunnerTests.swift delete mode 100644 example/lib/app/app.dart delete mode 100644 example/lib/app/theme.dart delete mode 100644 example/lib/main.dart delete mode 100644 example/pubspec.yaml delete mode 100644 example/test/widget_test.dart delete mode 100644 example/web/favicon.png delete mode 100644 example/web/icons/Icon-192.png delete mode 100644 example/web/icons/Icon-512.png delete mode 100644 example/web/index.html delete mode 100644 example/web/manifest.json delete mode 100644 lib/src/cupertino/cupertino_controls.dart delete mode 100644 lib/src/cupertino/cupertino_progress_bar.dart delete mode 100644 lib/src/cupertino/widgets/cupertino_options_dialog.dart delete mode 100644 lib/src/helpers/adaptive_controls.dart delete mode 100644 lib/src/material/material_controls.dart delete mode 100644 lib/src/material/material_desktop_controls.dart create mode 100644 lib/src/omni_video_controller.dart diff --git a/README.md b/README.md index a6bcb1e4b..0d4a1c7ad 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ ![CI](https://github.com/brianegan/chewie/workflows/CI/badge.svg) [![Generic badge](https://img.shields.io/badge/platform-android%20|%20ios%20|%20web%20-blue.svg)](https://pub.dev/packages/chewie) -The video player for Flutter with a heart of gold. +The video player for Flutter with a heart of gold. -The [`video_player`](https://pub.dartlang.org/packages/video_player) plugin provides low-level -access to video playback. +The [`video_player`](https://pub.dartlang.org/packages/video_player) plugin provides low-level +access to video playback. Chewie uses the `video_player` under the hood and wraps it in a friendly Material or Cupertino UI! @@ -29,17 +29,17 @@ Chewie uses the `video_player` under the hood and wraps it in a friendly Materia ## 🚨 IMPORTANT!!! (READ THIS FIRST) -This library is __NOT__ responsible for any issues caused by `video_player`, since it's merely a UI -layer on top of it. +This library is __NOT__ responsible for any issues caused by `video_player`, since it's merely a UI +layer on top of it. In other words, if you see any `PlatformException`s being thrown in your app due to video playback, -they are exclusive to the `video_player` library. +they are exclusive to the `video_player` library. Instead, please raise an issue related to it with the [Flutter Team](https://github.com/flutter/flutter/issues/new/choose). ## 🔀 Flutter Version Compatibility -This library will at the very least make a solid effort to support the second most recent version +This library will at the very least make a solid effort to support the second most recent version of Flutter released. In other words, it will adopt `N-1` version support at the bare minimum. @@ -69,7 +69,6 @@ dependencies: ```dart import 'package:chewie/chewie.dart'; -import 'package:video_player/video_player.dart'; final videoPlayerController = VideoPlayerController.networkUrl(Uri.parse( 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4')); @@ -151,7 +150,7 @@ Your `additionalOptions` are already included here (if you provided `additionalO ### Translations -What is an option without proper translation? +What is an option without proper translation? To add your translation strings add: @@ -278,7 +277,7 @@ final playerWidget = Chewie( - [x] Custom Progress-Bar colors - [x] Custom Overlay - [x] Allow Sleep (Wakelock) -- [x] Playbackspeed Control +- [x] Playbackspeed Control - [x] Custom Route-Pagebuilder - [x] Custom Device-Orientation and SystemOverlay before and after fullscreen - [x] Custom ErrorBuilder @@ -323,7 +322,7 @@ _chewieController = ChewieController( ); ``` -## 📱 iOS warning +## 📱 iOS warning The video_player plugin used by chewie will only work in iOS simulators if you are on flutter 1.26.0 or above. You may need to switch to the beta channel `flutter channel beta` Please refer to this [issue](https://github.com/flutter/flutter/issues/14647). diff --git a/analysis_options.yaml b/analysis_options.yaml index 9f9f8bd14..ed0df0424 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -13,5 +13,5 @@ analyzer: linter: rules: close_sinks: true - sort_constructors_first: true + sort_constructors_first: false sort_pub_dependencies: false diff --git a/example/.gitignore b/example/.gitignore deleted file mode 100644 index d4fd98cf1..000000000 --- a/example/.gitignore +++ /dev/null @@ -1,120 +0,0 @@ -# Miscellaneous -*.class -*.lock -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# Visual Studio Code related -.classpath -.project -.settings/ -.vscode/ - -# Flutter repo-specific -/bin/cache/ -/bin/internal/bootstrap.bat -/bin/internal/bootstrap.sh -/bin/mingit/ -/dev/benchmarks/mega_gallery/ -/dev/bots/.recipe_deps -/dev/bots/android_tools/ -/dev/devicelab/ABresults*.json -/dev/docs/doc/ -/dev/docs/flutter.docs.zip -/dev/docs/lib/ -/dev/docs/pubspec.yaml -/dev/integration_tests/**/xcuserdata -/dev/integration_tests/**/Pods -/packages/flutter/coverage/ -version -analysis_benchmark.json - -# packages file containing multi-root paths -.packages.generated - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -**/generated_plugin_registrant.dart -.packages -.pub-cache/ -.pub/ -build/ -flutter_*.png -linked_*.ds -unlinked.ds -unlinked_spec.ds - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java -**/android/key.properties -*.jks - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/.last_build_id -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# macOS -**/macos/Flutter/GeneratedPluginRegistrant.swift -**/macos/Flutter/Flutter-Debug.xcconfig -**/macos/Flutter/Flutter-Release.xcconfig -**/macos/Flutter/Flutter-Profile.xcconfig - -# Coverage -coverage/ - -# Symbols -app.*.symbols - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -!/dev/ci/**/Gemfile.lock \ No newline at end of file diff --git a/example/.metadata b/example/.metadata deleted file mode 100644 index 5e2646bb9..000000000 --- a/example/.metadata +++ /dev/null @@ -1,30 +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: "b0850beeb25f6d5b10426284f506557f66181b36" - channel: "stable" - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: b0850beeb25f6d5b10426284f506557f66181b36 - base_revision: b0850beeb25f6d5b10426284f506557f66181b36 - - platform: ios - create_revision: b0850beeb25f6d5b10426284f506557f66181b36 - base_revision: b0850beeb25f6d5b10426284f506557f66181b36 - - # 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/example/README.md b/example/README.md deleted file mode 100644 index 9f4ba27c3..000000000 --- a/example/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Chewie Example - -An example of how to use the chewie for Flutter - -## Getting Started - -For help getting started with Flutter, view our online -[documentation](http://flutter.io/). diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml deleted file mode 100644 index 3e67ba6df..000000000 --- a/example/analysis_options.yaml +++ /dev/null @@ -1,12 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -analyzer: - language: - strict-raw-types: true - exclude: - - lib/generated_plugin_registrant.dart - -linter: - rules: - close_sinks: true - sort_constructors_first: true diff --git a/example/android/.gitignore b/example/android/.gitignore deleted file mode 100644 index 0a741cb43..000000000 --- a/example/android/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle deleted file mode 100644 index d2622405e..000000000 --- a/example/android/app/build.gradle +++ /dev/null @@ -1,71 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - id "dev.flutter.flutter-gradle-plugin" -} - - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -def keystoreProperties = new Properties() -def keystorePropertiesFile = rootProject.file('key.properties') -if (keystorePropertiesFile.exists()) { - keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) -} - -android { - namespace "com.example.example" - compileSdk 34 - - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = '17' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - applicationId "com.example.example" - minSdk 21 - targetSdk 34 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - 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 '../..' -} - -dependencies { -} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index c208884f3..000000000 --- a/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 3da38e309..000000000 --- a/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt deleted file mode 100644 index e793a000d..000000000 --- a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3f..000000000 --- a/example/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f88..000000000 --- a/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/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/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/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/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/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/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/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/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 449a9f930..000000000 --- a/example/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index d74aa35c2..000000000 --- a/example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index c208884f3..000000000 --- a/example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/example/android/build.gradle b/example/android/build.gradle deleted file mode 100644 index 37b740654..000000000 --- a/example/android/build.gradle +++ /dev/null @@ -1,16 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} \ No newline at end of file diff --git a/example/android/gradle.properties b/example/android/gradle.properties deleted file mode 100644 index 94adc3a3f..000000000 --- a/example/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 2a0fcc1b8..000000000 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle deleted file mode 100644 index 0cc6b7af9..000000000 --- a/example/android/settings.gradle +++ /dev/null @@ -1,24 +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.3.1' apply false - id 'org.jetbrains.kotlin.android' version '1.8.22' apply false -} -include ':app' \ No newline at end of file diff --git a/example/devtools_options.yaml b/example/devtools_options.yaml deleted file mode 100644 index fa0b357c4..000000000 --- a/example/devtools_options.yaml +++ /dev/null @@ -1,3 +0,0 @@ -description: This file stores settings for Dart & Flutter DevTools. -documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states -extensions: diff --git a/example/ios/.gitignore b/example/ios/.gitignore deleted file mode 100644 index 7a7f9873a..000000000 --- a/example/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 7c5696400..000000000 --- a/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/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index ec97fc6f3..000000000 --- a/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/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index c4855bfe2..000000000 --- a/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/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index ab6356343..000000000 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,731 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 5B171717BA079CE808D1B32C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73C604A80B929E096139088E /* Pods_RunnerTests.framework */; }; - 65355E45871BBAC473F56EC4 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 161F52A253A901BB69307277 /* Pods_Runner.framework */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 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 */; }; -/* 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 */ - 0EA25D90DB1772C2D6071B55 /* 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 = ""; }; - 161F52A253A901BB69307277 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 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 = ""; }; - 6AEFCF184013ED5CA996B82B /* 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 = ""; }; - 6D5C22CEED22C7791375B03E /* 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 = ""; }; - 73C604A80B929E096139088E /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 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 = ""; }; - 75018BE4F219FC27188BF5C2 /* 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 = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 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 = ""; }; - CCE42FB5D8CBF00852B83E23 /* 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 = ""; }; - D9EB2FAA5097BC9A403E4AC5 /* 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 = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 65355E45871BBAC473F56EC4 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - ADF676FEC51290FAF51E0789 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 5B171717BA079CE808D1B32C /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 07E76744EA73A063120BFE5C /* Pods */ = { - isa = PBXGroup; - children = ( - D9EB2FAA5097BC9A403E4AC5 /* Pods-Runner.debug.xcconfig */, - 6AEFCF184013ED5CA996B82B /* Pods-Runner.release.xcconfig */, - 0EA25D90DB1772C2D6071B55 /* Pods-Runner.profile.xcconfig */, - CCE42FB5D8CBF00852B83E23 /* Pods-RunnerTests.debug.xcconfig */, - 75018BE4F219FC27188BF5C2 /* Pods-RunnerTests.release.xcconfig */, - 6D5C22CEED22C7791375B03E /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 22109C890749BA0B4E7C88B0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 161F52A253A901BB69307277 /* Pods_Runner.framework */, - 73C604A80B929E096139088E /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - 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 */, - 07E76744EA73A063120BFE5C /* Pods */, - 22109C890749BA0B4E7C88B0 /* 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 = ( - 3FADDB6B4D6AA8657115BAF4 /* [CP] Check Pods Manifest.lock */, - 331C807D294A63A400263BE5 /* Sources */, - 331C807F294A63A400263BE5 /* Resources */, - ADF676FEC51290FAF51E0789 /* 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 = ( - 6B3BB5498CBA14DCD8E20CF8 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 2261669A503474CE180D7658 /* [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; - 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 */ - 2261669A503474CE180D7658 /* [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; - }; - 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"; - }; - 3FADDB6B4D6AA8657115BAF4 /* [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; - }; - 6B3BB5498CBA14DCD8E20CF8 /* [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; - }; - 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"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C807D294A63A400263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C808B294A63AB00263BE5 /* RunnerTests.swift 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 = K4NVK382X5; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.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 = CCE42FB5D8CBF00852B83E23 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - 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 = 75018BE4F219FC27188BF5C2 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Release; - }; - 331C808A294A63A400263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 6D5C22CEED22C7791375B03E /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - 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 = K4NVK382X5; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.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 = K4NVK382X5; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.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/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5e..000000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 8e3ca5dfe..000000000 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14c..000000000 --- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5e..000000000 --- a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 626664468..000000000 --- a/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab2..000000000 --- a/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/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/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/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 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/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/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2fd..000000000 --- a/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/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/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/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/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/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/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/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/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/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7c..000000000 --- a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516f..000000000 --- a/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist deleted file mode 100644 index 7f553465b..000000000 --- a/example/ios/Runner/Info.plist +++ /dev/null @@ -1,51 +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 - - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a560..000000000 --- a/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/example/ios/RunnerTests/RunnerTests.swift b/example/ios/RunnerTests/RunnerTests.swift deleted file mode 100644 index 86a7c3b1b..000000000 --- a/example/ios/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Flutter -import UIKit -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/example/lib/app/app.dart b/example/lib/app/app.dart deleted file mode 100644 index 6d58f29f6..000000000 --- a/example/lib/app/app.dart +++ /dev/null @@ -1,375 +0,0 @@ - -import 'package:chewie/chewie.dart'; -import 'package:chewie_example/app/theme.dart'; -import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; - -class ChewieDemo extends StatefulWidget { - const ChewieDemo({super.key, this.title = 'Chewie Demo'}); - - final String title; - - @override - State createState() { - return _ChewieDemoState(); - } -} - -class _ChewieDemoState extends State { - TargetPlatform? _platform; - late VideoPlayerController _videoPlayerController1; - late VideoPlayerController _videoPlayerController2; - ChewieController? _chewieController; - int? bufferDelay; - - @override - void initState() { - super.initState(); - initializePlayer(); - } - - @override - void dispose() { - _videoPlayerController1.dispose(); - _videoPlayerController2.dispose(); - _chewieController?.dispose(); - super.dispose(); - } - - List srcs = [ - "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4", - "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4", - "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4", - ]; - - Future initializePlayer() async { - _videoPlayerController1 = VideoPlayerController.networkUrl( - Uri.parse(srcs[currPlayIndex]), - ); - _videoPlayerController2 = VideoPlayerController.networkUrl( - Uri.parse(srcs[currPlayIndex]), - ); - await Future.wait([ - _videoPlayerController1.initialize(), - _videoPlayerController2.initialize(), - ]); - _createChewieController(); - setState(() {}); - } - - void _createChewieController() { - // final subtitles = [ - // Subtitle( - // index: 0, - // start: Duration.zero, - // end: const Duration(seconds: 10), - // text: 'Hello from subtitles', - // ), - // Subtitle( - // index: 0, - // start: const Duration(seconds: 10), - // end: const Duration(seconds: 20), - // text: 'Whats up? :)', - // ), - // ]; - - final subtitles = [ - Subtitle( - index: 0, - start: Duration.zero, - end: const Duration(seconds: 10), - text: const TextSpan( - children: [ - TextSpan( - text: 'Hello', - style: TextStyle(color: Colors.red, fontSize: 22), - ), - TextSpan( - text: ' from ', - style: TextStyle(color: Colors.green, fontSize: 20), - ), - TextSpan( - text: 'subtitles', - style: TextStyle(color: Colors.blue, fontSize: 18), - ), - ], - ), - ), - Subtitle( - index: 0, - start: const Duration(seconds: 10), - end: const Duration(seconds: 20), - text: 'Whats up? :)', - // text: const TextSpan( - // text: 'Whats up? :)', - // style: TextStyle(color: Colors.amber, fontSize: 22, fontStyle: FontStyle.italic), - // ), - ), - ]; - - _chewieController = ChewieController( - videoPlayerController: _videoPlayerController1, - autoPlay: true, - looping: true, - progressIndicatorDelay: - bufferDelay != null ? Duration(milliseconds: bufferDelay!) : null, - - additionalOptions: (context) { - return [ - OptionItem( - onTap: (context) => toggleVideo(), - iconData: Icons.live_tv_sharp, - title: 'Toggle Video Src', - ), - ]; - }, - subtitle: Subtitles(subtitles), - showSubtitles: true, - subtitleBuilder: (context, dynamic subtitle) => Container( - padding: const EdgeInsets.all(10.0), - child: subtitle is InlineSpan - ? RichText(text: subtitle) - : Text( - subtitle.toString(), - style: const TextStyle(color: Colors.black), - ), - ), - - hideControlsTimer: const Duration(seconds: 1), - - // Try playing around with some of these other options: - - // showControls: false, - // materialProgressColors: ChewieProgressColors( - // playedColor: Colors.red, - // handleColor: Colors.blue, - // backgroundColor: Colors.grey, - // bufferedColor: Colors.lightGreen, - // ), - // placeholder: Container( - // color: Colors.grey, - // ), - // autoInitialize: true, - ); - } - - int currPlayIndex = 0; - - Future toggleVideo() async { - await _videoPlayerController1.pause(); - currPlayIndex += 1; - if (currPlayIndex >= srcs.length) { - currPlayIndex = 0; - } - await initializePlayer(); - } - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: widget.title, - theme: AppTheme.light.copyWith( - platform: _platform ?? Theme.of(context).platform, - ), - home: Scaffold( - appBar: AppBar(title: Text(widget.title)), - body: Column( - children: [ - Expanded( - child: Center( - child: _chewieController != null && - _chewieController! - .videoPlayerController.value.isInitialized - ? Chewie(controller: _chewieController!) - : const Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CircularProgressIndicator(), - SizedBox(height: 20), - Text('Loading'), - ], - ), - ), - ), - TextButton( - onPressed: () { - _chewieController?.enterFullScreen(); - }, - child: const Text('Fullscreen'), - ), - Row( - children: [ - Expanded( - child: TextButton( - onPressed: () { - setState(() { - _videoPlayerController1.pause(); - _videoPlayerController1.seekTo(Duration.zero); - _createChewieController(); - }); - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("Landscape Video"), - ), - ), - ), - Expanded( - child: TextButton( - onPressed: () { - setState(() { - _videoPlayerController2.pause(); - _videoPlayerController2.seekTo(Duration.zero); - _chewieController = _chewieController!.copyWith( - videoPlayerController: _videoPlayerController2, - autoPlay: true, - looping: true, - /* subtitle: Subtitles([ - Subtitle( - index: 0, - start: Duration.zero, - end: const Duration(seconds: 10), - text: 'Hello from subtitles', - ), - Subtitle( - index: 0, - start: const Duration(seconds: 10), - end: const Duration(seconds: 20), - text: 'Whats up? :)', - ), - ]), - subtitleBuilder: (context, subtitle) => Container( - padding: const EdgeInsets.all(10.0), - child: Text( - subtitle, - style: const TextStyle(color: Colors.white), - ), - ), */ - ); - }); - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("Portrait Video"), - ), - ), - ), - ], - ), - Row( - children: [ - Expanded( - child: TextButton( - onPressed: () { - setState(() { - _platform = TargetPlatform.android; - }); - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("Android controls"), - ), - ), - ), - Expanded( - child: TextButton( - onPressed: () { - setState(() { - _platform = TargetPlatform.iOS; - }); - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("iOS controls"), - ), - ), - ), - ], - ), - Row( - children: [ - Expanded( - child: TextButton( - onPressed: () { - setState(() { - _platform = TargetPlatform.windows; - }); - }, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16.0), - child: Text("Desktop controls"), - ), - ), - ), - ], - ), - if (Theme.of(context).platform == TargetPlatform.android) - ListTile( - title: const Text("Delay"), - subtitle: DelaySlider( - delay: - _chewieController?.progressIndicatorDelay?.inMilliseconds, - onSave: (delay) async { - if (delay != null) { - bufferDelay = delay == 0 ? null : delay; - await initializePlayer(); - } - }, - ), - ), - ], - ), - ), - ); - } -} - -class DelaySlider extends StatefulWidget { - const DelaySlider({super.key, required this.delay, required this.onSave}); - - final int? delay; - final void Function(int?) onSave; - @override - State createState() => _DelaySliderState(); -} - -class _DelaySliderState extends State { - int? delay; - bool saved = false; - - @override - void initState() { - super.initState(); - delay = widget.delay; - } - - @override - Widget build(BuildContext context) { - const int max = 1000; - return ListTile( - title: Text( - "Progress indicator delay ${delay != null ? "${delay.toString()} MS" : ""}", - ), - subtitle: Slider( - value: delay != null ? (delay! / max) : 0, - onChanged: (value) async { - delay = (value * max).toInt(); - setState(() { - saved = false; - }); - }, - ), - trailing: IconButton( - icon: const Icon(Icons.save), - onPressed: saved - ? null - : () { - widget.onSave(delay); - setState(() { - saved = true; - }); - }, - ), - ); - } -} diff --git a/example/lib/app/theme.dart b/example/lib/app/theme.dart deleted file mode 100644 index 41ac7e4d0..000000000 --- a/example/lib/app/theme.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:flutter/material.dart'; - -// ignore: avoid_classes_with_only_static_members -class AppTheme { - static final light = ThemeData( - brightness: Brightness.light, - useMaterial3: true, - colorScheme: const ColorScheme.light(secondary: Colors.red), - disabledColor: Colors.grey.shade400, - visualDensity: VisualDensity.adaptivePlatformDensity, - ); - - static final dark = ThemeData( - brightness: Brightness.dark, - colorScheme: const ColorScheme.dark(secondary: Colors.red), - disabledColor: Colors.grey.shade400, - useMaterial3: true, - visualDensity: VisualDensity.adaptivePlatformDensity, - ); -} diff --git a/example/lib/main.dart b/example/lib/main.dart deleted file mode 100644 index 496728a63..000000000 --- a/example/lib/main.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:chewie_example/app/app.dart'; -import 'package:flutter/material.dart'; - -void main() { - runApp(const ChewieDemo()); -} diff --git a/example/pubspec.yaml b/example/pubspec.yaml deleted file mode 100644 index be412fe2a..000000000 --- a/example/pubspec.yaml +++ /dev/null @@ -1,61 +0,0 @@ -name: chewie_example -description: An example of how to use the chewie for Flutter -version: 1.0.0 -publish_to: none - -environment: - sdk: '>=3.6.0 <4.0.0' - flutter: ">=3.27.0" - -dependencies: - chewie: - path: ../ - flutter: - sdk: flutter - video_player: ^2.9.3 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^5.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec - -# The following section is specific to Flutter. -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: - # - 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.io/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.io/assets-and-images/#from-packages - - # 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.io/custom-fonts/#from-packages diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart deleted file mode 100644 index 922999316..000000000 --- a/example/test/widget_test.dart +++ /dev/null @@ -1,16 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:chewie_example/app/app.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const ChewieDemo()); - }); -} diff --git a/example/web/favicon.png b/example/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 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 diff --git a/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/example/web/index.html b/example/web/index.html deleted file mode 100644 index 6eff9a740..000000000 --- a/example/web/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - example - - - - - diff --git a/example/web/manifest.json b/example/web/manifest.json deleted file mode 100644 index 8c012917d..000000000 --- a/example/web/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "example", - "short_name": "example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} diff --git a/lib/chewie.dart b/lib/chewie.dart index 7061505ad..43aea3944 100644 --- a/lib/chewie.dart +++ b/lib/chewie.dart @@ -2,8 +2,5 @@ library; export 'src/chewie_player.dart'; export 'src/chewie_progress_colors.dart'; -export 'src/cupertino/cupertino_controls.dart'; -export 'src/material/material_controls.dart'; -export 'src/material/material_desktop_controls.dart'; export 'src/material/material_progress_bar.dart'; export 'src/models/index.dart'; diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index 5d76fdf6d..3833e78b5 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -5,12 +5,12 @@ import 'package:chewie/src/models/option_item.dart'; import 'package:chewie/src/models/options_translation.dart'; import 'package:chewie/src/models/subtitle_model.dart'; import 'package:chewie/src/notifiers/player_notifier.dart'; +import 'package:chewie/src/omni_video_controller.dart'; import 'package:chewie/src/player_with_controls.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; -import 'package:video_player/video_player.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; typedef ChewieRoutePageBuilder = Widget Function( @@ -290,7 +290,7 @@ class ChewieController extends ChangeNotifier { this.subtitle, this.showSubtitles = false, this.subtitleBuilder, - this.customControls, + required this.customControls, this.errorBuilder, this.bufferingBuilder, this.allowedScreenSleep = true, @@ -317,7 +317,7 @@ class ChewieController extends ChangeNotifier { } ChewieController copyWith({ - VideoPlayerController? videoPlayerController, + OmniVideoController? videoPlayerController, OptionsTranslation? optionsTranslation, double? aspectRatio, bool? autoInitialize, @@ -467,7 +467,7 @@ class ChewieController extends ChangeNotifier { bool showSubtitles; /// The controller for the video you want to play - final VideoPlayerController videoPlayerController; + final OmniVideoController videoPlayerController; /// Initialize the Video on Startup. This will prep the video for playback. final bool autoInitialize; @@ -501,7 +501,7 @@ class ChewieController extends ChangeNotifier { /// Defines customised controls. Check [MaterialControls] or /// [CupertinoControls] for reference. - final Widget? customControls; + final Widget customControls; /// When the video playback runs into an error, you can build a custom /// error message. diff --git a/lib/src/cupertino/cupertino_controls.dart b/lib/src/cupertino/cupertino_controls.dart deleted file mode 100644 index b0488a275..000000000 --- a/lib/src/cupertino/cupertino_controls.dart +++ /dev/null @@ -1,872 +0,0 @@ -import 'dart:async'; -import 'dart:math' as math; -import 'dart:ui' as ui; - -import 'package:chewie/src/animated_play_pause.dart'; -import 'package:chewie/src/center_play_button.dart'; -import 'package:chewie/src/chewie_player.dart'; -import 'package:chewie/src/chewie_progress_colors.dart'; -import 'package:chewie/src/cupertino/cupertino_progress_bar.dart'; -import 'package:chewie/src/cupertino/widgets/cupertino_options_dialog.dart'; -import 'package:chewie/src/helpers/utils.dart'; -import 'package:chewie/src/models/option_item.dart'; -import 'package:chewie/src/models/subtitle_model.dart'; -import 'package:chewie/src/notifiers/index.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:video_player/video_player.dart'; - -class CupertinoControls extends StatefulWidget { - const CupertinoControls({ - required this.backgroundColor, - required this.iconColor, - this.showPlayButton = true, - super.key, - }); - - final Color backgroundColor; - final Color iconColor; - final bool showPlayButton; - - @override - State createState() { - return _CupertinoControlsState(); - } -} - -class _CupertinoControlsState extends State - with SingleTickerProviderStateMixin { - late PlayerNotifier notifier; - late VideoPlayerValue _latestValue; - double? _latestVolume; - Timer? _hideTimer; - final marginSize = 5.0; - Timer? _expandCollapseTimer; - Timer? _initTimer; - bool _dragging = false; - Duration? _subtitlesPosition; - bool _subtitleOn = false; - Timer? _bufferingDisplayTimer; - bool _displayBufferingIndicator = false; - double selectedSpeed = 1.0; - late VideoPlayerController controller; - - // We know that _chewieController is set in didChangeDependencies - ChewieController get chewieController => _chewieController!; - ChewieController? _chewieController; - - @override - void initState() { - super.initState(); - notifier = Provider.of(context, listen: false); - } - - @override - Widget build(BuildContext context) { - if (_latestValue.hasError) { - return chewieController.errorBuilder != null - ? chewieController.errorBuilder!( - context, - chewieController.videoPlayerController.value.errorDescription!, - ) - : const Center( - child: Icon( - CupertinoIcons.exclamationmark_circle, - color: Colors.white, - size: 42, - ), - ); - } - - final backgroundColor = widget.backgroundColor; - final iconColor = widget.iconColor; - final orientation = MediaQuery.of(context).orientation; - final barHeight = orientation == Orientation.portrait ? 30.0 : 47.0; - final buttonPadding = orientation == Orientation.portrait ? 16.0 : 24.0; - - return MouseRegion( - onHover: (_) => _cancelAndRestartTimer(), - child: GestureDetector( - onTap: () => _cancelAndRestartTimer(), - child: AbsorbPointer( - absorbing: notifier.hideStuff, - child: Stack( - children: [ - if (_displayBufferingIndicator) - _chewieController?.bufferingBuilder?.call(context) ?? - const Center( - child: CircularProgressIndicator(), - ) - else - _buildHitArea(), - Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _buildTopBar( - backgroundColor, - iconColor, - barHeight, - buttonPadding, - ), - const Spacer(), - if (_subtitleOn) - Transform.translate( - offset: Offset( - 0.0, - notifier.hideStuff ? barHeight * 0.8 : 0.0, - ), - child: _buildSubtitles(chewieController.subtitle!), - ), - _buildBottomBar(backgroundColor, iconColor, barHeight), - ], - ), - ], - ), - ), - ), - ); - } - - @override - void dispose() { - _dispose(); - super.dispose(); - } - - void _dispose() { - controller.removeListener(_updateState); - _hideTimer?.cancel(); - _expandCollapseTimer?.cancel(); - _initTimer?.cancel(); - } - - @override - void didChangeDependencies() { - final oldController = _chewieController; - _chewieController = ChewieController.of(context); - controller = chewieController.videoPlayerController; - - if (oldController != chewieController) { - _dispose(); - _initialize(); - } - - super.didChangeDependencies(); - } - - GestureDetector _buildOptionsButton( - Color iconColor, - double barHeight, - ) { - final options = []; - - if (chewieController.additionalOptions != null && - chewieController.additionalOptions!(context).isNotEmpty) { - options.addAll(chewieController.additionalOptions!(context)); - } - - return GestureDetector( - onTap: () async { - _hideTimer?.cancel(); - - if (chewieController.optionsBuilder != null) { - await chewieController.optionsBuilder!(context, options); - } else { - await showCupertinoModalPopup( - context: context, - semanticsDismissible: true, - useRootNavigator: chewieController.useRootNavigator, - builder: (context) => CupertinoOptionsDialog( - options: options, - cancelButtonText: - chewieController.optionsTranslation?.cancelButtonText, - ), - ); - if (_latestValue.isPlaying) { - _startHideTimer(); - } - } - }, - child: Container( - height: barHeight, - color: Colors.transparent, - padding: const EdgeInsets.only(left: 4.0, right: 8.0), - margin: const EdgeInsets.only(right: 6.0), - child: Icon( - Icons.more_vert, - color: iconColor, - size: 18, - ), - ), - ); - } - - Widget _buildSubtitles(Subtitles subtitles) { - if (!_subtitleOn) { - return const SizedBox(); - } - if (_subtitlesPosition == null) { - return const SizedBox(); - } - final currentSubtitle = subtitles.getByPosition(_subtitlesPosition!); - if (currentSubtitle.isEmpty) { - return const SizedBox(); - } - - if (chewieController.subtitleBuilder != null) { - return chewieController.subtitleBuilder!( - context, - currentSubtitle.first!.text, - ); - } - - return Padding( - padding: EdgeInsets.only(left: marginSize, right: marginSize), - child: Container( - padding: const EdgeInsets.all(5), - decoration: BoxDecoration( - color: const Color(0x96000000), - borderRadius: BorderRadius.circular(10.0), - ), - child: Text( - currentSubtitle.first!.text.toString(), - style: const TextStyle( - fontSize: 18, - ), - textAlign: TextAlign.center, - ), - ), - ); - } - - Widget _buildBottomBar( - Color backgroundColor, - Color iconColor, - double barHeight, - ) { - return SafeArea( - bottom: chewieController.isFullScreen, - minimum: chewieController.controlsSafeAreaMinimum, - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 300), - child: Container( - color: Colors.transparent, - alignment: Alignment.bottomCenter, - margin: EdgeInsets.all(marginSize), - child: ClipRRect( - borderRadius: BorderRadius.circular(10.0), - child: BackdropFilter( - filter: ui.ImageFilter.blur( - sigmaX: 10.0, - sigmaY: 10.0, - ), - child: Container( - height: barHeight, - color: backgroundColor, - child: chewieController.isLive - ? Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _buildPlayPause(controller, iconColor, barHeight), - _buildLive(iconColor), - ], - ) - : Row( - children: [ - _buildSkipBack(iconColor, barHeight), - _buildPlayPause(controller, iconColor, barHeight), - _buildSkipForward(iconColor, barHeight), - _buildPosition(iconColor), - _buildProgressBar(), - _buildRemaining(iconColor), - _buildSubtitleToggle(iconColor, barHeight), - if (chewieController.allowPlaybackSpeedChanging) - _buildSpeedButton(controller, iconColor, barHeight), - if (chewieController.additionalOptions != null && - chewieController - .additionalOptions!(context).isNotEmpty) - _buildOptionsButton(iconColor, barHeight), - ], - ), - ), - ), - ), - ), - ), - ); - } - - Widget _buildLive(Color iconColor) { - return Padding( - padding: const EdgeInsets.only(right: 12.0), - child: Text( - 'LIVE', - style: TextStyle(color: iconColor, fontSize: 12.0), - ), - ); - } - - GestureDetector _buildExpandButton( - Color backgroundColor, - Color iconColor, - double barHeight, - double buttonPadding, - ) { - return GestureDetector( - onTap: _onExpandCollapse, - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 300), - child: ClipRRect( - borderRadius: BorderRadius.circular(10.0), - child: BackdropFilter( - filter: ui.ImageFilter.blur(sigmaX: 10.0), - child: Container( - height: barHeight, - padding: EdgeInsets.only( - left: buttonPadding, - right: buttonPadding, - ), - color: backgroundColor, - child: Center( - child: Icon( - chewieController.isFullScreen - ? CupertinoIcons.arrow_down_right_arrow_up_left - : CupertinoIcons.arrow_up_left_arrow_down_right, - color: iconColor, - size: 16, - ), - ), - ), - ), - ), - ), - ); - } - - Widget _buildHitArea() { - final bool isFinished = (_latestValue.position >= _latestValue.duration) && - _latestValue.duration.inSeconds > 0; - final bool showPlayButton = - widget.showPlayButton && !_latestValue.isPlaying && !_dragging; - - return GestureDetector( - onTap: _latestValue.isPlaying - ? _chewieController?.pauseOnBackgroundTap ?? false - ? () { - _playPause(); - - setState(() { - notifier.hideStuff = true; - }); - } - : _cancelAndRestartTimer - : () { - _hideTimer?.cancel(); - - setState(() { - notifier.hideStuff = false; - }); - }, - child: CenterPlayButton( - backgroundColor: widget.backgroundColor, - iconColor: widget.iconColor, - isFinished: isFinished, - isPlaying: controller.value.isPlaying, - show: showPlayButton, - onPressed: _playPause, - ), - ); - } - - GestureDetector _buildMuteButton( - VideoPlayerController controller, - Color backgroundColor, - Color iconColor, - double barHeight, - double buttonPadding, - ) { - return GestureDetector( - onTap: () { - _cancelAndRestartTimer(); - - if (_latestValue.volume == 0) { - controller.setVolume(_latestVolume ?? 0.5); - } else { - _latestVolume = controller.value.volume; - controller.setVolume(0.0); - } - }, - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 300), - child: ClipRRect( - borderRadius: BorderRadius.circular(10.0), - child: BackdropFilter( - filter: ui.ImageFilter.blur(sigmaX: 10.0), - child: ColoredBox( - color: backgroundColor, - child: Container( - height: barHeight, - padding: EdgeInsets.only( - left: buttonPadding, - right: buttonPadding, - ), - child: Icon( - _latestValue.volume > 0 ? Icons.volume_up : Icons.volume_off, - color: iconColor, - size: 16, - ), - ), - ), - ), - ), - ), - ); - } - - GestureDetector _buildPlayPause( - VideoPlayerController controller, - Color iconColor, - double barHeight, - ) { - return GestureDetector( - onTap: _playPause, - child: Container( - height: barHeight, - color: Colors.transparent, - padding: const EdgeInsets.only( - left: 6.0, - right: 6.0, - ), - child: AnimatedPlayPause( - color: widget.iconColor, - playing: controller.value.isPlaying, - ), - ), - ); - } - - Widget _buildPosition(Color iconColor) { - final position = _latestValue.position; - - return Padding( - padding: const EdgeInsets.only(right: 12.0), - child: Text( - formatDuration(position), - style: TextStyle( - color: iconColor, - fontSize: 12.0, - ), - ), - ); - } - - Widget _buildRemaining(Color iconColor) { - final position = _latestValue.duration - _latestValue.position; - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: Text( - '-${formatDuration(position)}', - style: TextStyle(color: iconColor, fontSize: 12.0), - ), - ); - } - - Widget _buildSubtitleToggle(Color iconColor, double barHeight) { - //if don't have subtitle hiden button - if (chewieController.subtitle?.isEmpty ?? true) { - return const SizedBox(); - } - return GestureDetector( - onTap: _subtitleToggle, - child: Container( - height: barHeight, - color: Colors.transparent, - margin: const EdgeInsets.only(right: 10.0), - padding: const EdgeInsets.only( - left: 6.0, - right: 6.0, - ), - child: Icon( - Icons.subtitles, - color: _subtitleOn ? iconColor : Colors.grey[700], - size: 16.0, - ), - ), - ); - } - - void _subtitleToggle() { - setState(() { - _subtitleOn = !_subtitleOn; - }); - } - - GestureDetector _buildSkipBack(Color iconColor, double barHeight) { - return GestureDetector( - onTap: _skipBack, - child: Container( - height: barHeight, - color: Colors.transparent, - margin: const EdgeInsets.only(left: 10.0), - padding: const EdgeInsets.only( - left: 6.0, - right: 6.0, - ), - child: Icon( - CupertinoIcons.gobackward_15, - color: iconColor, - size: 18.0, - ), - ), - ); - } - - GestureDetector _buildSkipForward(Color iconColor, double barHeight) { - return GestureDetector( - onTap: _skipForward, - child: Container( - height: barHeight, - color: Colors.transparent, - padding: const EdgeInsets.only( - left: 6.0, - right: 8.0, - ), - margin: const EdgeInsets.only( - right: 8.0, - ), - child: Icon( - CupertinoIcons.goforward_15, - color: iconColor, - size: 18.0, - ), - ), - ); - } - - GestureDetector _buildSpeedButton( - VideoPlayerController controller, - Color iconColor, - double barHeight, - ) { - return GestureDetector( - onTap: () async { - _hideTimer?.cancel(); - - final chosenSpeed = await showCupertinoModalPopup( - context: context, - semanticsDismissible: true, - useRootNavigator: chewieController.useRootNavigator, - builder: (context) => _PlaybackSpeedDialog( - speeds: chewieController.playbackSpeeds, - selected: _latestValue.playbackSpeed, - ), - ); - - if (chosenSpeed != null) { - controller.setPlaybackSpeed(chosenSpeed); - - selectedSpeed = chosenSpeed; - } - - if (_latestValue.isPlaying) { - _startHideTimer(); - } - }, - child: Container( - height: barHeight, - color: Colors.transparent, - padding: const EdgeInsets.only( - left: 6.0, - right: 8.0, - ), - margin: const EdgeInsets.only( - right: 8.0, - ), - child: Transform( - alignment: Alignment.center, - transform: Matrix4.skewY(0.0) - ..rotateX(math.pi) - ..rotateZ(math.pi * 0.8), - child: Icon( - Icons.speed, - color: iconColor, - size: 18.0, - ), - ), - ), - ); - } - - Widget _buildTopBar( - Color backgroundColor, - Color iconColor, - double barHeight, - double buttonPadding, - ) { - return Container( - height: barHeight, - margin: EdgeInsets.only( - top: marginSize, - right: marginSize, - left: marginSize, - ), - child: Row( - children: [ - if (chewieController.allowFullScreen) - _buildExpandButton( - backgroundColor, - iconColor, - barHeight, - buttonPadding, - ), - const Spacer(), - if (chewieController.allowMuting) - _buildMuteButton( - controller, - backgroundColor, - iconColor, - barHeight, - buttonPadding, - ), - ], - ), - ); - } - - void _cancelAndRestartTimer() { - _hideTimer?.cancel(); - - setState(() { - notifier.hideStuff = false; - - _startHideTimer(); - }); - } - - Future _initialize() async { - chewieController.showSubtitles && - (chewieController.subtitle?.isNotEmpty ?? false); - controller.addListener(_updateState); - - _updateState(); - - if (controller.value.isPlaying || chewieController.autoPlay) { - _startHideTimer(); - } - - if (chewieController.showControlsOnInitialize) { - _initTimer = Timer(const Duration(milliseconds: 200), () { - setState(() { - notifier.hideStuff = false; - }); - }); - } - } - - void _onExpandCollapse() { - setState(() { - notifier.hideStuff = true; - - chewieController.toggleFullScreen(); - _expandCollapseTimer = Timer(const Duration(milliseconds: 300), () { - setState(() { - _cancelAndRestartTimer(); - }); - }); - }); - } - - Widget _buildProgressBar() { - return Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 12.0), - child: CupertinoVideoProgressBar( - controller, - onDragStart: () { - setState(() { - _dragging = true; - }); - - _hideTimer?.cancel(); - }, - onDragUpdate: () { - _hideTimer?.cancel(); - }, - onDragEnd: () { - setState(() { - _dragging = false; - }); - - _startHideTimer(); - }, - colors: chewieController.cupertinoProgressColors ?? - ChewieProgressColors( - playedColor: const Color.fromARGB( - 120, - 255, - 255, - 255, - ), - handleColor: const Color.fromARGB( - 255, - 255, - 255, - 255, - ), - bufferedColor: const Color.fromARGB( - 60, - 255, - 255, - 255, - ), - backgroundColor: const Color.fromARGB( - 20, - 255, - 255, - 255, - ), - ), - draggableProgressBar: chewieController.draggableProgressBar, - ), - ), - ); - } - - void _playPause() { - final isFinished = _latestValue.position >= _latestValue.duration && - _latestValue.duration.inSeconds > 0; - - setState(() { - if (controller.value.isPlaying) { - notifier.hideStuff = false; - _hideTimer?.cancel(); - controller.pause(); - } else { - _cancelAndRestartTimer(); - - if (!controller.value.isInitialized) { - controller.initialize().then((_) { - controller.play(); - }); - } else { - if (isFinished) { - controller.seekTo(Duration.zero); - } - controller.play(); - } - } - }); - } - - Future _skipBack() async { - _cancelAndRestartTimer(); - final beginning = Duration.zero.inMilliseconds; - final skip = - (_latestValue.position - const Duration(seconds: 15)).inMilliseconds; - await controller.seekTo(Duration(milliseconds: math.max(skip, beginning))); - // Restoring the video speed to selected speed - // A delay of 1 second is added to ensure a smooth transition of speed after reversing the video as reversing is an asynchronous function - Future.delayed(const Duration(milliseconds: 1000), () { - controller.setPlaybackSpeed(selectedSpeed); - }); - } - - Future _skipForward() async { - _cancelAndRestartTimer(); - final end = _latestValue.duration.inMilliseconds; - final skip = - (_latestValue.position + const Duration(seconds: 15)).inMilliseconds; - await controller.seekTo(Duration(milliseconds: math.min(skip, end))); - // Restoring the video speed to selected speed - // A delay of 1 second is added to ensure a smooth transition of speed after forwarding the video as forwaring is an asynchronous function - Future.delayed(const Duration(milliseconds: 1000), () { - controller.setPlaybackSpeed(selectedSpeed); - }); - } - - void _startHideTimer() { - final hideControlsTimer = chewieController.hideControlsTimer.isNegative - ? ChewieController.defaultHideControlsTimer - : chewieController.hideControlsTimer; - _hideTimer = Timer(hideControlsTimer, () { - setState(() { - notifier.hideStuff = true; - }); - }); - } - - void _bufferingTimerTimeout() { - _displayBufferingIndicator = true; - if (mounted) { - setState(() {}); - } - } - - void _updateState() { - if (!mounted) return; - - final bool buffering = getIsBuffering(controller); - - // display the progress bar indicator only after the buffering delay if it has been set - if (chewieController.progressIndicatorDelay != null) { - if (buffering) { - _bufferingDisplayTimer ??= Timer( - chewieController.progressIndicatorDelay!, - _bufferingTimerTimeout, - ); - } else { - _bufferingDisplayTimer?.cancel(); - _bufferingDisplayTimer = null; - _displayBufferingIndicator = false; - } - } else { - _displayBufferingIndicator = buffering; - } - - setState(() { - _latestValue = controller.value; - _subtitlesPosition = controller.value.position; - }); - } -} - -class _PlaybackSpeedDialog extends StatelessWidget { - const _PlaybackSpeedDialog({ - required List speeds, - required double selected, - }) : _speeds = speeds, - _selected = selected; - - final List _speeds; - final double _selected; - - @override - Widget build(BuildContext context) { - final selectedColor = CupertinoTheme.of(context).primaryColor; - - return CupertinoActionSheet( - actions: _speeds - .map( - (e) => CupertinoActionSheetAction( - onPressed: () { - Navigator.of(context).pop(e); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (e == _selected) - Icon(Icons.check, size: 20.0, color: selectedColor), - Text(e.toString()), - ], - ), - ), - ) - .toList(), - ); - } -} diff --git a/lib/src/cupertino/cupertino_progress_bar.dart b/lib/src/cupertino/cupertino_progress_bar.dart deleted file mode 100644 index f24fc0f80..000000000 --- a/lib/src/cupertino/cupertino_progress_bar.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:chewie/src/chewie_progress_colors.dart'; -import 'package:chewie/src/progress_bar.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:video_player/video_player.dart'; - -class CupertinoVideoProgressBar extends StatelessWidget { - CupertinoVideoProgressBar( - this.controller, { - ChewieProgressColors? colors, - this.onDragEnd, - this.onDragStart, - this.onDragUpdate, - super.key, - this.draggableProgressBar = true, - }) : colors = colors ?? ChewieProgressColors(); - - final VideoPlayerController controller; - final ChewieProgressColors colors; - final Function()? onDragStart; - final Function()? onDragEnd; - final Function()? onDragUpdate; - final bool draggableProgressBar; - - @override - Widget build(BuildContext context) { - return VideoProgressBar( - controller, - barHeight: 5, - handleHeight: 6, - drawShadow: true, - colors: colors, - onDragEnd: onDragEnd, - onDragStart: onDragStart, - onDragUpdate: onDragUpdate, - draggableProgressBar: draggableProgressBar, - ); - } -} diff --git a/lib/src/cupertino/widgets/cupertino_options_dialog.dart b/lib/src/cupertino/widgets/cupertino_options_dialog.dart deleted file mode 100644 index 4b923dc6e..000000000 --- a/lib/src/cupertino/widgets/cupertino_options_dialog.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:chewie/src/models/option_item.dart'; -import 'package:flutter/cupertino.dart'; - -class CupertinoOptionsDialog extends StatefulWidget { - const CupertinoOptionsDialog({ - super.key, - required this.options, - this.cancelButtonText, - }); - - final List options; - final String? cancelButtonText; - - @override - // ignore: library_private_types_in_public_api - _CupertinoOptionsDialogState createState() => _CupertinoOptionsDialogState(); -} - -class _CupertinoOptionsDialogState extends State { - @override - Widget build(BuildContext context) { - return SafeArea( - child: CupertinoActionSheet( - actions: widget.options - .map( - (option) => CupertinoActionSheetAction( - onPressed: () => option.onTap(context), - child: Text(option.title), - ), - ) - .toList(), - cancelButton: CupertinoActionSheetAction( - onPressed: () => Navigator.pop(context), - isDestructiveAction: true, - child: Text(widget.cancelButtonText ?? 'Cancel'), - ), - ), - ); - } -} diff --git a/lib/src/helpers/adaptive_controls.dart b/lib/src/helpers/adaptive_controls.dart deleted file mode 100644 index ef8968d3b..000000000 --- a/lib/src/helpers/adaptive_controls.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:chewie/chewie.dart'; -import 'package:flutter/material.dart'; - -class AdaptiveControls extends StatelessWidget { - const AdaptiveControls({ - super.key, - }); - - @override - Widget build(BuildContext context) { - switch (Theme.of(context).platform) { - case TargetPlatform.android: - case TargetPlatform.fuchsia: - return const MaterialControls(); - - case TargetPlatform.macOS: - case TargetPlatform.windows: - case TargetPlatform.linux: - return const MaterialDesktopControls(); - - case TargetPlatform.iOS: - return const CupertinoControls( - backgroundColor: Color.fromRGBO(41, 41, 41, 0.7), - iconColor: Color.fromARGB(255, 200, 200, 200), - ); - } - } -} diff --git a/lib/src/helpers/utils.dart b/lib/src/helpers/utils.dart index 17ae2161a..36612d003 100644 --- a/lib/src/helpers/utils.dart +++ b/lib/src/helpers/utils.dart @@ -1,5 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:video_player/video_player.dart'; +import 'package:chewie/src/omni_video_controller.dart'; String formatDuration(Duration position) { final ms = position.inMilliseconds; @@ -34,38 +33,6 @@ String formatDuration(Duration position) { return formattedTime; } -/// Gets the current buffering state of the video player. -/// -/// For Android, it will use a workaround due to a [bug](https://github.com/flutter/flutter/issues/165149) -/// affecting the `video_player` plugin, preventing it from getting the -/// actual buffering state. This currently results in the `VideoPlayerController` always buffering, -/// thus breaking UI elements. -/// -/// For this, the actual buffer position is used to determine if the video is -/// buffering or not. See Issue [#912](https://github.com/fluttercommunity/chewie/pull/912) for more details. -bool getIsBuffering(VideoPlayerController controller) { - final VideoPlayerValue value = controller.value; - - if (defaultTargetPlatform == TargetPlatform.android) { - if (value.isBuffering) { - // -> Check if we actually buffer, as android has a bug preventing to - // get the correct buffering state from this single bool. - final int position = value.position.inMilliseconds; - - // Special case, if the video is finished, we don't want to show the - // buffering indicator anymore - if (position >= value.duration.inMilliseconds) { - return false; - } else { - final int buffer = value.buffered.lastOrNull?.end.inMilliseconds ?? -1; - - return position >= buffer; - } - } else { - // -> No buffering - return false; - } - } - - return value.isBuffering; +bool getIsBuffering(OmniVideoController controller) { + return controller.value.isBuffering; } diff --git a/lib/src/material/color_compat_extensions.dart b/lib/src/material/color_compat_extensions.dart index bff4f3071..6b571e019 100644 --- a/lib/src/material/color_compat_extensions.dart +++ b/lib/src/material/color_compat_extensions.dart @@ -24,7 +24,7 @@ extension ColorCompatExtensions on Color { // version compatibility). // Once it's removed from a future update, we'll have to replace uses of // this method with withValues(alpha: opacity). - // TODO: Replace this bridge method once the above holds true. + // Replace this bridge method once the above holds true. return withOpacity(opacity); } } diff --git a/lib/src/material/material_controls.dart b/lib/src/material/material_controls.dart deleted file mode 100644 index 3ea67f31d..000000000 --- a/lib/src/material/material_controls.dart +++ /dev/null @@ -1,706 +0,0 @@ -import 'dart:async'; - -import 'package:chewie/src/center_play_button.dart'; -import 'package:chewie/src/center_seek_button.dart'; -import 'package:chewie/src/chewie_player.dart'; -import 'package:chewie/src/chewie_progress_colors.dart'; -import 'package:chewie/src/helpers/utils.dart'; -import 'package:chewie/src/material/color_compat_extensions.dart'; -import 'package:chewie/src/material/material_progress_bar.dart'; -import 'package:chewie/src/material/widgets/options_dialog.dart'; -import 'package:chewie/src/material/widgets/playback_speed_dialog.dart'; -import 'package:chewie/src/models/option_item.dart'; -import 'package:chewie/src/models/subtitle_model.dart'; -import 'package:chewie/src/notifiers/index.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:video_player/video_player.dart'; - -class MaterialControls extends StatefulWidget { - const MaterialControls({ - this.showPlayButton = true, - super.key, - }); - - final bool showPlayButton; - - @override - State createState() { - return _MaterialControlsState(); - } -} - -class _MaterialControlsState extends State - with SingleTickerProviderStateMixin { - late PlayerNotifier notifier; - late VideoPlayerValue _latestValue; - double? _latestVolume; - Timer? _hideTimer; - Timer? _initTimer; - late var _subtitlesPosition = Duration.zero; - bool _subtitleOn = false; - Timer? _showAfterExpandCollapseTimer; - bool _dragging = false; - bool _displayTapped = false; - Timer? _bufferingDisplayTimer; - bool _displayBufferingIndicator = false; - - final barHeight = 48.0 * 1.5; - final marginSize = 5.0; - - late VideoPlayerController controller; - ChewieController? _chewieController; - - // We know that _chewieController is set in didChangeDependencies - ChewieController get chewieController => _chewieController!; - - @override - void initState() { - super.initState(); - notifier = Provider.of(context, listen: false); - } - - @override - Widget build(BuildContext context) { - if (_latestValue.hasError) { - return chewieController.errorBuilder?.call( - context, - chewieController.videoPlayerController.value.errorDescription!, - ) ?? - const Center( - child: Icon( - Icons.error, - color: Colors.white, - size: 42, - ), - ); - } - - return MouseRegion( - onHover: (_) { - _cancelAndRestartTimer(); - }, - child: GestureDetector( - onTap: () => _cancelAndRestartTimer(), - child: AbsorbPointer( - absorbing: notifier.hideStuff, - child: Stack( - children: [ - if (_displayBufferingIndicator) - _chewieController?.bufferingBuilder?.call(context) ?? - const Center( - child: CircularProgressIndicator(), - ) - else - _buildHitArea(), - _buildActionBar(), - Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (_subtitleOn) - Transform.translate( - offset: Offset( - 0.0, - notifier.hideStuff ? barHeight * 0.8 : 0.0, - ), - child: - _buildSubtitles(context, chewieController.subtitle!), - ), - _buildBottomBar(context), - ], - ), - ], - ), - ), - ), - ); - } - - @override - void dispose() { - _dispose(); - super.dispose(); - } - - void _dispose() { - controller.removeListener(_updateState); - _hideTimer?.cancel(); - _initTimer?.cancel(); - _showAfterExpandCollapseTimer?.cancel(); - } - - @override - void didChangeDependencies() { - final oldController = _chewieController; - _chewieController = ChewieController.of(context); - controller = chewieController.videoPlayerController; - - if (oldController != chewieController) { - _dispose(); - _initialize(); - } - - super.didChangeDependencies(); - } - - Widget _buildActionBar() { - return Positioned( - top: 0, - right: 0, - child: SafeArea( - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 250), - child: Row( - children: [ - _buildSubtitleToggle(), - if (chewieController.showOptions) _buildOptionsButton(), - ], - ), - ), - ), - ); - } - - List _buildOptions(BuildContext context) { - final options = [ - OptionItem( - onTap: (context) async { - Navigator.pop(context); - _onSpeedButtonTap(); - }, - iconData: Icons.speed, - title: chewieController.optionsTranslation?.playbackSpeedButtonText ?? - 'Playback speed', - ) - ]; - - if (chewieController.additionalOptions != null && - chewieController.additionalOptions!(context).isNotEmpty) { - options.addAll(chewieController.additionalOptions!(context)); - } - return options; - } - - Widget _buildOptionsButton() { - return AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 250), - child: IconButton( - onPressed: () async { - _hideTimer?.cancel(); - - if (chewieController.optionsBuilder != null) { - await chewieController.optionsBuilder!( - context, _buildOptions(context)); - } else { - await showModalBottomSheet( - context: context, - isScrollControlled: true, - useRootNavigator: chewieController.useRootNavigator, - builder: (context) => OptionsDialog( - options: _buildOptions(context), - cancelButtonText: - chewieController.optionsTranslation?.cancelButtonText, - ), - ); - } - - if (_latestValue.isPlaying) { - _startHideTimer(); - } - }, - icon: const Icon( - Icons.more_vert, - color: Colors.white, - ), - ), - ); - } - - Widget _buildSubtitles(BuildContext context, Subtitles subtitles) { - if (!_subtitleOn) { - return const SizedBox(); - } - final currentSubtitle = subtitles.getByPosition(_subtitlesPosition); - if (currentSubtitle.isEmpty) { - return const SizedBox(); - } - - if (chewieController.subtitleBuilder != null) { - return chewieController.subtitleBuilder!( - context, - currentSubtitle.first!.text, - ); - } - - return Padding( - padding: EdgeInsets.all(marginSize), - child: Container( - padding: const EdgeInsets.all(5), - decoration: BoxDecoration( - color: const Color(0x96000000), - borderRadius: BorderRadius.circular(10.0), - ), - child: Text( - currentSubtitle.first!.text.toString(), - style: const TextStyle( - fontSize: 18, - ), - textAlign: TextAlign.center, - ), - ), - ); - } - - AnimatedOpacity _buildBottomBar( - BuildContext context, - ) { - final iconColor = Theme.of(context).textTheme.labelLarge!.color; - - return AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 300), - child: Container( - height: barHeight + (chewieController.isFullScreen ? 10.0 : 0), - padding: EdgeInsets.only( - left: 20, - right: 20, - bottom: !chewieController.isFullScreen ? 10.0 : 0, - ), - child: SafeArea( - top: false, - bottom: chewieController.isFullScreen, - minimum: chewieController.controlsSafeAreaMinimum, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Flexible( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (chewieController.isLive) - const Expanded(child: Text('LIVE')) - else - _buildPosition(iconColor), - if (chewieController.allowMuting) - _buildMuteButton(controller), - const Spacer(), - if (chewieController.allowFullScreen) _buildExpandButton(), - ], - ), - ), - SizedBox( - height: chewieController.isFullScreen ? 15.0 : 0, - ), - if (!chewieController.isLive) - Expanded( - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( - children: [ - _buildProgressBar(), - ], - ), - ), - ), - ], - ), - ), - ), - ); - } - - GestureDetector _buildMuteButton( - VideoPlayerController controller, - ) { - return GestureDetector( - onTap: () { - _cancelAndRestartTimer(); - - if (_latestValue.volume == 0) { - controller.setVolume(_latestVolume ?? 0.5); - } else { - _latestVolume = controller.value.volume; - controller.setVolume(0.0); - } - }, - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 300), - child: ClipRect( - child: Container( - height: barHeight, - padding: const EdgeInsets.only( - left: 6.0, - ), - child: Icon( - _latestValue.volume > 0 ? Icons.volume_up : Icons.volume_off, - color: Colors.white, - ), - ), - ), - ), - ); - } - - GestureDetector _buildExpandButton() { - return GestureDetector( - onTap: _onExpandCollapse, - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 300), - child: Container( - height: barHeight + (chewieController.isFullScreen ? 15.0 : 0), - margin: const EdgeInsets.only(right: 12.0), - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - ), - child: Center( - child: Icon( - chewieController.isFullScreen - ? Icons.fullscreen_exit - : Icons.fullscreen, - color: Colors.white, - ), - ), - ), - ), - ); - } - - Widget _buildHitArea() { - final bool isFinished = (_latestValue.position >= _latestValue.duration) && - _latestValue.duration.inSeconds > 0; - final bool showPlayButton = - widget.showPlayButton && !_dragging && !notifier.hideStuff; - - return GestureDetector( - onTap: () { - if (_latestValue.isPlaying) { - if (_chewieController?.pauseOnBackgroundTap ?? false) { - _playPause(); - _cancelAndRestartTimer(); - } else { - if (_displayTapped) { - setState(() { - notifier.hideStuff = true; - }); - } else { - _cancelAndRestartTimer(); - } - } - } else { - _playPause(); - - setState(() { - notifier.hideStuff = true; - }); - } - }, - child: Container( - alignment: Alignment.center, - color: Colors - .transparent, // The Gesture Detector doesn't expand to the full size of the container without this; Not sure why! - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (!isFinished && !chewieController.isLive) - CenterSeekButton( - iconData: Icons.replay_10, - backgroundColor: Colors.black54, - iconColor: Colors.white, - show: showPlayButton, - fadeDuration: chewieController.materialSeekButtonFadeDuration, - iconSize: chewieController.materialSeekButtonSize, - onPressed: _seekBackward, - ), - Container( - margin: EdgeInsets.symmetric( - horizontal: marginSize, - ), - child: CenterPlayButton( - backgroundColor: Colors.black54, - iconColor: Colors.white, - isFinished: isFinished, - isPlaying: controller.value.isPlaying, - show: showPlayButton, - onPressed: _playPause, - ), - ), - if (!isFinished && !chewieController.isLive) - CenterSeekButton( - iconData: Icons.forward_10, - backgroundColor: Colors.black54, - iconColor: Colors.white, - show: showPlayButton, - fadeDuration: chewieController.materialSeekButtonFadeDuration, - iconSize: chewieController.materialSeekButtonSize, - onPressed: _seekForward, - ), - ], - ), - ), - ); - } - - Future _onSpeedButtonTap() async { - _hideTimer?.cancel(); - - final chosenSpeed = await showModalBottomSheet( - context: context, - isScrollControlled: true, - useRootNavigator: chewieController.useRootNavigator, - builder: (context) => PlaybackSpeedDialog( - speeds: chewieController.playbackSpeeds, - selected: _latestValue.playbackSpeed, - ), - ); - - if (chosenSpeed != null) { - controller.setPlaybackSpeed(chosenSpeed); - } - - if (_latestValue.isPlaying) { - _startHideTimer(); - } - } - - Widget _buildPosition(Color? iconColor) { - final position = _latestValue.position; - final duration = _latestValue.duration; - - return RichText( - text: TextSpan( - text: '${formatDuration(position)} ', - children: [ - TextSpan( - text: '/ ${formatDuration(duration)}', - style: TextStyle( - fontSize: 14.0, - color: Colors.white.withOpacityCompat(.75), - fontWeight: FontWeight.normal, - ), - ) - ], - style: const TextStyle( - fontSize: 14.0, - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - ); - } - - Widget _buildSubtitleToggle() { - //if don't have subtitle hiden button - if (chewieController.subtitle?.isEmpty ?? true) { - return const SizedBox(); - } - return GestureDetector( - onTap: _onSubtitleTap, - child: Container( - height: barHeight, - color: Colors.transparent, - padding: const EdgeInsets.only( - left: 12.0, - right: 12.0, - ), - child: Icon( - _subtitleOn - ? Icons.closed_caption - : Icons.closed_caption_off_outlined, - color: _subtitleOn ? Colors.white : Colors.grey[700], - ), - ), - ); - } - - void _onSubtitleTap() { - setState(() { - _subtitleOn = !_subtitleOn; - }); - } - - void _cancelAndRestartTimer() { - _hideTimer?.cancel(); - _startHideTimer(); - - setState(() { - notifier.hideStuff = false; - _displayTapped = true; - }); - } - - Future _initialize() async { - _subtitleOn = chewieController.showSubtitles && - (chewieController.subtitle?.isNotEmpty ?? false); - controller.addListener(_updateState); - - _updateState(); - - if (controller.value.isPlaying || chewieController.autoPlay) { - _startHideTimer(); - } - - if (chewieController.showControlsOnInitialize) { - _initTimer = Timer(const Duration(milliseconds: 200), () { - setState(() { - notifier.hideStuff = false; - }); - }); - } - } - - void _onExpandCollapse() { - setState(() { - notifier.hideStuff = true; - - chewieController.toggleFullScreen(); - _showAfterExpandCollapseTimer = - Timer(const Duration(milliseconds: 300), () { - setState(() { - _cancelAndRestartTimer(); - }); - }); - }); - } - - void _playPause() { - final bool isFinished = (_latestValue.position >= _latestValue.duration) && - _latestValue.duration.inSeconds > 0; - - setState(() { - if (controller.value.isPlaying) { - notifier.hideStuff = false; - _hideTimer?.cancel(); - controller.pause(); - } else { - _cancelAndRestartTimer(); - - if (!controller.value.isInitialized) { - controller.initialize().then((_) { - controller.play(); - }); - } else { - if (isFinished) { - controller.seekTo(Duration.zero); - } - controller.play(); - } - } - }); - } - - void _seekRelative(Duration relativeSeek) { - _cancelAndRestartTimer(); - final position = _latestValue.position + relativeSeek; - final duration = _latestValue.duration; - - if (position < Duration.zero) { - controller.seekTo(Duration.zero); - } else if (position > duration) { - controller.seekTo(duration); - } else { - controller.seekTo(position); - } - } - - void _seekBackward() { - _seekRelative( - const Duration( - seconds: -10, - ), - ); - } - - void _seekForward() { - _seekRelative( - const Duration( - seconds: 10, - ), - ); - } - - void _startHideTimer() { - final hideControlsTimer = chewieController.hideControlsTimer.isNegative - ? ChewieController.defaultHideControlsTimer - : chewieController.hideControlsTimer; - _hideTimer = Timer(hideControlsTimer, () { - setState(() { - notifier.hideStuff = true; - }); - }); - } - - void _bufferingTimerTimeout() { - _displayBufferingIndicator = true; - if (mounted) { - setState(() {}); - } - } - - void _updateState() { - if (!mounted) return; - - final bool buffering = getIsBuffering(controller); - - // display the progress bar indicator only after the buffering delay if it has been set - if (chewieController.progressIndicatorDelay != null) { - if (buffering) { - _bufferingDisplayTimer ??= Timer( - chewieController.progressIndicatorDelay!, - _bufferingTimerTimeout, - ); - } else { - _bufferingDisplayTimer?.cancel(); - _bufferingDisplayTimer = null; - _displayBufferingIndicator = false; - } - } else { - _displayBufferingIndicator = buffering; - } - - setState(() { - _latestValue = controller.value; - _subtitlesPosition = controller.value.position; - }); - } - - Widget _buildProgressBar() { - return Expanded( - child: MaterialVideoProgressBar( - controller, - onDragStart: () { - setState(() { - _dragging = true; - }); - - _hideTimer?.cancel(); - }, - onDragUpdate: () { - _hideTimer?.cancel(); - }, - onDragEnd: () { - setState(() { - _dragging = false; - }); - - _startHideTimer(); - }, - colors: chewieController.materialProgressColors ?? - ChewieProgressColors( - playedColor: Theme.of(context).colorScheme.secondary, - handleColor: Theme.of(context).colorScheme.secondary, - bufferedColor: - Theme.of(context).colorScheme.surface.withOpacityCompat(0.5), - backgroundColor: - Theme.of(context).disabledColor.withOpacityCompat(.5), - ), - draggableProgressBar: chewieController.draggableProgressBar, - ), - ); - } -} diff --git a/lib/src/material/material_desktop_controls.dart b/lib/src/material/material_desktop_controls.dart deleted file mode 100644 index ebffd9560..000000000 --- a/lib/src/material/material_desktop_controls.dart +++ /dev/null @@ -1,672 +0,0 @@ -import 'dart:async'; - -import 'package:chewie/src/animated_play_pause.dart'; -import 'package:chewie/src/center_play_button.dart'; -import 'package:chewie/src/chewie_player.dart'; -import 'package:chewie/src/chewie_progress_colors.dart'; -import 'package:chewie/src/helpers/utils.dart'; -import 'package:chewie/src/material/color_compat_extensions.dart'; -import 'package:chewie/src/material/material_progress_bar.dart'; -import 'package:chewie/src/material/widgets/options_dialog.dart'; -import 'package:chewie/src/material/widgets/playback_speed_dialog.dart'; -import 'package:chewie/src/models/option_item.dart'; -import 'package:chewie/src/models/subtitle_model.dart'; -import 'package:chewie/src/notifiers/index.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:provider/provider.dart'; -import 'package:video_player/video_player.dart'; - -class MaterialDesktopControls extends StatefulWidget { - const MaterialDesktopControls({ - this.showPlayButton = true, - super.key, - }); - - final bool showPlayButton; - - @override - State createState() { - return _MaterialDesktopControlsState(); - } -} - -class _MaterialDesktopControlsState extends State - with SingleTickerProviderStateMixin { - late PlayerNotifier notifier; - late VideoPlayerValue _latestValue; - double? _latestVolume; - Timer? _hideTimer; - Timer? _initTimer; - late var _subtitlesPosition = Duration.zero; - bool _subtitleOn = false; - Timer? _showAfterExpandCollapseTimer; - bool _dragging = false; - bool _displayTapped = false; - Timer? _bufferingDisplayTimer; - bool _displayBufferingIndicator = false; - - final barHeight = 48.0 * 1.5; - final marginSize = 5.0; - - late VideoPlayerController controller; - ChewieController? _chewieController; - late final FocusNode _focusNode; - - // We know that _chewieController is set in didChangeDependencies - ChewieController get chewieController => _chewieController!; - - @override - void initState() { - super.initState(); - _focusNode = FocusNode(); - _focusNode.requestFocus(); - notifier = Provider.of(context, listen: false); - } - - void _handleKeyPress(event) { - if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.space) { - _playPause(); - } else if (event is KeyDownEvent && - event.logicalKey == LogicalKeyboardKey.arrowRight) { - _seekForward(); - } else if (event is KeyDownEvent && - event.logicalKey == LogicalKeyboardKey.arrowLeft) { - _seekBackward(); - } else if (event is KeyDownEvent && - event.logicalKey == LogicalKeyboardKey.escape) { - if (chewieController.isFullScreen) { - _onExpandCollapse(); - } - } - } - - @override - Widget build(BuildContext context) { - if (_latestValue.hasError) { - return chewieController.errorBuilder?.call( - context, - chewieController.videoPlayerController.value.errorDescription!, - ) ?? - const Center( - child: Icon( - Icons.error, - color: Colors.white, - size: 42, - ), - ); - } - - return KeyboardListener( - focusNode: _focusNode, - onKeyEvent: _handleKeyPress, - child: MouseRegion( - onHover: (_) { - _focusNode.requestFocus(); - _cancelAndRestartTimer(); - }, - child: GestureDetector( - onTap: () { - _playPause(); - _cancelAndRestartTimer(); - }, - child: AbsorbPointer( - absorbing: notifier.hideStuff, - child: Stack( - children: [ - if (_displayBufferingIndicator) - _chewieController?.bufferingBuilder?.call(context) ?? - const Center( - child: CircularProgressIndicator(), - ) - else - _buildHitArea(), - Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (_subtitleOn) - Transform.translate( - offset: Offset( - 0.0, - notifier.hideStuff ? barHeight * 0.8 : 0.0, - ), - child: _buildSubtitles( - context, chewieController.subtitle!), - ), - _buildBottomBar(context), - ], - ), - ], - ), - ), - ), - ), - ); - } - - @override - void dispose() { - _dispose(); - _focusNode.dispose(); - super.dispose(); - } - - void _dispose() { - controller.removeListener(_updateState); - _hideTimer?.cancel(); - _initTimer?.cancel(); - _showAfterExpandCollapseTimer?.cancel(); - } - - @override - void didChangeDependencies() { - final oldController = _chewieController; - _chewieController = ChewieController.of(context); - controller = chewieController.videoPlayerController; - - if (oldController != chewieController) { - _dispose(); - _initialize(); - } - - super.didChangeDependencies(); - } - - Widget _buildSubtitleToggle({IconData? icon, bool isPadded = false}) { - return IconButton( - padding: isPadded ? const EdgeInsets.all(8.0) : EdgeInsets.zero, - icon: Icon(icon, color: _subtitleOn ? Colors.white : Colors.grey[700]), - onPressed: _onSubtitleTap, - ); - } - - Widget _buildOptionsButton({ - IconData? icon, - bool isPadded = false, - }) { - final options = [ - OptionItem( - onTap: (context) async { - Navigator.pop(context); - _onSpeedButtonTap(); - }, - iconData: Icons.speed, - title: chewieController.optionsTranslation?.playbackSpeedButtonText ?? - 'Playback speed', - ) - ]; - - if (chewieController.additionalOptions != null && - chewieController.additionalOptions!(context).isNotEmpty) { - options.addAll(chewieController.additionalOptions!(context)); - } - - return AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 250), - child: IconButton( - padding: isPadded ? const EdgeInsets.all(8.0) : EdgeInsets.zero, - onPressed: () async { - _hideTimer?.cancel(); - - if (chewieController.optionsBuilder != null) { - await chewieController.optionsBuilder!(context, options); - } else { - await showModalBottomSheet( - context: context, - isScrollControlled: true, - useRootNavigator: chewieController.useRootNavigator, - builder: (context) => OptionsDialog( - options: options, - cancelButtonText: - chewieController.optionsTranslation?.cancelButtonText, - ), - ); - } - - if (_latestValue.isPlaying) { - _startHideTimer(); - } - }, - icon: Icon( - icon ?? Icons.more_vert, - color: Colors.white, - ), - ), - ); - } - - Widget _buildSubtitles(BuildContext context, Subtitles subtitles) { - if (!_subtitleOn) { - return const SizedBox(); - } - final currentSubtitle = subtitles.getByPosition(_subtitlesPosition); - if (currentSubtitle.isEmpty) { - return const SizedBox(); - } - - if (chewieController.subtitleBuilder != null) { - return chewieController.subtitleBuilder!( - context, - currentSubtitle.first!.text, - ); - } - - return Padding( - padding: EdgeInsets.all(marginSize), - child: Container( - padding: const EdgeInsets.all(5), - decoration: BoxDecoration( - color: const Color(0x96000000), - borderRadius: BorderRadius.circular(10.0), - ), - child: Text( - currentSubtitle.first!.text.toString(), - style: const TextStyle( - fontSize: 18, - ), - textAlign: TextAlign.center, - ), - ), - ); - } - - AnimatedOpacity _buildBottomBar( - BuildContext context, - ) { - final iconColor = Theme.of(context).textTheme.labelLarge!.color; - - return AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 300), - child: Container( - height: barHeight + (chewieController.isFullScreen ? 20.0 : 0), - padding: - EdgeInsets.only(bottom: chewieController.isFullScreen ? 10.0 : 15), - child: SafeArea( - bottom: chewieController.isFullScreen, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - verticalDirection: VerticalDirection.up, - children: [ - Flexible( - child: Row( - children: [ - _buildPlayPause(controller), - if (chewieController.allowMuting) - _buildMuteButton(controller), - if (chewieController.isLive) - const Expanded(child: Text('LIVE')) - else - _buildPosition(iconColor), - const Spacer(), - if (chewieController.showControls && - chewieController.subtitle != null && - chewieController.subtitle!.isNotEmpty) - _buildSubtitleToggle(icon: Icons.subtitles), - if (chewieController.showOptions) - _buildOptionsButton(icon: Icons.settings), - if (chewieController.allowFullScreen) _buildExpandButton(), - ], - ), - ), - if (!chewieController.isLive) - Expanded( - child: Container( - padding: EdgeInsets.only( - right: 20, - left: 20, - bottom: chewieController.isFullScreen ? 5.0 : 0, - ), - child: Row( - children: [ - _buildProgressBar(), - ], - ), - ), - ), - ], - ), - ), - ), - ); - } - - GestureDetector _buildExpandButton() { - return GestureDetector( - onTap: _onExpandCollapse, - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 300), - child: Container( - height: barHeight + (chewieController.isFullScreen ? 15.0 : 0), - margin: const EdgeInsets.only(right: 12.0), - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - ), - child: Center( - child: Icon( - chewieController.isFullScreen - ? Icons.fullscreen_exit - : Icons.fullscreen, - color: Colors.white, - ), - ), - ), - ), - ); - } - - Widget _buildHitArea() { - final bool isFinished = _latestValue.position >= _latestValue.duration && - _latestValue.duration.inSeconds > 0; - final bool showPlayButton = - widget.showPlayButton && !_dragging && !notifier.hideStuff; - - return GestureDetector( - onTap: () { - if (_latestValue.isPlaying) { - if (_chewieController?.pauseOnBackgroundTap ?? false) { - _playPause(); - _cancelAndRestartTimer(); - } else { - if (_displayTapped) { - setState(() { - notifier.hideStuff = true; - }); - } else { - _cancelAndRestartTimer(); - } - } - } else { - _playPause(); - - setState(() { - notifier.hideStuff = true; - }); - } - }, - child: CenterPlayButton( - backgroundColor: Colors.black54, - iconColor: Colors.white, - isFinished: isFinished, - isPlaying: controller.value.isPlaying, - show: showPlayButton, - onPressed: _playPause, - ), - ); - } - - Future _onSpeedButtonTap() async { - _hideTimer?.cancel(); - - final chosenSpeed = await showModalBottomSheet( - context: context, - isScrollControlled: true, - useRootNavigator: chewieController.useRootNavigator, - builder: (context) => PlaybackSpeedDialog( - speeds: chewieController.playbackSpeeds, - selected: _latestValue.playbackSpeed, - ), - ); - - if (chosenSpeed != null) { - controller.setPlaybackSpeed(chosenSpeed); - } - - if (_latestValue.isPlaying) { - _startHideTimer(); - } - } - - GestureDetector _buildMuteButton( - VideoPlayerController controller, - ) { - return GestureDetector( - onTap: () { - _cancelAndRestartTimer(); - - if (_latestValue.volume == 0) { - controller.setVolume(_latestVolume ?? 0.5); - } else { - _latestVolume = controller.value.volume; - controller.setVolume(0.0); - } - }, - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 1.0, - duration: const Duration(milliseconds: 300), - child: ClipRect( - child: Container( - height: barHeight, - padding: const EdgeInsets.only( - right: 15.0, - ), - child: Icon( - _latestValue.volume > 0 ? Icons.volume_up : Icons.volume_off, - color: Colors.white, - ), - ), - ), - ), - ); - } - - GestureDetector _buildPlayPause(VideoPlayerController controller) { - return GestureDetector( - onTap: _playPause, - child: Container( - height: barHeight, - color: Colors.transparent, - margin: const EdgeInsets.only(left: 8.0, right: 4.0), - padding: const EdgeInsets.only( - left: 12.0, - right: 12.0, - ), - child: AnimatedPlayPause( - playing: controller.value.isPlaying, - color: Colors.white, - ), - ), - ); - } - - Widget _buildPosition(Color? iconColor) { - final position = _latestValue.position; - final duration = _latestValue.duration; - - return Text( - '${formatDuration(position)} / ${formatDuration(duration)}', - style: const TextStyle( - fontSize: 14.0, - color: Colors.white, - ), - ); - } - - void _onSubtitleTap() { - setState(() { - _subtitleOn = !_subtitleOn; - }); - } - - void _cancelAndRestartTimer() { - _hideTimer?.cancel(); - _startHideTimer(); - - setState(() { - notifier.hideStuff = false; - _displayTapped = true; - }); - } - - Future _initialize() async { - _subtitleOn = chewieController.showSubtitles && - (chewieController.subtitle?.isNotEmpty ?? false); - controller.addListener(_updateState); - - _updateState(); - - if (controller.value.isPlaying || chewieController.autoPlay) { - _startHideTimer(); - } - - if (chewieController.showControlsOnInitialize) { - _initTimer = Timer(const Duration(milliseconds: 200), () { - setState(() { - notifier.hideStuff = false; - }); - }); - } - } - - void _onExpandCollapse() { - setState(() { - notifier.hideStuff = true; - }); - - chewieController.toggleFullScreen(); - - _showAfterExpandCollapseTimer = - Timer(const Duration(milliseconds: 300), () { - setState(() { - _cancelAndRestartTimer(); - }); - }); - } - - void _playPause() { - if (controller.value.isPlaying) { - setState(() { - notifier.hideStuff = false; - }); - - _hideTimer?.cancel(); - controller.pause(); - } else { - _cancelAndRestartTimer(); - - if (!controller.value.isInitialized) { - controller.initialize().then((_) { - //[VideoPlayerController.play] If the video is at the end, this method starts playing from the beginning - controller.play(); - }); - } else { - //[VideoPlayerController.play] If the video is at the end, this method starts playing from the beginning - controller.play(); - } - } - } - - void _startHideTimer() { - final hideControlsTimer = chewieController.hideControlsTimer.isNegative - ? ChewieController.defaultHideControlsTimer - : chewieController.hideControlsTimer; - _hideTimer = Timer(hideControlsTimer, () { - setState(() { - notifier.hideStuff = true; - }); - }); - } - - void _bufferingTimerTimeout() { - _displayBufferingIndicator = true; - if (mounted) { - setState(() {}); - } - } - - void _updateState() { - if (!mounted) return; - - final bool buffering = getIsBuffering(controller); - - // display the progress bar indicator only after the buffering delay if it has been set - if (chewieController.progressIndicatorDelay != null) { - if (buffering) { - _bufferingDisplayTimer ??= Timer( - chewieController.progressIndicatorDelay!, - _bufferingTimerTimeout, - ); - } else { - _bufferingDisplayTimer?.cancel(); - _bufferingDisplayTimer = null; - _displayBufferingIndicator = false; - } - } else { - _displayBufferingIndicator = buffering; - } - - setState(() { - _latestValue = controller.value; - _subtitlesPosition = controller.value.position; - }); - } - - void _seekBackward() { - _seekRelative( - const Duration( - seconds: -10, - ), - ); - } - - void _seekForward() { - _seekRelative( - const Duration( - seconds: 10, - ), - ); - } - - void _seekRelative(Duration relativeSeek) { - _cancelAndRestartTimer(); - final position = _latestValue.position + relativeSeek; - final duration = _latestValue.duration; - - if (position < Duration.zero) { - controller.seekTo(Duration.zero); - } else if (position > duration) { - controller.seekTo(duration); - } else { - controller.seekTo(position); - } - } - - Widget _buildProgressBar() { - return Expanded( - child: MaterialVideoProgressBar( - controller, - onDragStart: () { - setState(() { - _dragging = true; - }); - - _hideTimer?.cancel(); - }, - onDragUpdate: () { - _hideTimer?.cancel(); - }, - onDragEnd: () { - setState(() { - _dragging = false; - }); - - _startHideTimer(); - }, - colors: chewieController.materialProgressColors ?? - ChewieProgressColors( - playedColor: Theme.of(context).colorScheme.secondary, - handleColor: Theme.of(context).colorScheme.secondary, - bufferedColor: - Theme.of(context).colorScheme.surface.withOpacityCompat(0.5), - backgroundColor: - Theme.of(context).disabledColor.withOpacityCompat(0.5), - ), - draggableProgressBar: chewieController.draggableProgressBar, - ), - ); - } -} diff --git a/lib/src/material/material_progress_bar.dart b/lib/src/material/material_progress_bar.dart index ba58a37d6..8f322d0fa 100644 --- a/lib/src/material/material_progress_bar.dart +++ b/lib/src/material/material_progress_bar.dart @@ -1,7 +1,7 @@ import 'package:chewie/src/chewie_progress_colors.dart'; +import 'package:chewie/src/omni_video_controller.dart'; import 'package:chewie/src/progress_bar.dart'; import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; class MaterialVideoProgressBar extends StatelessWidget { MaterialVideoProgressBar( @@ -20,7 +20,7 @@ class MaterialVideoProgressBar extends StatelessWidget { final double height; final double barHeight; final double handleHeight; - final VideoPlayerController controller; + final OmniVideoController controller; final ChewieProgressColors colors; final Function()? onDragStart; final Function()? onDragEnd; diff --git a/lib/src/omni_video_controller.dart b/lib/src/omni_video_controller.dart new file mode 100644 index 000000000..a64487f08 --- /dev/null +++ b/lib/src/omni_video_controller.dart @@ -0,0 +1,219 @@ +import 'dart:async'; +import 'dart:io' show Platform; + +import 'package:flutter/services.dart'; +import 'package:video_player/video_player.dart' as video_player; +import 'package:media_kit/media_kit.dart' as media_kit; +import 'package:media_kit_video/media_kit_video.dart' as media_kit_video; +import 'package:wakelock_plus/wakelock_plus.dart'; + +class OmniVideoController { + final String url; + final Map httpHeaders; + final bool backgroundPlayback; + final bool mixAudio; + late final OmniVideoValue value; + + late final media_kit.Player _iosPlayer; + late final media_kit_video.VideoController _iosController; + final Map> _iosListeners = {}; + + late final video_player.VideoPlayerController _androidController; + + OmniVideoController({ + required this.url, + this.httpHeaders = const {}, + this.backgroundPlayback = false, + this.mixAudio = false, + }); + + void initalize() async { + value = OmniVideoValue(this); + + if (Platform.isIOS) { + _iosPlayer = media_kit.Player(); + _iosController = media_kit_video.VideoController(_iosPlayer); + await _iosPlayer.open(media_kit.Media(url, httpHeaders: httpHeaders)); + value.iosInitialized = true; + } else { + _androidController = video_player.VideoPlayerController.networkUrl( + Uri.parse(url), + httpHeaders: httpHeaders, + videoPlayerOptions: video_player.VideoPlayerOptions( + allowBackgroundPlayback: backgroundPlayback, + mixWithOthers: mixAudio, + ), + ); + // todo probably initialize android manually ?? maybe idk + } + try { + await WakelockPlus.enable(); + } catch (e) { + // pass + } + } + + void dispose() async { + try { + if (Platform.isIOS) { + await _iosPlayer.dispose(); + } else { + await _androidController.dispose(); + } + } catch (e) { + // pass + } + try { + await WakelockPlus.disable(); + } catch (e) { + // pass + } + } + + void addPositionListener(void Function() listener) { + if (Platform.isIOS) { + final subscription = _iosController.player.stream.position.listen( + (_) => listener(), + ); + _iosListeners[listener] = subscription; + } else { + _androidController.addListener(listener); + } + } + + void removeListener(void Function() listener) { + if (Platform.isIOS) { + final subscription = _iosListeners.remove(listener); + if (subscription != null) { + subscription.cancel(); + } + } else { + _androidController.removeListener(listener); + } + } + + Future play() { + if (Platform.isIOS) { + return _iosPlayer.play(); + } else { + return _androidController.play(); + } + } + + Future pause() { + if (Platform.isIOS) { + return _iosPlayer.pause(); + } else { + return _androidController.pause(); + } + } + + Future seekTo(Duration position) { + if (Platform.isIOS) { + return _iosPlayer.seek(position); + } else { + return _androidController.seekTo(position); + } + } + + Future setLooping(bool looping) { + if (Platform.isIOS) { + return _iosPlayer.setPlaylistMode( + looping ? media_kit.PlaylistMode.loop : media_kit.PlaylistMode.none, + ); + } else { + return _androidController.setLooping(looping); + } + } + + Future setVolume(double volume) { + if (Platform.isIOS) { + return _iosPlayer.setVolume(volume * 100); + } else { + return _androidController.setVolume(volume); + } + } +} + +class OmniVideoValue { + final OmniVideoController ctl; + bool iosInitialized = false; + + OmniVideoValue(this.ctl); + + bool get isInitialized { + if (Platform.isIOS) { + return iosInitialized; + } else { + return ctl._androidController.value.isInitialized; + } + } + + bool get isPlaying { + if (Platform.isIOS) { + return ctl._iosPlayer.state.playing; + } else { + return ctl._androidController.value.isPlaying; + } + } + + Duration get duration { + if (Platform.isIOS) { + return ctl._iosPlayer.state.duration; + } else { + return ctl._androidController.value.duration; + } + } + + Duration get position { + if (Platform.isIOS) { + return ctl._iosPlayer.state.position; + } else { + return ctl._androidController.value.position; + } + } + + Size get size { + if (Platform.isIOS) { + final w = ctl._iosPlayer.state.width ?? 100; + final h = ctl._iosPlayer.state.height ?? 100; + return Size(w.toDouble(), h.toDouble()); + } else { + return ctl._androidController.value.size; + } + } + + bool get isBuffering { + if (Platform.isIOS) { + return ctl._iosPlayer.state.buffering; + } else { + /// Gets the current buffering state of the video player. + /// + /// For Android, it will use a workaround due to a [bug](https://github.com/flutter/flutter/issues/165149) + /// affecting the `video_player` plugin, preventing it from getting the + /// actual buffering state. This currently results in the `VideoPlayerController` always buffering, + /// thus breaking UI elements. + /// + /// For this, the actual buffer position is used to determine if the video is + /// buffering or not. See Issue [#912](https://github.com/fluttercommunity/chewie/pull/912) for more details. + if (ctl._androidController.value.isBuffering) { + // -> Check if we actually buffer, as android has a bug preventing to + // get the correct buffering state from this single bool. + final int position = ctl._androidController.value.position.inMilliseconds; + + // Special case, if the video is finished, we don't want to show the + // buffering indicator anymore + if (position >= ctl._androidController.value.duration.inMilliseconds) { + return false; + } else { + final int buffer = + ctl._androidController.value.buffered.lastOrNull?.end.inMilliseconds ?? -1; + + return position >= buffer; + } + } else { + return false; + } + } + } +} diff --git a/lib/src/player_with_controls.dart b/lib/src/player_with_controls.dart index 65d51a69b..15d116512 100644 --- a/lib/src/player_with_controls.dart +++ b/lib/src/player_with_controls.dart @@ -1,5 +1,4 @@ import 'package:chewie/src/chewie_player.dart'; -import 'package:chewie/src/helpers/adaptive_controls.dart'; import 'package:chewie/src/notifiers/index.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -20,12 +19,9 @@ class PlayerWithControls extends StatelessWidget { return width > height ? width / height : height / width; } - Widget buildControls( - BuildContext context, - ChewieController chewieController, - ) { + Widget buildControls(BuildContext context, ChewieController chewieController) { return chewieController.showControls - ? chewieController.customControls ?? const AdaptiveControls() + ? chewieController.customControls : const SizedBox(); } @@ -35,8 +31,7 @@ class PlayerWithControls extends StatelessWidget { ) { return Stack( children: [ - if (chewieController.placeholder != null) - chewieController.placeholder!, + if (chewieController.placeholder != null) chewieController.placeholder!, InteractiveViewer( transformationController: chewieController.transformationController, maxScale: chewieController.maxScale, @@ -44,7 +39,8 @@ class PlayerWithControls extends StatelessWidget { scaleEnabled: chewieController.zoomAndPan, child: Center( child: AspectRatio( - aspectRatio: chewieController.aspectRatio ?? + aspectRatio: + chewieController.aspectRatio ?? chewieController.videoPlayerController.value.aspectRatio, child: VideoPlayer(chewieController.videoPlayerController), ), @@ -53,48 +49,41 @@ class PlayerWithControls extends StatelessWidget { if (chewieController.overlay != null) chewieController.overlay!, if (Theme.of(context).platform != TargetPlatform.iOS) Consumer( - builder: ( - BuildContext context, - PlayerNotifier notifier, - Widget? widget, - ) => - Visibility( - visible: !notifier.hideStuff, - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 0.8, - duration: const Duration( - milliseconds: 250, - ), - child: const DecoratedBox( - decoration: BoxDecoration(color: Colors.black54), - child: SizedBox.expand(), - ), - ), - ), + builder: + (BuildContext context, PlayerNotifier notifier, Widget? widget) => + Visibility( + visible: !notifier.hideStuff, + child: AnimatedOpacity( + opacity: notifier.hideStuff ? 0.0 : 0.8, + duration: const Duration(milliseconds: 250), + child: const DecoratedBox( + decoration: BoxDecoration(color: Colors.black54), + child: SizedBox.expand(), + ), + ), + ), ), if (!chewieController.isFullScreen) buildControls(context, chewieController) else - SafeArea( - bottom: false, - child: buildControls(context, chewieController), - ), + SafeArea(bottom: false, child: buildControls(context, chewieController)), ], ); } return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Center( - child: SizedBox( - height: constraints.maxHeight, - width: constraints.maxWidth, - child: AspectRatio( - aspectRatio: calculateAspectRatio(context), - child: buildPlayerWithControls(chewieController, context), + builder: (BuildContext context, BoxConstraints constraints) { + return Center( + child: SizedBox( + height: constraints.maxHeight, + width: constraints.maxWidth, + child: AspectRatio( + aspectRatio: calculateAspectRatio(context), + child: buildPlayerWithControls(chewieController, context), + ), ), - ), - ); - }); + ); + }, + ); } } diff --git a/lib/src/progress_bar.dart b/lib/src/progress_bar.dart index b07a16e5b..46b686921 100644 --- a/lib/src/progress_bar.dart +++ b/lib/src/progress_bar.dart @@ -1,6 +1,6 @@ import 'package:chewie/chewie.dart'; +import 'package:chewie/src/omni_video_controller.dart'; import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; class VideoProgressBar extends StatefulWidget { VideoProgressBar( @@ -16,7 +16,7 @@ class VideoProgressBar extends StatefulWidget { required this.drawShadow, }) : colors = colors ?? ChewieProgressColors(); - final VideoPlayerController controller; + final OmniVideoController controller; final ChewieProgressColors colors; final Function()? onDragStart; final Function()? onDragEnd; @@ -44,12 +44,12 @@ class _VideoProgressBarState extends State { Offset? _latestDraggableOffset; - VideoPlayerController get controller => widget.controller; + OmniVideoController get controller => widget.controller; @override void initState() { super.initState(); - controller.addListener(listener); + controller.addPositionListener(listener); } @override @@ -59,10 +59,9 @@ class _VideoProgressBarState extends State { } void _seekToRelativePosition(Offset globalPosition) { - controller.seekTo(context.calcRelativePosition( - controller.value.duration, - globalPosition, - )); + controller.seekTo( + context.calcRelativePosition(controller.value.duration, globalPosition), + ); } @override @@ -80,46 +79,46 @@ class _VideoProgressBarState extends State { return widget.draggableProgressBar ? GestureDetector( - onHorizontalDragStart: (DragStartDetails details) { - if (!controller.value.isInitialized) { - return; - } - _controllerWasPlaying = controller.value.isPlaying; - if (_controllerWasPlaying) { - controller.pause(); - } - - widget.onDragStart?.call(); - }, - onHorizontalDragUpdate: (DragUpdateDetails details) { - if (!controller.value.isInitialized) { - return; - } - _latestDraggableOffset = details.globalPosition; - listener(); - - widget.onDragUpdate?.call(); - }, - onHorizontalDragEnd: (DragEndDetails details) { - if (_controllerWasPlaying) { - controller.play(); - } - - if (_latestDraggableOffset != null) { - _seekToRelativePosition(_latestDraggableOffset!); - _latestDraggableOffset = null; - } - - widget.onDragEnd?.call(); - }, - onTapDown: (TapDownDetails details) { - if (!controller.value.isInitialized) { - return; - } - _seekToRelativePosition(details.globalPosition); - }, - child: child, - ) + onHorizontalDragStart: (DragStartDetails details) { + if (!controller.value.isInitialized) { + return; + } + _controllerWasPlaying = controller.value.isPlaying; + if (_controllerWasPlaying) { + controller.pause(); + } + + widget.onDragStart?.call(); + }, + onHorizontalDragUpdate: (DragUpdateDetails details) { + if (!controller.value.isInitialized) { + return; + } + _latestDraggableOffset = details.globalPosition; + listener(); + + widget.onDragUpdate?.call(); + }, + onHorizontalDragEnd: (DragEndDetails details) { + if (_controllerWasPlaying) { + controller.play(); + } + + if (_latestDraggableOffset != null) { + _seekToRelativePosition(_latestDraggableOffset!); + _latestDraggableOffset = null; + } + + widget.onDragEnd?.call(); + }, + onTapDown: (TapDownDetails details) { + if (!controller.value.isInitialized) { + return; + } + _seekToRelativePosition(details.globalPosition); + }, + child: child, + ) : child; } } @@ -136,7 +135,7 @@ class StaticProgressBar extends StatelessWidget { }); final Offset? latestDraggableOffset; - final VideoPlayerValue value; + final OmniVideoValue value; final ChewieProgressColors colors; final double barHeight; @@ -152,12 +151,10 @@ class StaticProgressBar extends StatelessWidget { child: CustomPaint( painter: _ProgressBarPainter( value: value, - draggableValue: latestDraggableOffset != null - ? context.calcRelativePosition( - value.duration, - latestDraggableOffset!, - ) - : null, + draggableValue: + latestDraggableOffset != null + ? context.calcRelativePosition(value.duration, latestDraggableOffset!) + : null, colors: colors, barHeight: barHeight, handleHeight: handleHeight, @@ -178,7 +175,7 @@ class _ProgressBarPainter extends CustomPainter { required this.draggableValue, }); - VideoPlayerValue value; + OmniVideoValue value; ChewieProgressColors colors; final double barHeight; @@ -211,25 +208,15 @@ class _ProgressBarPainter extends CustomPainter { if (!value.isInitialized) { return; } - final double playedPartPercent = (draggableValue != null + final double playedPartPercent = + (draggableValue != null ? draggableValue!.inMilliseconds : value.position.inMilliseconds) / value.duration.inMilliseconds; final double playedPart = playedPartPercent > 1 ? size.width : playedPartPercent * size.width; - for (final DurationRange range in value.buffered) { - final double start = range.startFraction(value.duration) * size.width; - final double end = range.endFraction(value.duration) * size.width; - canvas.drawRRect( - RRect.fromRectAndRadius( - Rect.fromPoints( - Offset(start, baseOffset), - Offset(end, baseOffset + barHeight), - ), - const Radius.circular(4.0), - ), - colors.bufferedPaint, - ); + if (playedPart.isNaN) { + return; } canvas.drawRRect( RRect.fromRectAndRadius( @@ -243,13 +230,13 @@ class _ProgressBarPainter extends CustomPainter { ); if (drawShadow) { - final Path shadowPath = Path() - ..addOval( - Rect.fromCircle( - center: Offset(playedPart, baseOffset + barHeight / 2), - radius: handleHeight, - ), - ); + final Path shadowPath = + Path()..addOval( + Rect.fromCircle( + center: Offset(playedPart, baseOffset + barHeight / 2), + radius: handleHeight, + ), + ); canvas.drawShadow(shadowPath, Colors.black, 0.2, false); } @@ -263,10 +250,7 @@ class _ProgressBarPainter extends CustomPainter { } extension RelativePositionExtensions on BuildContext { - Duration calcRelativePosition( - Duration videoDuration, - Offset globalPosition, - ) { + Duration calcRelativePosition(Duration videoDuration, Offset globalPosition) { final box = findRenderObject()! as RenderBox; final Offset tapPos = box.globalToLocal(globalPosition); final double relative = (tapPos.dx / box.size.width).clamp(0, 1); diff --git a/pubspec.yaml b/pubspec.yaml index 502ff8b43..c14896a7b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,16 +4,19 @@ version: 1.11.1 homepage: https://github.com/fluttercommunity/chewie environment: - sdk: '>=3.6.0 <4.0.0' - flutter: ">=3.27.0" + sdk: '>=3.7.2 <4.0.0' + flutter: ">=3.29.2" dependencies: - cupertino_icons: ^1.0.8 flutter: sdk: flutter - provider: ^6.1.2 - video_player: ^2.9.3 - wakelock_plus: ^1.2.10 + cupertino_icons: "1.0.8" + provider: "6.1.2" + video_player: "2.9.5" + wakelock_plus: "1.2.10" + media_kit: "1.2.0" + media_kit_video: "1.3.0" + media_kit_libs_video: "1.0.6" dev_dependencies: flutter_test: diff --git a/test/uninitialized_controls_state_test.dart b/test/uninitialized_controls_state_test.dart index 0b538784a..bc3f9bc4c 100644 --- a/test/uninitialized_controls_state_test.dart +++ b/test/uninitialized_controls_state_test.dart @@ -1,115 +1,115 @@ -import 'package:chewie/chewie.dart'; -import 'package:chewie/src/center_play_button.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:video_player/video_player.dart'; +// import 'package:chewie/chewie.dart'; +// import 'package:chewie/src/center_play_button.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_test/flutter_test.dart'; +// import 'package:video_player/video_player.dart'; -List srcs = [ - "https://assets.mixkit.co/videos/preview/mixkit-spinning-around-the-earth-29351-large.mp4", - "https://assets.mixkit.co/videos/preview/mixkit-daytime-city-traffic-aerial-view-56-large.mp4", - "https://assets.mixkit.co/videos/preview/mixkit-a-girl-blowing-a-bubble-gum-at-an-amusement-park-1226-large.mp4" -]; +// List srcs = [ +// "https://assets.mixkit.co/videos/preview/mixkit-spinning-around-the-earth-29351-large.mp4", +// "https://assets.mixkit.co/videos/preview/mixkit-daytime-city-traffic-aerial-view-56-large.mp4", +// "https://assets.mixkit.co/videos/preview/mixkit-a-girl-blowing-a-bubble-gum-at-an-amusement-park-1226-large.mp4" +// ]; -main() { - testWidgets("MaterialControls state test", (WidgetTester tester) async { - // Build our app and trigger a frame. - var videoPlayerController = VideoPlayerController.networkUrl( - Uri.parse(srcs[0]), - ); - var materialControlsKey = GlobalKey(); - var chewieController = ChewieController( - videoPlayerController: videoPlayerController, - autoPlay: false, - looping: false, - customControls: MaterialControls( - key: materialControlsKey, - ), - ); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Chewie( - controller: chewieController, - ), - ), - ), - ); +// main() { +// testWidgets("MaterialControls state test", (WidgetTester tester) async { +// // Build our app and trigger a frame. +// var videoPlayerController = VideoPlayerController.networkUrl( +// Uri.parse(srcs[0]), +// ); +// var materialControlsKey = GlobalKey(); +// var chewieController = ChewieController( +// videoPlayerController: videoPlayerController, +// autoPlay: false, +// looping: false, +// customControls: MaterialControls( +// key: materialControlsKey, +// ), +// ); +// await tester.pumpWidget( +// MaterialApp( +// home: Scaffold( +// body: Chewie( +// controller: chewieController, +// ), +// ), +// ), +// ); - await tester.pump(); +// await tester.pump(); - var playButton = find.byType(CenterPlayButton); - expect(playButton, findsOneWidget); - var btn = playButton.first; - var playButtonWidget = tester.widget(btn); - expect(playButtonWidget.isFinished, false); - }); +// var playButton = find.byType(CenterPlayButton); +// expect(playButton, findsOneWidget); +// var btn = playButton.first; +// var playButtonWidget = tester.widget(btn); +// expect(playButtonWidget.isFinished, false); +// }); - testWidgets("CupertinoControls state test", (WidgetTester tester) async { - // Build our app and trigger a frame. - var videoPlayerController = VideoPlayerController.networkUrl( - Uri.parse(srcs[0]), - ); - var materialControlsKey = GlobalKey(); - var chewieController = ChewieController( - videoPlayerController: videoPlayerController, - autoPlay: false, - looping: false, - customControls: CupertinoControls( - key: materialControlsKey, - backgroundColor: Colors.black, - iconColor: Colors.white, - ), - ); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Chewie( - controller: chewieController, - ), - ), - ), - ); +// testWidgets("CupertinoControls state test", (WidgetTester tester) async { +// // Build our app and trigger a frame. +// var videoPlayerController = VideoPlayerController.networkUrl( +// Uri.parse(srcs[0]), +// ); +// var materialControlsKey = GlobalKey(); +// var chewieController = ChewieController( +// videoPlayerController: videoPlayerController, +// autoPlay: false, +// looping: false, +// customControls: CupertinoControls( +// key: materialControlsKey, +// backgroundColor: Colors.black, +// iconColor: Colors.white, +// ), +// ); +// await tester.pumpWidget( +// MaterialApp( +// home: Scaffold( +// body: Chewie( +// controller: chewieController, +// ), +// ), +// ), +// ); - await tester.pump(); +// await tester.pump(); - var playButton = find.byType(CenterPlayButton); - expect(playButton, findsOneWidget); - var btn = playButton.first; - var playButtonWidget = tester.widget(btn); - expect(playButtonWidget.isFinished, false); - }); +// var playButton = find.byType(CenterPlayButton); +// expect(playButton, findsOneWidget); +// var btn = playButton.first; +// var playButtonWidget = tester.widget(btn); +// expect(playButtonWidget.isFinished, false); +// }); - testWidgets("MaterialDesktopControls state test", - (WidgetTester tester) async { - // Build our app and trigger a frame. - var videoPlayerController = VideoPlayerController.networkUrl( - Uri.parse(srcs[0]), - ); - var materialControlsKey = GlobalKey(); - var chewieController = ChewieController( - videoPlayerController: videoPlayerController, - autoPlay: false, - looping: false, - customControls: MaterialDesktopControls( - key: materialControlsKey, - ), - ); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Chewie( - controller: chewieController, - ), - ), - ), - ); +// testWidgets("MaterialDesktopControls state test", +// (WidgetTester tester) async { +// // Build our app and trigger a frame. +// var videoPlayerController = VideoPlayerController.networkUrl( +// Uri.parse(srcs[0]), +// ); +// var materialControlsKey = GlobalKey(); +// var chewieController = ChewieController( +// videoPlayerController: videoPlayerController, +// autoPlay: false, +// looping: false, +// customControls: MaterialDesktopControls( +// key: materialControlsKey, +// ), +// ); +// await tester.pumpWidget( +// MaterialApp( +// home: Scaffold( +// body: Chewie( +// controller: chewieController, +// ), +// ), +// ), +// ); - await tester.pump(); +// await tester.pump(); - var playButton = find.byType(CenterPlayButton); - expect(playButton, findsOneWidget); - var btn = playButton.first; - var playButtonWidget = tester.widget(btn); - expect(playButtonWidget.isFinished, false); - }); -} +// var playButton = find.byType(CenterPlayButton); +// expect(playButton, findsOneWidget); +// var btn = playButton.first; +// var playButtonWidget = tester.widget(btn); +// expect(playButtonWidget.isFinished, false); +// }); +// } From 1e58889075bcc16621ed321ab4f86fe69f1f155b Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Sun, 13 Apr 2025 16:27:30 -0400 Subject: [PATCH 02/11] progress --- lib/src/chewie_player.dart | 41 -------------- lib/src/omni_video_controller.dart | 86 +++++++++++++++++------------- lib/src/player_with_controls.dart | 19 +++++-- 3 files changed, 62 insertions(+), 84 deletions(-) diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index 3833e78b5..cddd5fa0e 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -7,7 +7,6 @@ import 'package:chewie/src/models/subtitle_model.dart'; import 'package:chewie/src/notifiers/player_notifier.dart'; import 'package:chewie/src/omni_video_controller.dart'; import 'package:chewie/src/player_with_controls.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; @@ -168,10 +167,6 @@ class ChewieState extends State { rootNavigator: widget.controller.useRootNavigator, ).push(route); - if (kIsWeb) { - _reInitializeControllers(); - } - _isFullScreen = false; widget.controller.exitFullScreen(); @@ -238,18 +233,6 @@ class ChewieState extends State { } } } - - ///When viewing full screen on web, returning from full screen causes original video to lose the picture. - ///We re initialise controllers for web only when returning from full screen - void _reInitializeControllers() { - final prevPosition = widget.controller.videoPlayerController.value.position; - widget.controller.videoPlayerController.initialize().then((_) async { - widget.controller._initialize(); - widget.controller.videoPlayerController.seekTo(prevPosition); - await widget.controller.videoPlayerController.play(); - widget.controller.videoPlayerController.pause(); - }); - } } /// The ChewieController is used to configure and drive the Chewie Player @@ -266,7 +249,6 @@ class ChewieController extends ChangeNotifier { ChewieController({ required this.videoPlayerController, this.optionsTranslation, - this.aspectRatio, this.autoInitialize = false, this.autoPlay = false, this.draggableProgressBar = true, @@ -319,7 +301,6 @@ class ChewieController extends ChangeNotifier { ChewieController copyWith({ OmniVideoController? videoPlayerController, OptionsTranslation? optionsTranslation, - double? aspectRatio, bool? autoInitialize, bool? autoPlay, bool? draggableProgressBar, @@ -373,7 +354,6 @@ class ChewieController extends ChangeNotifier { videoPlayerController: videoPlayerController ?? this.videoPlayerController, optionsTranslation: optionsTranslation ?? this.optionsTranslation, - aspectRatio: aspectRatio ?? this.aspectRatio, autoInitialize: autoInitialize ?? this.autoInitialize, autoPlay: autoPlay ?? this.autoPlay, startAt: startAt ?? this.startAt, @@ -511,12 +491,6 @@ class ChewieController extends ChangeNotifier { /// When the video is buffering, you can build a custom widget. final WidgetBuilder? bufferingBuilder; - /// The Aspect Ratio of the Video. Important to get the correct size of the - /// video! - /// - /// Will fallback to fitting within the space allowed. - final double? aspectRatio; - /// The colors to use for controls on iOS. By default, the iOS player uses /// colors sampled from the original iOS 11 designs. final ChewieProgressColors? cupertinoProgressColors; @@ -612,27 +586,12 @@ class ChewieController extends ChangeNotifier { } if (autoPlay) { - if (fullScreenByDefault) { - enterFullScreen(); - } - await videoPlayerController.play(); } if (startAt != null) { await videoPlayerController.seekTo(startAt!); } - - if (fullScreenByDefault) { - videoPlayerController.addListener(_fullScreenListener); - } - } - - Future _fullScreenListener() async { - if (videoPlayerController.value.isPlaying && !_isFullScreen) { - enterFullScreen(); - videoPlayerController.removeListener(_fullScreenListener); - } } void enterFullScreen() { diff --git a/lib/src/omni_video_controller.dart b/lib/src/omni_video_controller.dart index a64487f08..8a491edef 100644 --- a/lib/src/omni_video_controller.dart +++ b/lib/src/omni_video_controller.dart @@ -14,11 +14,11 @@ class OmniVideoController { final bool mixAudio; late final OmniVideoValue value; - late final media_kit.Player _iosPlayer; - late final media_kit_video.VideoController _iosController; + late final media_kit.Player iosPlayer; + late final media_kit_video.VideoController iosController; final Map> _iosListeners = {}; - late final video_player.VideoPlayerController _androidController; + late final video_player.VideoPlayerController androidController; OmniVideoController({ required this.url, @@ -27,16 +27,16 @@ class OmniVideoController { this.mixAudio = false, }); - void initalize() async { + Future initialize() async { value = OmniVideoValue(this); if (Platform.isIOS) { - _iosPlayer = media_kit.Player(); - _iosController = media_kit_video.VideoController(_iosPlayer); - await _iosPlayer.open(media_kit.Media(url, httpHeaders: httpHeaders)); + iosPlayer = media_kit.Player(); + iosController = media_kit_video.VideoController(iosPlayer); + await iosPlayer.open(media_kit.Media(url, httpHeaders: httpHeaders)); value.iosInitialized = true; } else { - _androidController = video_player.VideoPlayerController.networkUrl( + androidController = video_player.VideoPlayerController.networkUrl( Uri.parse(url), httpHeaders: httpHeaders, videoPlayerOptions: video_player.VideoPlayerOptions( @@ -56,9 +56,9 @@ class OmniVideoController { void dispose() async { try { if (Platform.isIOS) { - await _iosPlayer.dispose(); + await iosPlayer.dispose(); } else { - await _androidController.dispose(); + await androidController.dispose(); } } catch (e) { // pass @@ -72,12 +72,12 @@ class OmniVideoController { void addPositionListener(void Function() listener) { if (Platform.isIOS) { - final subscription = _iosController.player.stream.position.listen( + final subscription = iosController.player.stream.position.listen( (_) => listener(), ); _iosListeners[listener] = subscription; } else { - _androidController.addListener(listener); + androidController.addListener(listener); } } @@ -88,49 +88,49 @@ class OmniVideoController { subscription.cancel(); } } else { - _androidController.removeListener(listener); + androidController.removeListener(listener); } } Future play() { if (Platform.isIOS) { - return _iosPlayer.play(); + return iosPlayer.play(); } else { - return _androidController.play(); + return androidController.play(); } } Future pause() { if (Platform.isIOS) { - return _iosPlayer.pause(); + return iosPlayer.pause(); } else { - return _androidController.pause(); + return androidController.pause(); } } Future seekTo(Duration position) { if (Platform.isIOS) { - return _iosPlayer.seek(position); + return iosPlayer.seek(position); } else { - return _androidController.seekTo(position); + return androidController.seekTo(position); } } Future setLooping(bool looping) { if (Platform.isIOS) { - return _iosPlayer.setPlaylistMode( + return iosPlayer.setPlaylistMode( looping ? media_kit.PlaylistMode.loop : media_kit.PlaylistMode.none, ); } else { - return _androidController.setLooping(looping); + return androidController.setLooping(looping); } } Future setVolume(double volume) { if (Platform.isIOS) { - return _iosPlayer.setVolume(volume * 100); + return iosPlayer.setVolume(volume * 100); } else { - return _androidController.setVolume(volume); + return androidController.setVolume(volume); } } } @@ -145,47 +145,57 @@ class OmniVideoValue { if (Platform.isIOS) { return iosInitialized; } else { - return ctl._androidController.value.isInitialized; + return ctl.androidController.value.isInitialized; } } bool get isPlaying { if (Platform.isIOS) { - return ctl._iosPlayer.state.playing; + return ctl.iosPlayer.state.playing; } else { - return ctl._androidController.value.isPlaying; + return ctl.androidController.value.isPlaying; } } Duration get duration { if (Platform.isIOS) { - return ctl._iosPlayer.state.duration; + return ctl.iosPlayer.state.duration; } else { - return ctl._androidController.value.duration; + return ctl.androidController.value.duration; } } Duration get position { if (Platform.isIOS) { - return ctl._iosPlayer.state.position; + return ctl.iosPlayer.state.position; } else { - return ctl._androidController.value.position; + return ctl.androidController.value.position; } } Size get size { if (Platform.isIOS) { - final w = ctl._iosPlayer.state.width ?? 100; - final h = ctl._iosPlayer.state.height ?? 100; + final w = ctl.iosPlayer.state.width ?? 100; + final h = ctl.iosPlayer.state.height ?? 100; return Size(w.toDouble(), h.toDouble()); } else { - return ctl._androidController.value.size; + return ctl.androidController.value.size; + } + } + + double get aspectRatio { + if (Platform.isIOS) { + final w = ctl.iosPlayer.state.width ?? 100; + final h = ctl.iosPlayer.state.height ?? 100; + return w.toDouble() / h.toDouble(); + } else { + return ctl.androidController.value.aspectRatio; } } bool get isBuffering { if (Platform.isIOS) { - return ctl._iosPlayer.state.buffering; + return ctl.iosPlayer.state.buffering; } else { /// Gets the current buffering state of the video player. /// @@ -196,18 +206,18 @@ class OmniVideoValue { /// /// For this, the actual buffer position is used to determine if the video is /// buffering or not. See Issue [#912](https://github.com/fluttercommunity/chewie/pull/912) for more details. - if (ctl._androidController.value.isBuffering) { + if (ctl.androidController.value.isBuffering) { // -> Check if we actually buffer, as android has a bug preventing to // get the correct buffering state from this single bool. - final int position = ctl._androidController.value.position.inMilliseconds; + final int position = ctl.androidController.value.position.inMilliseconds; // Special case, if the video is finished, we don't want to show the // buffering indicator anymore - if (position >= ctl._androidController.value.duration.inMilliseconds) { + if (position >= ctl.androidController.value.duration.inMilliseconds) { return false; } else { final int buffer = - ctl._androidController.value.buffered.lastOrNull?.end.inMilliseconds ?? -1; + ctl.androidController.value.buffered.lastOrNull?.end.inMilliseconds ?? -1; return position >= buffer; } diff --git a/lib/src/player_with_controls.dart b/lib/src/player_with_controls.dart index 15d116512..6367d9c71 100644 --- a/lib/src/player_with_controls.dart +++ b/lib/src/player_with_controls.dart @@ -1,8 +1,11 @@ +import 'dart:io'; + import 'package:chewie/src/chewie_player.dart'; import 'package:chewie/src/notifiers/index.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:video_player/video_player.dart'; +import 'package:media_kit_video/media_kit_video.dart' as media_kit_video; +import 'package:video_player/video_player.dart' as video_player; class PlayerWithControls extends StatelessWidget { const PlayerWithControls({super.key}); @@ -39,10 +42,16 @@ class PlayerWithControls extends StatelessWidget { scaleEnabled: chewieController.zoomAndPan, child: Center( child: AspectRatio( - aspectRatio: - chewieController.aspectRatio ?? - chewieController.videoPlayerController.value.aspectRatio, - child: VideoPlayer(chewieController.videoPlayerController), + aspectRatio: chewieController.videoPlayerController.value.aspectRatio, + child: + Platform.isIOS + ? media_kit_video.Video( + controller: + chewieController.videoPlayerController.iosController, + ) + : video_player.VideoPlayer( + chewieController.videoPlayerController.androidController, + ), ), ), ), From eba7ec03c37df056a854741f00f9ccfb0976e86d Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Sun, 13 Apr 2025 16:35:55 -0400 Subject: [PATCH 03/11] progress --- lib/chewie.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/chewie.dart b/lib/chewie.dart index 43aea3944..2cd6a3ad5 100644 --- a/lib/chewie.dart +++ b/lib/chewie.dart @@ -3,4 +3,5 @@ library; export 'src/chewie_player.dart'; export 'src/chewie_progress_colors.dart'; export 'src/material/material_progress_bar.dart'; +export 'src/omni_video_controller.dart'; export 'src/models/index.dart'; From b8617db05edb53b3989c4f727ef55cdbd945f6ff Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Thu, 17 Apr 2025 19:16:50 -0400 Subject: [PATCH 04/11] done? --- lib/src/chewie_player.dart | 341 +++++++++-------------------- lib/src/omni_video_controller.dart | 103 ++++++++- lib/src/player_with_controls.dart | 98 --------- lib/src/progress_bar.dart | 8 +- pubspec.yaml | 1 + 5 files changed, 197 insertions(+), 354 deletions(-) delete mode 100644 lib/src/player_with_controls.dart diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index cddd5fa0e..1f743daa8 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:chewie/src/chewie_progress_colors.dart'; import 'package:chewie/src/models/option_item.dart'; @@ -6,28 +7,27 @@ import 'package:chewie/src/models/options_translation.dart'; import 'package:chewie/src/models/subtitle_model.dart'; import 'package:chewie/src/notifiers/player_notifier.dart'; import 'package:chewie/src/omni_video_controller.dart'; -import 'package:chewie/src/player_with_controls.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; +import 'package:media_kit_video/media_kit_video.dart' as media_kit_video; +import 'package:video_player/video_player.dart' as video_player; -typedef ChewieRoutePageBuilder = Widget Function( - BuildContext context, - Animation animation, - Animation secondaryAnimation, - ChewieControllerProvider controllerProvider, -); +typedef ChewieRoutePageBuilder = + Widget Function( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ChewieControllerProvider controllerProvider, + ); /// A Video Player with Material and Cupertino skins. /// /// `video_player` is pretty low level. Chewie wraps it in a friendly skin to /// make it easy to use! class Chewie extends StatefulWidget { - const Chewie({ - super.key, - required this.controller, - }); + const Chewie({super.key, required this.controller}); /// The [ChewieController] final ChewieController controller; @@ -39,200 +39,98 @@ class Chewie extends StatefulWidget { } class ChewieState extends State { - bool _isFullScreen = false; - - bool get isControllerFullScreen => widget.controller.isFullScreen; - late PlayerNotifier notifier; + bool initialized = false; @override void initState() { super.initState(); - widget.controller.addListener(listener); - notifier = PlayerNotifier.init(); + widget.controller.videoPlayerController.initialize().then((_) { + setState(() { + initialized = true; // Update the state + }); + widget.controller.videoPlayerController.play(); + }); } @override void dispose() { - widget.controller.removeListener(listener); - notifier.dispose(); + widget.controller.videoPlayerController.dispose(); super.dispose(); } - @override - void didUpdateWidget(Chewie oldWidget) { - if (oldWidget.controller != widget.controller) { - widget.controller.addListener(listener); - } - super.didUpdateWidget(oldWidget); - if (_isFullScreen != isControllerFullScreen) { - widget.controller._isFullScreen = _isFullScreen; - } - } - - Future listener() async { - if (isControllerFullScreen && !_isFullScreen) { - _isFullScreen = isControllerFullScreen; - await _pushFullScreenWidget(context); - } else if (_isFullScreen) { - Navigator.of( - context, - rootNavigator: widget.controller.useRootNavigator, - ).pop(); - _isFullScreen = false; - } - } - @override Widget build(BuildContext context) { - return ChewieControllerProvider( - controller: widget.controller, - child: ChangeNotifierProvider.value( - value: notifier, - builder: (context, w) => const PlayerWithControls(), - ), - ); - } + double calculateAspectRatio(BuildContext context) { + final size = MediaQuery.of(context).size; + final width = size.width; + final height = size.height; - Widget _buildFullScreenVideo( - BuildContext context, - Animation animation, - ChewieControllerProvider controllerProvider, - ) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: Container( - alignment: Alignment.center, - color: Colors.black, - child: controllerProvider, - ), - ); - } - - AnimatedWidget _defaultRoutePageBuilder( - BuildContext context, - Animation animation, - Animation secondaryAnimation, - ChewieControllerProvider controllerProvider, - ) { - return AnimatedBuilder( - animation: animation, - builder: (BuildContext context, Widget? child) { - return _buildFullScreenVideo(context, animation, controllerProvider); - }, - ); - } - - Widget _fullScreenRoutePageBuilder( - BuildContext context, - Animation animation, - Animation secondaryAnimation, - ) { - final controllerProvider = ChewieControllerProvider( - controller: widget.controller, - child: ChangeNotifierProvider.value( - value: notifier, - builder: (context, w) => const PlayerWithControls(), - ), - ); - - if (widget.controller.routePageBuilder == null) { - return _defaultRoutePageBuilder( - context, - animation, - secondaryAnimation, - controllerProvider, - ); + return width > height ? width / height : height / width; } - return widget.controller.routePageBuilder!( - context, - animation, - secondaryAnimation, - controllerProvider, - ); - } - - Future _pushFullScreenWidget(BuildContext context) async { - final TransitionRoute route = PageRouteBuilder( - pageBuilder: _fullScreenRoutePageBuilder, - ); - onEnterFullScreen(); - - if (!widget.controller.allowedScreenSleep) { - WakelockPlus.enable(); + Widget buildControls(BuildContext context, ChewieController chewieController) { + return chewieController.showControls + ? chewieController.customControls + : const SizedBox(); } - await Navigator.of( - context, - rootNavigator: widget.controller.useRootNavigator, - ).push(route); - - _isFullScreen = false; - widget.controller.exitFullScreen(); - - if (!widget.controller.allowedScreenSleep) { - WakelockPlus.disable(); + Widget buildPlayerWithControls( + ChewieController chewieController, + BuildContext context, + ) { + return Stack( + children: [ + if (chewieController.placeholder != null) chewieController.placeholder!, + InteractiveViewer( + transformationController: chewieController.transformationController, + maxScale: chewieController.maxScale, + panEnabled: chewieController.zoomAndPan, + scaleEnabled: chewieController.zoomAndPan, + child: + Platform.isIOS + ? media_kit_video.Video( + controller: chewieController.videoPlayerController.iosController, + controls: media_kit_video.NoVideoControls, + ) + : Center( + child: AspectRatio( + aspectRatio: + initialized + ? chewieController.videoPlayerController.value.aspectRatio + : 9 / 16, + child: video_player.VideoPlayer( + chewieController.videoPlayerController.androidController, + ), + ), + ), + ), + if (chewieController.overlay != null) chewieController.overlay!, + if (!chewieController.isFullScreen) + buildControls(context, chewieController) + else + SafeArea(bottom: false, child: buildControls(context, chewieController)), + ], + ); } - SystemChrome.setEnabledSystemUIMode( - SystemUiMode.manual, - overlays: widget.controller.systemOverlaysAfterFullScreen, - ); - SystemChrome.setPreferredOrientations( - widget.controller.deviceOrientationsAfterFullScreen, + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return ChewieControllerProvider( + controller: widget.controller, + child: Center( + child: SizedBox( + height: constraints.maxHeight, + width: constraints.maxWidth, + child: AspectRatio( + aspectRatio: calculateAspectRatio(context), + child: buildPlayerWithControls(widget.controller, context), + ), + ), + ), + ); + }, ); } - - void onEnterFullScreen() { - final videoWidth = widget.controller.videoPlayerController.value.size.width; - final videoHeight = - widget.controller.videoPlayerController.value.size.height; - - SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); - - // if (widget.controller.systemOverlaysOnEnterFullScreen != null) { - // /// Optional user preferred settings - // SystemChrome.setEnabledSystemUIMode( - // SystemUiMode.manual, - // overlays: widget.controller.systemOverlaysOnEnterFullScreen, - // ); - // } else { - // /// Default behavior - // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); - // } - - if (widget.controller.deviceOrientationsOnEnterFullScreen != null) { - /// Optional user preferred settings - SystemChrome.setPreferredOrientations( - widget.controller.deviceOrientationsOnEnterFullScreen!, - ); - } else { - final isLandscapeVideo = videoWidth > videoHeight; - final isPortraitVideo = videoWidth < videoHeight; - - /// Default behavior - /// Video w > h means we force landscape - if (isLandscapeVideo) { - SystemChrome.setPreferredOrientations([ - DeviceOrientation.landscapeLeft, - DeviceOrientation.landscapeRight, - ]); - } - - /// Video h > w means we force portrait - else if (isPortraitVideo) { - SystemChrome.setPreferredOrientations([ - DeviceOrientation.portraitUp, - DeviceOrientation.portraitDown, - ]); - } - - /// Otherwise if h == w (square video) - else { - SystemChrome.setPreferredOrientations(DeviceOrientation.values); - } - } - } } /// The ChewieController is used to configure and drive the Chewie Player @@ -252,8 +150,6 @@ class ChewieController extends ChangeNotifier { this.autoInitialize = false, this.autoPlay = false, this.draggableProgressBar = true, - this.startAt, - this.looping = false, this.fullScreenByDefault = false, this.cupertinoProgressColors, this.materialProgressColors, @@ -292,11 +188,9 @@ class ChewieController extends ChangeNotifier { this.controlsSafeAreaMinimum = EdgeInsets.zero, this.pauseOnBackgroundTap = false, }) : assert( - playbackSpeeds.every((speed) => speed > 0), - 'The playbackSpeeds values must all be greater than 0', - ) { - _initialize(); - } + playbackSpeeds.every((speed) => speed > 0), + 'The playbackSpeeds values must all be greater than 0', + ); ChewieController copyWith({ OmniVideoController? videoPlayerController, @@ -304,7 +198,6 @@ class ChewieController extends ChangeNotifier { bool? autoInitialize, bool? autoPlay, bool? draggableProgressBar, - Duration? startAt, bool? looping, bool? fullScreenByDefault, ChewieProgressColors? cupertinoProgressColors, @@ -346,31 +239,25 @@ class ChewieController extends ChangeNotifier { Animation, Animation, ChewieControllerProvider, - )? routePageBuilder, + )? + routePageBuilder, bool? pauseOnBackgroundTap, }) { return ChewieController( draggableProgressBar: draggableProgressBar ?? this.draggableProgressBar, - videoPlayerController: - videoPlayerController ?? this.videoPlayerController, + videoPlayerController: videoPlayerController ?? this.videoPlayerController, optionsTranslation: optionsTranslation ?? this.optionsTranslation, autoInitialize: autoInitialize ?? this.autoInitialize, autoPlay: autoPlay ?? this.autoPlay, - startAt: startAt ?? this.startAt, - looping: looping ?? this.looping, fullScreenByDefault: fullScreenByDefault ?? this.fullScreenByDefault, - cupertinoProgressColors: - cupertinoProgressColors ?? this.cupertinoProgressColors, - materialProgressColors: - materialProgressColors ?? this.materialProgressColors, + cupertinoProgressColors: cupertinoProgressColors ?? this.cupertinoProgressColors, + materialProgressColors: materialProgressColors ?? this.materialProgressColors, materialSeekButtonFadeDuration: materialSeekButtonFadeDuration ?? this.materialSeekButtonFadeDuration, - materialSeekButtonSize: - materialSeekButtonSize ?? this.materialSeekButtonSize, + materialSeekButtonSize: materialSeekButtonSize ?? this.materialSeekButtonSize, placeholder: placeholder ?? this.placeholder, overlay: overlay ?? this.overlay, - showControlsOnInitialize: - showControlsOnInitialize ?? this.showControlsOnInitialize, + showControlsOnInitialize: showControlsOnInitialize ?? this.showControlsOnInitialize, showOptions: showOptions ?? this.showOptions, optionsBuilder: optionsBuilder ?? this.optionsBuilder, additionalOptions: additionalOptions ?? this.additionalOptions, @@ -389,19 +276,17 @@ class ChewieController extends ChangeNotifier { allowPlaybackSpeedChanging ?? this.allowPlaybackSpeedChanging, useRootNavigator: useRootNavigator ?? this.useRootNavigator, playbackSpeeds: playbackSpeeds ?? this.playbackSpeeds, - systemOverlaysOnEnterFullScreen: systemOverlaysOnEnterFullScreen ?? - this.systemOverlaysOnEnterFullScreen, + systemOverlaysOnEnterFullScreen: + systemOverlaysOnEnterFullScreen ?? this.systemOverlaysOnEnterFullScreen, deviceOrientationsOnEnterFullScreen: - deviceOrientationsOnEnterFullScreen ?? - this.deviceOrientationsOnEnterFullScreen, + deviceOrientationsOnEnterFullScreen ?? this.deviceOrientationsOnEnterFullScreen, systemOverlaysAfterFullScreen: systemOverlaysAfterFullScreen ?? this.systemOverlaysAfterFullScreen, - deviceOrientationsAfterFullScreen: deviceOrientationsAfterFullScreen ?? - this.deviceOrientationsAfterFullScreen, + deviceOrientationsAfterFullScreen: + deviceOrientationsAfterFullScreen ?? this.deviceOrientationsAfterFullScreen, routePageBuilder: routePageBuilder ?? this.routePageBuilder, hideControlsTimer: hideControlsTimer ?? this.hideControlsTimer, - progressIndicatorDelay: - progressIndicatorDelay ?? this.progressIndicatorDelay, + progressIndicatorDelay: progressIndicatorDelay ?? this.progressIndicatorDelay, pauseOnBackgroundTap: pauseOnBackgroundTap ?? this.pauseOnBackgroundTap, ); } @@ -426,10 +311,8 @@ class ChewieController extends ChangeNotifier { /// the builder method. Just add your own options to the Widget /// you'll build. If you want to hide the chewieOptions, just leave them /// out from your Widget. - final Future Function( - BuildContext context, - List chewieOptions, - )? optionsBuilder; + final Future Function(BuildContext context, List chewieOptions)? + optionsBuilder; /// Add your own additional options on top of chewie options final List Function(BuildContext context)? additionalOptions; @@ -458,12 +341,6 @@ class ChewieController extends ChangeNotifier { /// Non-Draggable Progress Bar final bool draggableProgressBar; - /// Start video at a certain position - final Duration? startAt; - - /// Whether or not the video should loop - final bool looping; - /// Wether or not to show the controls when initializing the widget. final bool showControlsOnInitialize; @@ -485,8 +362,7 @@ class ChewieController extends ChangeNotifier { /// When the video playback runs into an error, you can build a custom /// error message. - final Widget Function(BuildContext context, String errorMessage)? - errorBuilder; + final Widget Function(BuildContext context, String errorMessage)? errorBuilder; /// When the video is buffering, you can build a custom widget. final WidgetBuilder? bufferingBuilder; @@ -577,23 +453,6 @@ class ChewieController extends ChangeNotifier { bool get isPlaying => videoPlayerController.value.isPlaying; - Future _initialize() async { - await videoPlayerController.setLooping(looping); - - if ((autoInitialize || autoPlay) && - !videoPlayerController.value.isInitialized) { - await videoPlayerController.initialize(); - } - - if (autoPlay) { - await videoPlayerController.play(); - } - - if (startAt != null) { - await videoPlayerController.seekTo(startAt!); - } - } - void enterFullScreen() { _isFullScreen = true; notifyListeners(); diff --git a/lib/src/omni_video_controller.dart b/lib/src/omni_video_controller.dart index 8a491edef..52e00b4c9 100644 --- a/lib/src/omni_video_controller.dart +++ b/lib/src/omni_video_controller.dart @@ -1,18 +1,26 @@ import 'dart:async'; import 'dart:io' show Platform; +import 'package:async/async.dart'; import 'package:flutter/services.dart'; import 'package:video_player/video_player.dart' as video_player; import 'package:media_kit/media_kit.dart' as media_kit; import 'package:media_kit_video/media_kit_video.dart' as media_kit_video; import 'package:wakelock_plus/wakelock_plus.dart'; +// You must manually call this in the client app's main() if using mediakit +void initializeMediaKit() { + media_kit.MediaKit.ensureInitialized(); +} + class OmniVideoController { final String url; final Map httpHeaders; final bool backgroundPlayback; final bool mixAudio; late final OmniVideoValue value; + bool hasInitBeenCalled = false; + bool hasDisposeBeenCalled = false; late final media_kit.Player iosPlayer; late final media_kit_video.VideoController iosController; @@ -25,15 +33,19 @@ class OmniVideoController { this.httpHeaders = const {}, this.backgroundPlayback = false, this.mixAudio = false, - }); - - Future initialize() async { + }) { value = OmniVideoValue(this); + } + Future initialize() async { + if (hasInitBeenCalled) { + return; + } + hasInitBeenCalled = true; if (Platform.isIOS) { iosPlayer = media_kit.Player(); iosController = media_kit_video.VideoController(iosPlayer); - await iosPlayer.open(media_kit.Media(url, httpHeaders: httpHeaders)); + await iosPlayer.open(media_kit.Media(url, httpHeaders: httpHeaders), play: true); value.iosInitialized = true; } else { androidController = video_player.VideoPlayerController.networkUrl( @@ -44,7 +56,7 @@ class OmniVideoController { mixWithOthers: mixAudio, ), ); - // todo probably initialize android manually ?? maybe idk + await androidController.initialize(); } try { await WakelockPlus.enable(); @@ -53,7 +65,11 @@ class OmniVideoController { } } - void dispose() async { + Future dispose() async { + if (hasDisposeBeenCalled) { + return; + } + hasDisposeBeenCalled = true; try { if (Platform.isIOS) { await iosPlayer.dispose(); @@ -70,11 +86,30 @@ class OmniVideoController { } } + void addStateListener(void Function() listener) { + if (Platform.isIOS) { + final merged = StreamGroup.merge([ + iosPlayer.stream.buffering, + iosPlayer.stream.bufferingPercentage, + iosPlayer.stream.completed, + iosPlayer.stream.duration, + iosPlayer.stream.error, + iosPlayer.stream.playing, + iosPlayer.stream.position, + iosPlayer.stream.rate, + iosPlayer.stream.volume, + ]); + + final subscription = merged.listen((_) => listener()); + _iosListeners[listener] = subscription; + } else { + androidController.addListener(listener); + } + } + void addPositionListener(void Function() listener) { if (Platform.isIOS) { - final subscription = iosController.player.stream.position.listen( - (_) => listener(), - ); + final subscription = iosController.player.stream.position.listen((_) => listener()); _iosListeners[listener] = subscription; } else { androidController.addListener(listener); @@ -133,6 +168,14 @@ class OmniVideoController { return androidController.setVolume(volume); } } + + Future setPlaybackSpeed(double speed) { + if (Platform.isIOS) { + return iosPlayer.setRate(speed); + } else { + return androidController.setPlaybackSpeed(speed); + } + } } class OmniVideoValue { @@ -142,10 +185,14 @@ class OmniVideoValue { OmniVideoValue(this.ctl); bool get isInitialized { - if (Platform.isIOS) { - return iosInitialized; + if (ctl.hasInitBeenCalled) { + if (Platform.isIOS) { + return iosInitialized; + } else { + return ctl.androidController.value.isInitialized; + } } else { - return ctl.androidController.value.isInitialized; + return false; } } @@ -193,6 +240,22 @@ class OmniVideoValue { } } + double get volume { + if (Platform.isIOS) { + return ctl.iosPlayer.state.volume; + } else { + return ctl.androidController.value.volume; + } + } + + double get playbackSpeed { + if (Platform.isIOS) { + return ctl.iosPlayer.state.rate; + } else { + return ctl.androidController.value.playbackSpeed; + } + } + bool get isBuffering { if (Platform.isIOS) { return ctl.iosPlayer.state.buffering; @@ -226,4 +289,20 @@ class OmniVideoValue { } } } + + bool get hasError { + if (Platform.isIOS) { + return false; + } else { + return ctl.androidController.value.hasError; + } + } + + String? get errorDescription { + if (Platform.isIOS) { + return null; + } else { + return ctl.androidController.value.errorDescription; + } + } } diff --git a/lib/src/player_with_controls.dart b/lib/src/player_with_controls.dart deleted file mode 100644 index 6367d9c71..000000000 --- a/lib/src/player_with_controls.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'dart:io'; - -import 'package:chewie/src/chewie_player.dart'; -import 'package:chewie/src/notifiers/index.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:media_kit_video/media_kit_video.dart' as media_kit_video; -import 'package:video_player/video_player.dart' as video_player; - -class PlayerWithControls extends StatelessWidget { - const PlayerWithControls({super.key}); - - @override - Widget build(BuildContext context) { - final ChewieController chewieController = ChewieController.of(context); - - double calculateAspectRatio(BuildContext context) { - final size = MediaQuery.of(context).size; - final width = size.width; - final height = size.height; - - return width > height ? width / height : height / width; - } - - Widget buildControls(BuildContext context, ChewieController chewieController) { - return chewieController.showControls - ? chewieController.customControls - : const SizedBox(); - } - - Widget buildPlayerWithControls( - ChewieController chewieController, - BuildContext context, - ) { - return Stack( - children: [ - if (chewieController.placeholder != null) chewieController.placeholder!, - InteractiveViewer( - transformationController: chewieController.transformationController, - maxScale: chewieController.maxScale, - panEnabled: chewieController.zoomAndPan, - scaleEnabled: chewieController.zoomAndPan, - child: Center( - child: AspectRatio( - aspectRatio: chewieController.videoPlayerController.value.aspectRatio, - child: - Platform.isIOS - ? media_kit_video.Video( - controller: - chewieController.videoPlayerController.iosController, - ) - : video_player.VideoPlayer( - chewieController.videoPlayerController.androidController, - ), - ), - ), - ), - if (chewieController.overlay != null) chewieController.overlay!, - if (Theme.of(context).platform != TargetPlatform.iOS) - Consumer( - builder: - (BuildContext context, PlayerNotifier notifier, Widget? widget) => - Visibility( - visible: !notifier.hideStuff, - child: AnimatedOpacity( - opacity: notifier.hideStuff ? 0.0 : 0.8, - duration: const Duration(milliseconds: 250), - child: const DecoratedBox( - decoration: BoxDecoration(color: Colors.black54), - child: SizedBox.expand(), - ), - ), - ), - ), - if (!chewieController.isFullScreen) - buildControls(context, chewieController) - else - SafeArea(bottom: false, child: buildControls(context, chewieController)), - ], - ); - } - - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Center( - child: SizedBox( - height: constraints.maxHeight, - width: constraints.maxWidth, - child: AspectRatio( - aspectRatio: calculateAspectRatio(context), - child: buildPlayerWithControls(chewieController, context), - ), - ), - ); - }, - ); - } -} diff --git a/lib/src/progress_bar.dart b/lib/src/progress_bar.dart index 46b686921..9da0ad44e 100644 --- a/lib/src/progress_bar.dart +++ b/lib/src/progress_bar.dart @@ -1,3 +1,5 @@ +import 'dart:math' as math; + import 'package:chewie/chewie.dart'; import 'package:chewie/src/omni_video_controller.dart'; import 'package:flutter/material.dart'; @@ -59,9 +61,9 @@ class _VideoProgressBarState extends State { } void _seekToRelativePosition(Offset globalPosition) { - controller.seekTo( - context.calcRelativePosition(controller.value.duration, globalPosition), - ); + final end = Duration(milliseconds: controller.value.duration.inMilliseconds - 1000); + final seek = context.calcRelativePosition(controller.value.duration, globalPosition); + controller.seekTo(seek < end ? seek : end); } @override diff --git a/pubspec.yaml b/pubspec.yaml index c14896a7b..47be81f44 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: provider: "6.1.2" video_player: "2.9.5" wakelock_plus: "1.2.10" + async: "2.12.0" media_kit: "1.2.0" media_kit_video: "1.3.0" media_kit_libs_video: "1.0.6" From 3d5ff49f7d68b308800e13263a18c5d4320bdb45 Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Thu, 17 Apr 2025 19:26:01 -0400 Subject: [PATCH 05/11] done? --- lib/src/omni_video_controller.dart | 9 --------- lib/src/progress_bar.dart | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/lib/src/omni_video_controller.dart b/lib/src/omni_video_controller.dart index 52e00b4c9..6e17331d7 100644 --- a/lib/src/omni_video_controller.dart +++ b/lib/src/omni_video_controller.dart @@ -107,15 +107,6 @@ class OmniVideoController { } } - void addPositionListener(void Function() listener) { - if (Platform.isIOS) { - final subscription = iosController.player.stream.position.listen((_) => listener()); - _iosListeners[listener] = subscription; - } else { - androidController.addListener(listener); - } - } - void removeListener(void Function() listener) { if (Platform.isIOS) { final subscription = _iosListeners.remove(listener); diff --git a/lib/src/progress_bar.dart b/lib/src/progress_bar.dart index 9da0ad44e..1f8ad930e 100644 --- a/lib/src/progress_bar.dart +++ b/lib/src/progress_bar.dart @@ -51,7 +51,7 @@ class _VideoProgressBarState extends State { @override void initState() { super.initState(); - controller.addPositionListener(listener); + controller.addStateListener(listener); } @override From 198f6f8082dca04dc1553a14d8f13bf3288ec312 Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Thu, 17 Apr 2025 19:37:01 -0400 Subject: [PATCH 06/11] fix volume --- lib/src/omni_video_controller.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/omni_video_controller.dart b/lib/src/omni_video_controller.dart index 6e17331d7..f5c86d4f7 100644 --- a/lib/src/omni_video_controller.dart +++ b/lib/src/omni_video_controller.dart @@ -231,9 +231,10 @@ class OmniVideoValue { } } + // from 0 to 1 double get volume { if (Platform.isIOS) { - return ctl.iosPlayer.state.volume; + return ctl.iosPlayer.state.volume / 100.0; } else { return ctl.androidController.value.volume; } From 4c9c8e4f241b85487028c85c9a374aa8a524441f Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Sat, 24 May 2025 05:00:02 -0400 Subject: [PATCH 07/11] update async --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 47be81f44..c1fc50a7f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: provider: "6.1.2" video_player: "2.9.5" wakelock_plus: "1.2.10" - async: "2.12.0" + async: "2.13.0" media_kit: "1.2.0" media_kit_video: "1.3.0" media_kit_libs_video: "1.0.6" From 9f6a54da6435eb6c4f5337a6118bceefb1eeb8e8 Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Thu, 26 Jun 2025 22:51:38 -0400 Subject: [PATCH 08/11] fix android aspect ratio change --- lib/src/chewie_player.dart | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index 1f743daa8..90c556343 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -39,15 +39,23 @@ class Chewie extends StatefulWidget { } class ChewieState extends State { - bool initialized = false; + double exoAspectRatio = 9 / 16; @override void initState() { super.initState(); - widget.controller.videoPlayerController.initialize().then((_) { - setState(() { - initialized = true; // Update the state + if (Platform.isAndroid) { + widget.controller.videoPlayerController.addStateListener(() { + final newAspectRatio = widget.controller.videoPlayerController.value.aspectRatio; + if (mounted && newAspectRatio != exoAspectRatio) { + setState(() { + exoAspectRatio = newAspectRatio; + }); + } }); + } + + widget.controller.videoPlayerController.initialize().then((_) { widget.controller.videoPlayerController.play(); }); } @@ -94,10 +102,7 @@ class ChewieState extends State { ) : Center( child: AspectRatio( - aspectRatio: - initialized - ? chewieController.videoPlayerController.value.aspectRatio - : 9 / 16, + aspectRatio: exoAspectRatio, child: video_player.VideoPlayer( chewieController.videoPlayerController.androidController, ), From 744e88360251fc507127b65e382d4ec40d9999a7 Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Thu, 26 Jun 2025 22:53:21 -0400 Subject: [PATCH 09/11] fix android aspect ratio change pt2 --- lib/src/chewie_player.dart | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index 90c556343..03ff55f9b 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -44,18 +44,19 @@ class ChewieState extends State { @override void initState() { super.initState(); - if (Platform.isAndroid) { - widget.controller.videoPlayerController.addStateListener(() { - final newAspectRatio = widget.controller.videoPlayerController.value.aspectRatio; - if (mounted && newAspectRatio != exoAspectRatio) { - setState(() { - exoAspectRatio = newAspectRatio; - }); - } - }); - } widget.controller.videoPlayerController.initialize().then((_) { + if (Platform.isAndroid) { + widget.controller.videoPlayerController.addStateListener(() { + final newAspectRatio = + widget.controller.videoPlayerController.value.aspectRatio; + if (mounted && newAspectRatio != exoAspectRatio) { + setState(() { + exoAspectRatio = newAspectRatio; + }); + } + }); + } widget.controller.videoPlayerController.play(); }); } From 974b445a5c0215f8c2d29a5289d7be001cf81be7 Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Thu, 26 Jun 2025 23:24:21 -0400 Subject: [PATCH 10/11] force mediakit option --- lib/src/chewie_player.dart | 4 +-- lib/src/omni_video_controller.dart | 47 ++++++++++++++++-------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index 03ff55f9b..53beaa9b0 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -39,7 +39,7 @@ class Chewie extends StatefulWidget { } class ChewieState extends State { - double exoAspectRatio = 9 / 16; + double exoAspectRatio = 9 / 18; @override void initState() { @@ -96,7 +96,7 @@ class ChewieState extends State { panEnabled: chewieController.zoomAndPan, scaleEnabled: chewieController.zoomAndPan, child: - Platform.isIOS + alwaysUseMediaKit || Platform.isIOS ? media_kit_video.Video( controller: chewieController.videoPlayerController.iosController, controls: media_kit_video.NoVideoControls, diff --git a/lib/src/omni_video_controller.dart b/lib/src/omni_video_controller.dart index f5c86d4f7..338418fa4 100644 --- a/lib/src/omni_video_controller.dart +++ b/lib/src/omni_video_controller.dart @@ -8,8 +8,11 @@ import 'package:media_kit/media_kit.dart' as media_kit; import 'package:media_kit_video/media_kit_video.dart' as media_kit_video; import 'package:wakelock_plus/wakelock_plus.dart'; +var alwaysUseMediaKit = false; + // You must manually call this in the client app's main() if using mediakit -void initializeMediaKit() { +void initializeMediaKit(bool useMediaKit) { + alwaysUseMediaKit = useMediaKit; media_kit.MediaKit.ensureInitialized(); } @@ -42,7 +45,7 @@ class OmniVideoController { return; } hasInitBeenCalled = true; - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { iosPlayer = media_kit.Player(); iosController = media_kit_video.VideoController(iosPlayer); await iosPlayer.open(media_kit.Media(url, httpHeaders: httpHeaders), play: true); @@ -71,7 +74,7 @@ class OmniVideoController { } hasDisposeBeenCalled = true; try { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { await iosPlayer.dispose(); } else { await androidController.dispose(); @@ -87,7 +90,7 @@ class OmniVideoController { } void addStateListener(void Function() listener) { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { final merged = StreamGroup.merge([ iosPlayer.stream.buffering, iosPlayer.stream.bufferingPercentage, @@ -108,7 +111,7 @@ class OmniVideoController { } void removeListener(void Function() listener) { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { final subscription = _iosListeners.remove(listener); if (subscription != null) { subscription.cancel(); @@ -119,7 +122,7 @@ class OmniVideoController { } Future play() { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return iosPlayer.play(); } else { return androidController.play(); @@ -127,7 +130,7 @@ class OmniVideoController { } Future pause() { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return iosPlayer.pause(); } else { return androidController.pause(); @@ -135,7 +138,7 @@ class OmniVideoController { } Future seekTo(Duration position) { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return iosPlayer.seek(position); } else { return androidController.seekTo(position); @@ -143,7 +146,7 @@ class OmniVideoController { } Future setLooping(bool looping) { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return iosPlayer.setPlaylistMode( looping ? media_kit.PlaylistMode.loop : media_kit.PlaylistMode.none, ); @@ -153,7 +156,7 @@ class OmniVideoController { } Future setVolume(double volume) { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return iosPlayer.setVolume(volume * 100); } else { return androidController.setVolume(volume); @@ -161,7 +164,7 @@ class OmniVideoController { } Future setPlaybackSpeed(double speed) { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return iosPlayer.setRate(speed); } else { return androidController.setPlaybackSpeed(speed); @@ -177,7 +180,7 @@ class OmniVideoValue { bool get isInitialized { if (ctl.hasInitBeenCalled) { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return iosInitialized; } else { return ctl.androidController.value.isInitialized; @@ -188,7 +191,7 @@ class OmniVideoValue { } bool get isPlaying { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return ctl.iosPlayer.state.playing; } else { return ctl.androidController.value.isPlaying; @@ -196,7 +199,7 @@ class OmniVideoValue { } Duration get duration { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return ctl.iosPlayer.state.duration; } else { return ctl.androidController.value.duration; @@ -204,7 +207,7 @@ class OmniVideoValue { } Duration get position { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return ctl.iosPlayer.state.position; } else { return ctl.androidController.value.position; @@ -212,7 +215,7 @@ class OmniVideoValue { } Size get size { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { final w = ctl.iosPlayer.state.width ?? 100; final h = ctl.iosPlayer.state.height ?? 100; return Size(w.toDouble(), h.toDouble()); @@ -222,7 +225,7 @@ class OmniVideoValue { } double get aspectRatio { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { final w = ctl.iosPlayer.state.width ?? 100; final h = ctl.iosPlayer.state.height ?? 100; return w.toDouble() / h.toDouble(); @@ -233,7 +236,7 @@ class OmniVideoValue { // from 0 to 1 double get volume { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return ctl.iosPlayer.state.volume / 100.0; } else { return ctl.androidController.value.volume; @@ -241,7 +244,7 @@ class OmniVideoValue { } double get playbackSpeed { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return ctl.iosPlayer.state.rate; } else { return ctl.androidController.value.playbackSpeed; @@ -249,7 +252,7 @@ class OmniVideoValue { } bool get isBuffering { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return ctl.iosPlayer.state.buffering; } else { /// Gets the current buffering state of the video player. @@ -283,7 +286,7 @@ class OmniVideoValue { } bool get hasError { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return false; } else { return ctl.androidController.value.hasError; @@ -291,7 +294,7 @@ class OmniVideoValue { } String? get errorDescription { - if (Platform.isIOS) { + if (alwaysUseMediaKit || Platform.isIOS) { return null; } else { return ctl.androidController.value.errorDescription; From be0c174be8fe45974ae1462e1e8ba5b7821ce511 Mon Sep 17 00:00:00 2001 From: Israel Madueme Date: Mon, 30 Jun 2025 15:05:39 -0400 Subject: [PATCH 11/11] use mediakit option --- lib/src/chewie_player.dart | 2 +- lib/src/omni_video_controller.dart | 56 ++++++++++++++++-------------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index 53beaa9b0..d73fee57b 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -96,7 +96,7 @@ class ChewieState extends State { panEnabled: chewieController.zoomAndPan, scaleEnabled: chewieController.zoomAndPan, child: - alwaysUseMediaKit || Platform.isIOS + useMediaKit ? media_kit_video.Video( controller: chewieController.videoPlayerController.iosController, controls: media_kit_video.NoVideoControls, diff --git a/lib/src/omni_video_controller.dart b/lib/src/omni_video_controller.dart index 338418fa4..c2488d5f1 100644 --- a/lib/src/omni_video_controller.dart +++ b/lib/src/omni_video_controller.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io' show Platform; import 'package:async/async.dart'; import 'package:flutter/services.dart'; @@ -8,12 +7,17 @@ import 'package:media_kit/media_kit.dart' as media_kit; import 'package:media_kit_video/media_kit_video.dart' as media_kit_video; import 'package:wakelock_plus/wakelock_plus.dart'; -var alwaysUseMediaKit = false; +var useMediaKit = false; + +void setUseMediaKit(bool shouldUse) { + useMediaKit = shouldUse; +} // You must manually call this in the client app's main() if using mediakit -void initializeMediaKit(bool useMediaKit) { - alwaysUseMediaKit = useMediaKit; - media_kit.MediaKit.ensureInitialized(); +void initializeMediaKit() { + if (useMediaKit) { + media_kit.MediaKit.ensureInitialized(); + } } class OmniVideoController { @@ -45,7 +49,7 @@ class OmniVideoController { return; } hasInitBeenCalled = true; - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { iosPlayer = media_kit.Player(); iosController = media_kit_video.VideoController(iosPlayer); await iosPlayer.open(media_kit.Media(url, httpHeaders: httpHeaders), play: true); @@ -74,7 +78,7 @@ class OmniVideoController { } hasDisposeBeenCalled = true; try { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { await iosPlayer.dispose(); } else { await androidController.dispose(); @@ -90,7 +94,7 @@ class OmniVideoController { } void addStateListener(void Function() listener) { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { final merged = StreamGroup.merge([ iosPlayer.stream.buffering, iosPlayer.stream.bufferingPercentage, @@ -111,7 +115,7 @@ class OmniVideoController { } void removeListener(void Function() listener) { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { final subscription = _iosListeners.remove(listener); if (subscription != null) { subscription.cancel(); @@ -122,7 +126,7 @@ class OmniVideoController { } Future play() { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return iosPlayer.play(); } else { return androidController.play(); @@ -130,7 +134,7 @@ class OmniVideoController { } Future pause() { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return iosPlayer.pause(); } else { return androidController.pause(); @@ -138,7 +142,7 @@ class OmniVideoController { } Future seekTo(Duration position) { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return iosPlayer.seek(position); } else { return androidController.seekTo(position); @@ -146,7 +150,7 @@ class OmniVideoController { } Future setLooping(bool looping) { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return iosPlayer.setPlaylistMode( looping ? media_kit.PlaylistMode.loop : media_kit.PlaylistMode.none, ); @@ -156,7 +160,7 @@ class OmniVideoController { } Future setVolume(double volume) { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return iosPlayer.setVolume(volume * 100); } else { return androidController.setVolume(volume); @@ -164,7 +168,7 @@ class OmniVideoController { } Future setPlaybackSpeed(double speed) { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return iosPlayer.setRate(speed); } else { return androidController.setPlaybackSpeed(speed); @@ -180,7 +184,7 @@ class OmniVideoValue { bool get isInitialized { if (ctl.hasInitBeenCalled) { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return iosInitialized; } else { return ctl.androidController.value.isInitialized; @@ -191,7 +195,7 @@ class OmniVideoValue { } bool get isPlaying { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return ctl.iosPlayer.state.playing; } else { return ctl.androidController.value.isPlaying; @@ -199,7 +203,7 @@ class OmniVideoValue { } Duration get duration { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return ctl.iosPlayer.state.duration; } else { return ctl.androidController.value.duration; @@ -207,7 +211,7 @@ class OmniVideoValue { } Duration get position { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return ctl.iosPlayer.state.position; } else { return ctl.androidController.value.position; @@ -215,7 +219,7 @@ class OmniVideoValue { } Size get size { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { final w = ctl.iosPlayer.state.width ?? 100; final h = ctl.iosPlayer.state.height ?? 100; return Size(w.toDouble(), h.toDouble()); @@ -225,7 +229,7 @@ class OmniVideoValue { } double get aspectRatio { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { final w = ctl.iosPlayer.state.width ?? 100; final h = ctl.iosPlayer.state.height ?? 100; return w.toDouble() / h.toDouble(); @@ -236,7 +240,7 @@ class OmniVideoValue { // from 0 to 1 double get volume { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return ctl.iosPlayer.state.volume / 100.0; } else { return ctl.androidController.value.volume; @@ -244,7 +248,7 @@ class OmniVideoValue { } double get playbackSpeed { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return ctl.iosPlayer.state.rate; } else { return ctl.androidController.value.playbackSpeed; @@ -252,7 +256,7 @@ class OmniVideoValue { } bool get isBuffering { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return ctl.iosPlayer.state.buffering; } else { /// Gets the current buffering state of the video player. @@ -286,7 +290,7 @@ class OmniVideoValue { } bool get hasError { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return false; } else { return ctl.androidController.value.hasError; @@ -294,7 +298,7 @@ class OmniVideoValue { } String? get errorDescription { - if (alwaysUseMediaKit || Platform.isIOS) { + if (useMediaKit) { return null; } else { return ctl.androidController.value.errorDescription;