Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
8.16
-----
- Make the Liquid Glass mini player's play button translucent with a springy bounce on tap [#4677](https://github.com/Automattic/pocket-casts-ios/pull/4677)
- Fix the smart playlist and podcast page header showing the system light/dark appearance instead of the in-app theme when scrolling on iOS 18 [#4662](https://github.com/Automattic/pocket-casts-ios/pull/4662)
- Fix episode lists jumping when a background download finishes [#4648](https://github.com/Automattic/pocket-casts-ios/pull/4648)
- Fix a rare crash during playback when an audio buffer fails to allocate [#4645](https://github.com/Automattic/pocket-casts-ios/pull/4645)
Expand Down
39 changes: 36 additions & 3 deletions podcasts/MiniPlayerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class MiniPlayerViewController: SimpleNotificationsViewController {
textStack.alignment = .leading
textStack.spacing = 2

addPlayButtonBounce()
let buttonStack = UIStackView(arrangedSubviews: [skipBackBtn, playPauseBtn, skipFwdBtn])
buttonStack.translatesAutoresizingMaskIntoConstraints = false
buttonStack.axis = .horizontal
Expand Down Expand Up @@ -221,6 +222,33 @@ class MiniPlayerViewController: SimpleNotificationsViewController {
}
}

/// Adds a springy scale-up-and-settle-back response to the play/pause
/// button so the translucent accent circle feels tactile on tap.
private func addPlayButtonBounce() {
playPauseBtn.addTarget(self, action: #selector(playButtonTouchedDown), for: .touchDown)
playPauseBtn.addTarget(self, action: #selector(playButtonReleased), for: [.touchUpInside, .touchUpOutside, .touchCancel])
}

@objc private func playButtonTouchedDown() {
guard !UIAccessibility.isReduceMotionEnabled else { return }
UIView.animate(withDuration: 0.18, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.8, options: [.allowUserInteraction, .beginFromCurrentState]) {
self.playPauseBtn.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
self.playPauseBtn.alpha = 0.75
}
}

@objc private func playButtonReleased() {
guard !UIAccessibility.isReduceMotionEnabled else {
playPauseBtn.transform = .identity
playPauseBtn.alpha = 1
return
}
UIView.animate(withDuration: 0.55, delay: 0, usingSpringWithDamping: 0.35, initialSpringVelocity: 0.7, options: [.allowUserInteraction, .beginFromCurrentState]) {
self.playPauseBtn.transform = .identity
self.playPauseBtn.alpha = 1
}
}

override func updateViewConstraints() {
if #available(iOS 26.0, *), let glassButtonStack, let glassProgressView {
let isInline = forcedInlineLayout ?? (view.traitCollection.tabAccessoryEnvironment == .inline)
Expand Down Expand Up @@ -620,11 +648,16 @@ class MiniPlayerViewController: SimpleNotificationsViewController {
episodeTitleLabel?.textColor = .label
timeLeftModel?.color = Color(ThemeColor.primaryText02())

// A slightly translucent accent circle lets the tab bar's glass show
// through for a vibrant, glassy feel (without the buggy UIGlassEffect).
// The skip glyphs reuse that same translucent accent so all three
// controls share one color.
let accentColor = iconColor.withAlphaComponent(0.8)
playPauseBtn.playButtonColor = bgColor
playPauseBtn.circleColor = iconColor
playPauseBtn.circleColor = accentColor

skipBackBtn.tintColor = iconColor
skipFwdBtn.tintColor = iconColor
skipBackBtn.tintColor = accentColor
skipFwdBtn.tintColor = accentColor

glassProgressView?.tintColorOverride = actionColor
}
Expand Down