Skip to content

Commit

Permalink
Increase playback speed during a long press gesture (#746)
Browse files Browse the repository at this point in the history
  • Loading branch information
waliid authored Jan 22, 2024
1 parent 1db9b9a commit 75057b6
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Demo/Pillarbox-demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
0E4128BF2AFB959B00D67759 /* PlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E4128BE2AFB959B00D67759 /* PlayerViewModel.swift */; };
0E48F3FC2B2DBAD4001982BB /* CustomNavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E48F3FB2B2DBAD4001982BB /* CustomNavigationLink.swift */; };
0E6B995C29D43E4200D0276D /* OptInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6B995B29D43E4200D0276D /* OptInView.swift */; };
0EB94A1F2B5AE29000FF3175 /* HighSpeedView~ios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB94A1E2B5AE29000FF3175 /* HighSpeedView~ios.swift */; };
0ECC5AD52A517A4C0064E701 /* PlaybackSlider~ios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECC5AD42A517A4C0064E701 /* PlaybackSlider~ios.swift */; };
0EDFF0DB2B0740DA005030B4 /* SourceCodeViewable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDFF0DA2B0740DA005030B4 /* SourceCodeViewable.swift */; };
0EE2A3AE2B29D6D000BAAD65 /* CustomList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE2A3AD2B29D6D000BAAD65 /* CustomList.swift */; };
Expand Down Expand Up @@ -98,6 +99,7 @@
0E4128BE2AFB959B00D67759 /* PlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerViewModel.swift; sourceTree = "<group>"; };
0E48F3FB2B2DBAD4001982BB /* CustomNavigationLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationLink.swift; sourceTree = "<group>"; };
0E6B995B29D43E4200D0276D /* OptInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptInView.swift; sourceTree = "<group>"; };
0EB94A1E2B5AE29000FF3175 /* HighSpeedView~ios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HighSpeedView~ios.swift"; sourceTree = "<group>"; };
0ECC5AD42A517A4C0064E701 /* PlaybackSlider~ios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PlaybackSlider~ios.swift"; sourceTree = "<group>"; };
0EDFF0DA2B0740DA005030B4 /* SourceCodeViewable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceCodeViewable.swift; sourceTree = "<group>"; };
0EE2A3AD2B29D6D000BAAD65 /* CustomList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomList.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -381,6 +383,7 @@
0EE2A3AD2B29D6D000BAAD65 /* CustomList.swift */,
0E48F3FB2B2DBAD4001982BB /* CustomNavigationLink.swift */,
0EE2A3AF2B29F82200BAAD65 /* CustomSection.swift */,
0EB94A1E2B5AE29000FF3175 /* HighSpeedView~ios.swift */,
0E011D192B2DF9BE00DAAD3D /* MediaCardView.swift */,
6F59E86829CF31E10093E6FB /* MessageViews.swift */,
6FC5D6A12A6FA8D20012BC89 /* Modal.swift */,
Expand Down Expand Up @@ -639,6 +642,7 @@
6F59E88029CF31E10093E6FB /* RadioChannel.swift in Sources */,
6F0E5CD32B3394EA0031E313 /* PiPButton.swift in Sources */,
6F59E89629CF31E20093E6FB /* Cell.swift in Sources */,
0EB94A1F2B5AE29000FF3175 /* HighSpeedView~ios.swift in Sources */,
0EF2A5452B443FEF00F01804 /* WebView~ios.swift in Sources */,
6F59E89A29CF31E20093E6FB /* SimplePlayerView.swift in Sources */,
6F59E89329CF31E20093E6FB /* LinkView.swift in Sources */,
Expand Down
10 changes: 10 additions & 0 deletions Demo/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@
}
}
},
"%g× %@" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "%1$g× %2$@"
}
}
}
},
"Active" : {

},
Expand Down
1 change: 1 addition & 0 deletions Demo/Sources/Players/PlaybackView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ private struct MainView: View {
}
.statusBarHidden(isFullScreen ? isUserInterfaceHidden : false)
.animation(.defaultLinear, value: isUserInterfaceHidden)
.supportsHighSpeed(for: player)
.bind(visibilityTracker, to: player)
._debugBodyCounter()
}
Expand Down
93 changes: 93 additions & 0 deletions Demo/Sources/Views/HighSpeedView~ios.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//
// Copyright (c) SRG SSR. All rights reserved.
//
// License information is available from the LICENSE file.
//

import PillarboxPlayer
import SwiftUI

private struct HighSpeedCapsule: View {
let speed: Float

var body: some View {
Text("\(speed, specifier: "%g×") \(Image(systemName: "forward.fill"))")
.font(.footnote)
.bold()
.padding(.horizontal, 10)
.padding(.vertical, 5)
.foregroundStyle(.white)
.background(.black.opacity(0.7))
.clipShape(Capsule())
}
}

private struct HighSpeedGestureView<Content>: View where Content: View {
@GestureState private var isLongPressing = false
@State private var timer: Timer?

let content: () -> Content
let action: (_ finished: Bool) -> Void

var body: some View {
content()
.simultaneousGesture(longPressGesture())
.onChange(of: isLongPressing) { isPressing in
timer?.invalidate()
if !isPressing {
action(true)
}
else {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
action(false)
}
}
}
}

private func longPressGesture() -> some Gesture {
LongPressGesture(minimumDuration: .infinity, maximumDistance: .infinity)
.updating($isLongPressing) { value, state, _ in
state = value
}
}
}

private struct HighSpeedView<Content>: View where Content: View {
private let highSpeed: Float = 2
@State private var speed: Float?

private var displaysCapsule: Bool {
speed != nil && speed != highSpeed && player.playbackSpeedRange.contains(highSpeed) && player.playbackState == .playing
}

@ObservedObject var player: Player
let content: () -> Content

var body: some View {
HighSpeedGestureView(content: content) { finished in
if !finished {
speed = player.effectivePlaybackSpeed
player.setDesiredPlaybackSpeed(highSpeed)
}
else if let speed {
player.setDesiredPlaybackSpeed(speed)
self.speed = nil
}
}
.overlay(alignment: .top) {
HighSpeedCapsule(speed: highSpeed)
.opacity(displaysCapsule ? 1 : 0)
.animation(.easeInOut(duration: 0.1), value: displaysCapsule)
.padding()
}
}
}

extension View {
func supportsHighSpeed(for player: Player) -> some View {
HighSpeedView(player: player) {
self
}
}
}

0 comments on commit 75057b6

Please sign in to comment.