mirror of
https://github.com/yattee/yattee.git
synced 2026-08-26 08:52:32 +00:00
Fix playback rate display dropping meaningful digits (#963)
PlaybackRate.displayText/compactDisplayText used String(format: "%.2gx"), whose significant-figure notation dropped meaningful digits (1.25 -> "1.2x") and rounded others (1.75 -> "1.8x"). Replace with a fixed two-decimal format + trailing-zero strip so whole rates have no decimal (2 -> "2x"), halves show one (1.5 -> "1.5x"), and quarter-steps are preserved (1.25 -> "1.25x"). Adds a Swift Testing suite (PlaybackRateTests) proving red->green.
This commit is contained in:
@@ -131,13 +131,26 @@ enum PlaybackRate: Double, CaseIterable, Identifiable, Sendable {
|
|||||||
if rawValue == 1.0 {
|
if rawValue == 1.0 {
|
||||||
return String(localized: "player.playbackRate.normal")
|
return String(localized: "player.playbackRate.normal")
|
||||||
}
|
}
|
||||||
return String(format: "%.2gx", rawValue)
|
return formattedRate
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compact display text that always shows numeric value (e.g., "1x", "1.5x").
|
/// Compact display text that always shows numeric value (e.g., "1x", "1.5x").
|
||||||
/// Use this in space-constrained UI like the player pill.
|
/// Use this in space-constrained UI like the player pill.
|
||||||
var compactDisplayText: String {
|
var compactDisplayText: String {
|
||||||
String(format: "%.2gx", rawValue)
|
formattedRate
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The rate with an `x` suffix rendered with a fixed two-decimal format and
|
||||||
|
/// the trailing `.0` stripped, so whole rates have no decimal
|
||||||
|
/// (2 → "2x", 1.5 → "1.5x", 1.25 → "1.25x"). Replaces `%.2g`, whose
|
||||||
|
/// significant-figure notation dropped meaningful digits (1.25 → "1.2") and
|
||||||
|
/// rounded others (1.75 → "1.8"). `String(format:)` keeps the period decimal
|
||||||
|
/// separator, matching the player's other speed labels.
|
||||||
|
private var formattedRate: String {
|
||||||
|
var value = String(format: "%.2f", rawValue)
|
||||||
|
while value.hasSuffix("0") { value.removeLast() }
|
||||||
|
if value.hasSuffix(".") { value.removeLast() }
|
||||||
|
return "\(value)x"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
YatteeTests/PlaybackRateTests.swift
Normal file
51
YatteeTests/PlaybackRateTests.swift
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// PlaybackRateTests.swift
|
||||||
|
// YatteeTests
|
||||||
|
//
|
||||||
|
// Tests for PlaybackRate display-text formatting.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Testing
|
||||||
|
import Foundation
|
||||||
|
@testable import Yattee
|
||||||
|
|
||||||
|
@Suite("PlaybackRate Display Tests")
|
||||||
|
struct PlaybackRateDisplayTests {
|
||||||
|
@Test("displayText renders every rate without losing precision")
|
||||||
|
func displayTextPrecision() {
|
||||||
|
#expect(PlaybackRate.x025.displayText == "0.25x")
|
||||||
|
#expect(PlaybackRate.x05.displayText == "0.5x")
|
||||||
|
#expect(PlaybackRate.x075.displayText == "0.75x")
|
||||||
|
#expect(PlaybackRate.x125.displayText == "1.25x")
|
||||||
|
#expect(PlaybackRate.x15.displayText == "1.5x")
|
||||||
|
#expect(PlaybackRate.x175.displayText == "1.75x")
|
||||||
|
#expect(PlaybackRate.x2.displayText == "2x")
|
||||||
|
#expect(PlaybackRate.x25.displayText == "2.5x")
|
||||||
|
#expect(PlaybackRate.x3.displayText == "3x")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("displayText for the normal rate uses the localized label, not the numeric form")
|
||||||
|
func displayTextNormal() {
|
||||||
|
let normal = PlaybackRate.x1.displayText
|
||||||
|
#expect(normal == String(localized: "player.playbackRate.normal"))
|
||||||
|
#expect(!normal.hasSuffix("x"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("compactDisplayText always shows the numeric value")
|
||||||
|
func compactDisplayText() {
|
||||||
|
#expect(PlaybackRate.x1.compactDisplayText == "1x")
|
||||||
|
#expect(PlaybackRate.x125.compactDisplayText == "1.25x")
|
||||||
|
#expect(PlaybackRate.x15.compactDisplayText == "1.5x")
|
||||||
|
#expect(PlaybackRate.x175.compactDisplayText == "1.75x")
|
||||||
|
#expect(PlaybackRate.x2.compactDisplayText == "2x")
|
||||||
|
#expect(PlaybackRate.x3.compactDisplayText == "3x")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("every case has a non-empty display string")
|
||||||
|
func allCasesNonEmpty() {
|
||||||
|
for rate in PlaybackRate.allCases {
|
||||||
|
#expect(!rate.displayText.isEmpty)
|
||||||
|
#expect(!rate.compactDisplayText.isEmpty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user