diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2e361db1..81deb5bc0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,11 +2,7 @@ name: CI on: pull_request: - paths-ignore: - - '**.md' - push: - branches: - - master + types: [opened, synchronize, reopened] paths-ignore: - '**.md' workflow_dispatch: @@ -15,7 +11,41 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + # Define global environment variables for the workflow + # The version of Flutter to use should use the minimum Dart SDK version supported by the package, + # refer to https://docs.flutter.dev/development/tools/sdk/releases. + # Note: The version below should be manually updated to the latest second most recent version + # after a new stable version comes out. + # Current minimum is set to Flutter 3.29. Make this the new minimum once the next + # stable version is released + FLUTTER_VERSION_MINIMUM_DEFAULT: "3.29.3" + FLUTTER_VERSION_LATEST_STABLE_CHANNEL_DEFAULT: "3.x" + jobs: + setup_matrix: + name: Determine Flutter Test Versions # Name for the setup_matrix job + runs-on: ubuntu-latest + outputs: + flutter_versions_json: ${{ steps.set_versions.outputs.versions_json }} + flutter_version_minimum: ${{ steps.set_versions.outputs.version_min }} + steps: + - name: Determine Flutter versions + id: set_versions + run: | + MIN_VERSION_VALUE="${{ env.FLUTTER_VERSION_MINIMUM_DEFAULT }}" + LATEST_VERSION_VALUE="${{ env.FLUTTER_VERSION_LATEST_STABLE_CHANNEL_DEFAULT }}" + + echo "version_min=$MIN_VERSION_VALUE" >> $GITHUB_OUTPUT + echo "version_latest=$LATEST_VERSION_VALUE" >> $GITHUB_OUTPUT + + VERSIONS_JSON=$(jq -c --null-input '$ARGS.positional' --args "$MIN_VERSION_VALUE" "$LATEST_VERSION_VALUE") + echo "versions_json=$VERSIONS_JSON" >> $GITHUB_OUTPUT + + echo "Determined Min Version: $MIN_VERSION_VALUE" + echo "Determined Latest Version: $LATEST_VERSION_VALUE" + echo "Determined JSON: $VERSIONS_JSON" + # Does a sanity check that packages at least pass analysis on the N-1 # versions of Flutter stable if the package claims to support that version. # This is to minimize accidentally making changes that break old versions @@ -23,16 +53,14 @@ jobs: # without updating the constraints. lint_and_build: name: Flutter Version ${{ matrix.flutter-version }} Lint and Build. + needs: setup_matrix # Ensures this job runs after setup_matrix completes runs-on: ubuntu-latest + env: + SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + FLUTTER_VERSION_MINIMUM: ${{ needs.setup_matrix.outputs.flutter_version_minimum }} strategy: matrix: - flutter-version: - # The version of Flutter to use should use the minimum Dart SDK version supported by the package, - # refer to https://docs.flutter.dev/development/tools/sdk/releases. - # Note: The version below should be manually updated to the latest second most recent version - # after a new stable version comes out. - - "3.29.3" - - "3.x" + flutter-version: ${{ fromJSON(needs.setup_matrix.outputs.flutter_versions_json) }} fail-fast: false steps: - name: 📚 Git Checkout @@ -51,6 +79,10 @@ jobs: - name: ✨ Check Formatting run: dart format --set-exit-if-changed lib + # Only continue on error if this is the job for the MINIMUM Flutter version + # This allows formatting issues to be warnings on older supported versions + # but enforces them on the latest stable or primary development version. + continue-on-error: ${{ matrix.flutter-version == env.FLUTTER_VERSION_MINIMUM }} - name: 🕵️ Analyze run: flutter analyze lib diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index d2622405e..84fedd3aa 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -31,7 +31,7 @@ if (keystorePropertiesFile.exists()) { android { namespace "com.example.example" - compileSdk 34 + compileSdk 35 compileOptions { sourceCompatibility JavaVersion.VERSION_17 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index ab6356343..638b434e2 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -10,7 +10,6 @@ 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 */; }; @@ -50,11 +49,8 @@ 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 = ""; }; @@ -63,7 +59,6 @@ 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 */ @@ -80,7 +75,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5B171717BA079CE808D1B32C /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -93,9 +87,6 @@ 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; @@ -105,7 +96,6 @@ isa = PBXGroup; children = ( 161F52A253A901BB69307277 /* Pods_Runner.framework */, - 73C604A80B929E096139088E /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -172,7 +162,6 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 3FADDB6B4D6AA8657115BAF4 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, ADF676FEC51290FAF51E0789 /* Frameworks */, @@ -303,28 +292,6 @@ 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; @@ -488,7 +455,6 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CCE42FB5D8CBF00852B83E23 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -506,7 +472,6 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 75018BE4F219FC27188BF5C2 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -522,7 +487,6 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6D5C22CEED22C7791375B03E /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 8e3ca5dfe..e3773d42e 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> diff --git a/example/lib/app/app.dart b/example/lib/app/app.dart index 7bd09c598..ce3f46efa 100644 --- a/example/lib/app/app.dart +++ b/example/lib/app/app.dart @@ -109,6 +109,7 @@ class _ChewieDemoState extends State { _chewieController = ChewieController( videoPlayerController: _videoPlayerController1, autoPlay: true, + zoomAndPan: true, looping: true, progressIndicatorDelay: bufferDelay != null ? Duration(milliseconds: bufferDelay!) : null, diff --git a/lib/src/chewie_player.dart b/lib/src/chewie_player.dart index 463140167..6c98a3caf 100644 --- a/lib/src/chewie_player.dart +++ b/lib/src/chewie_player.dart @@ -380,6 +380,12 @@ class ChewieController extends ChangeNotifier { cupertinoProgressColors ?? this.cupertinoProgressColors, materialProgressColors: materialProgressColors ?? this.materialProgressColors, + zoomAndPan: zoomAndPan ?? this.zoomAndPan, + maxScale: maxScale ?? this.maxScale, + controlsSafeAreaMinimum: + controlsSafeAreaMinimum ?? this.controlsSafeAreaMinimum, + transformationController: + transformationController ?? this.transformationController, materialSeekButtonFadeDuration: materialSeekButtonFadeDuration ?? this.materialSeekButtonFadeDuration, materialSeekButtonSize: @@ -490,10 +496,14 @@ class ChewieController extends ChangeNotifier { /// Whether or not to show the controls at all final bool showControls; - /// Controller to pass into the [InteractiveViewer] component + /// Controller to pass into the [InteractiveViewer] component. + /// If it is required to control the transformation only via the controller, + /// `zoomAndPan` should be set to false. final TransformationController? transformationController; - /// Whether or not to allow zooming and panning + /// Whether or not to allow zooming and panning. + /// This can still be false, and the `transformationController` can be used to control the + /// transformation. final bool zoomAndPan; /// Max scale when zooming diff --git a/lib/src/player_with_controls.dart b/lib/src/player_with_controls.dart index f394a4541..a8d974020 100644 --- a/lib/src/player_with_controls.dart +++ b/lib/src/player_with_controls.dart @@ -33,22 +33,17 @@ class PlayerWithControls extends StatelessWidget { ChewieController chewieController, BuildContext context, ) { - return Stack( - children: [ + final playerNotifier = context.read(); + final child = 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.aspectRatio ?? - chewieController.videoPlayerController.value.aspectRatio, - child: VideoPlayer(chewieController.videoPlayerController), - ), + Center( + child: AspectRatio( + aspectRatio: + chewieController.aspectRatio ?? + chewieController.videoPlayerController.value.aspectRatio, + child: VideoPlayer(chewieController.videoPlayerController), ), ), if (chewieController.overlay != null) chewieController.overlay!, @@ -80,6 +75,27 @@ class PlayerWithControls extends StatelessWidget { ), ], ); + + if (chewieController.zoomAndPan || + chewieController.transformationController != null) { + return InteractiveViewer( + transformationController: chewieController.transformationController, + maxScale: chewieController.maxScale, + panEnabled: chewieController.zoomAndPan, + scaleEnabled: chewieController.zoomAndPan, + onInteractionUpdate: + chewieController.zoomAndPan + ? (_) => playerNotifier.hideStuff = true + : null, + onInteractionEnd: + chewieController.zoomAndPan + ? (_) => playerNotifier.hideStuff = false + : null, + child: child, + ); + } + + return child; } return LayoutBuilder(