diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bd3a9e353..515890420e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/podcasts/MiniPlayerViewController.swift b/podcasts/MiniPlayerViewController.swift index 14e88ccab9..4f5a9ef0f4 100644 --- a/podcasts/MiniPlayerViewController.swift +++ b/podcasts/MiniPlayerViewController.swift @@ -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 @@ -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) @@ -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 }