From d613b5a90f3a0d783c4e7bcee55c8aed22e72cdb Mon Sep 17 00:00:00 2001 From: Kyle Hickinson Date: Wed, 9 Apr 2025 09:53:59 -0400 Subject: [PATCH] [iOS] Update Playlist timestamp formatting when content over 1 hour long (#28497) This replaces the hardcoded minute second formatting used on the scrubber to dynamically include the hour if the duration is 60 minutes or longer --- .../Sources/PlaylistUI/MediaScrubber.swift | 18 ++++++++----- .../Sources/PlaylistUI/PlayerView.swift | 4 +-- .../Sources/PlaylistUI/PlaylistItemView.swift | 2 +- .../PlaylistUI/TimestampFormatStyle.swift | 25 +++++++++++++++++++ 4 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 ios/brave-ios/Sources/PlaylistUI/TimestampFormatStyle.swift diff --git a/ios/brave-ios/Sources/PlaylistUI/MediaScrubber.swift b/ios/brave-ios/Sources/PlaylistUI/MediaScrubber.swift index 9d1ea710743..ea2fff9418f 100644 --- a/ios/brave-ios/Sources/PlaylistUI/MediaScrubber.swift +++ b/ios/brave-ios/Sources/PlaylistUI/MediaScrubber.swift @@ -39,7 +39,7 @@ struct MediaScrubber: View { @Environment(\.layoutDirection) private var layoutDirection private var currentValueLabel: Text { - return Text(.seconds(currentTime), format: .time(pattern: .minuteSecond)) + return Text(.seconds(currentTime), format: .timestamp) } @ViewBuilder private var remainingTimeLabel: some View { @@ -47,7 +47,7 @@ struct MediaScrubber: View { case .unknown: EmptyView() case .seconds(let duration): - Text(.seconds(currentTime - duration), format: .time(pattern: .minuteSecond)) + Text(.seconds(currentTime - duration), format: .timestamp) case .indefinite: Text(Strings.Playlist.liveIndicator) } @@ -55,7 +55,7 @@ struct MediaScrubber: View { private var durationLabel: Text { if case .seconds(let duration) = duration { - return Text(.seconds(duration), format: .time(pattern: .minuteSecond)) + return Text(.seconds(duration), format: .timestamp) } return Text("") } @@ -202,7 +202,7 @@ struct DefaultMediaScrubberLabel: View { var body: some View { HStack { - Text(.seconds(currentTime), format: .time(pattern: .minuteSecond)) + Text(.seconds(currentTime), format: .timestamp) Spacer() switch duration { case .unknown: @@ -214,9 +214,9 @@ struct DefaultMediaScrubberLabel: View { } label: { Group { if isShowingTotalTime { - Text(.seconds(duration), format: .time(pattern: .minuteSecond)) + Text(.seconds(duration), format: .timestamp) } else { - Text(.seconds(currentTime - duration), format: .time(pattern: .minuteSecond)) + Text(.seconds(currentTime - duration), format: .timestamp) } } .transition(.move(edge: .trailing).combined(with: .opacity)) @@ -248,6 +248,12 @@ private struct MediaScrubberPreview: View { isScrubbing: $isScrubbing ) .padding() + MediaScrubber( + currentTime: $currentTime, + duration: .seconds(3600), + isScrubbing: $isScrubbing + ) + .padding() MediaScrubber( currentTime: $currentTime, duration: .seconds(1000), diff --git a/ios/brave-ios/Sources/PlaylistUI/PlayerView.swift b/ios/brave-ios/Sources/PlaylistUI/PlayerView.swift index 93b1b4808f0..e580942afdc 100644 --- a/ios/brave-ios/Sources/PlaylistUI/PlayerView.swift +++ b/ios/brave-ios/Sources/PlaylistUI/PlayerView.swift @@ -353,7 +353,7 @@ struct CompactMediaScrubberLabel: View { var duration: PlayerModel.ItemDuration private var currentValueLabel: Text { - return Text(.seconds(currentTime), format: .time(pattern: .minuteSecond)) + return Text(.seconds(currentTime), format: .timestamp) } var body: some View { @@ -361,7 +361,7 @@ struct CompactMediaScrubberLabel: View { currentValueLabel if case .seconds(let duration) = duration { Text(verbatim: "/") // FIXME: Does this need some sort of localization? - Text(.seconds(currentTime - duration), format: .time(pattern: .minuteSecond)) + Text(.seconds(currentTime - duration), format: .timestamp) } } .font(.caption2) diff --git a/ios/brave-ios/Sources/PlaylistUI/PlaylistItemView.swift b/ios/brave-ios/Sources/PlaylistUI/PlaylistItemView.swift index 6726f6d39a0..cc167aedd64 100644 --- a/ios/brave-ios/Sources/PlaylistUI/PlaylistItemView.swift +++ b/ios/brave-ios/Sources/PlaylistUI/PlaylistItemView.swift @@ -57,7 +57,7 @@ struct PlaylistItemView: View { switch duration { case .seconds(let duration): if duration > 0 { - Text(.seconds(duration), format: .time(pattern: .minuteSecond)) + Text(.seconds(duration), format: .timestamp) } else { EmptyView() } diff --git a/ios/brave-ios/Sources/PlaylistUI/TimestampFormatStyle.swift b/ios/brave-ios/Sources/PlaylistUI/TimestampFormatStyle.swift new file mode 100644 index 00000000000..7a5e95bc3ad --- /dev/null +++ b/ios/brave-ios/Sources/PlaylistUI/TimestampFormatStyle.swift @@ -0,0 +1,25 @@ +// Copyright (c) 2025 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +import Foundation + +/// Formats a Duration dynamically based on if the value is over an hour. +struct TimestampFormatStyle: FormatStyle { + func format(_ value: Duration) -> String { + let pattern: Duration.TimeFormatStyle.Pattern + if abs(value.components.seconds) >= (60 * 60) { + pattern = .hourMinuteSecond + } else { + pattern = .minuteSecond + } + return value.formatted(.time(pattern: pattern)) + } +} + +extension FormatStyle where Self == TimestampFormatStyle { + static var timestamp: TimestampFormatStyle { + .init() + } +}