@@ -22,6 +22,12 @@ struct PlayerBar: View {
2222 @State private var volumeValue : Double = 1.0
2323 @State private var isAdjustingVolume = false
2424
25+ /// Cached formatted progress string to avoid repeated formatting.
26+ @State private var formattedProgress : String = " 0:00 "
27+ @State private var formattedRemaining : String = " -0:00 "
28+ /// Last integer second of progress to reduce string formatting frequency.
29+ @State private var lastProgressSecond : Int = - 1
30+
2531 var body : some View {
2632 GlassEffectContainer ( spacing: 0 ) {
2733 HStack ( spacing: 0 ) {
@@ -102,6 +108,13 @@ struct PlayerBar: View {
102108 if !self . isSeeking, self . playerService. duration > 0 {
103109 self . seekValue = newValue / self . playerService. duration
104110 }
111+ // Only update formatted strings when the second changes to reduce Text view updates
112+ let currentSecond = Int ( newValue)
113+ if currentSecond != self . lastProgressSecond {
114+ self . lastProgressSecond = currentSecond
115+ self . formattedProgress = self . formatTime ( newValue)
116+ self . formattedRemaining = " - \( self . formatTime ( self . playerService. duration - newValue) ) "
117+ }
105118 }
106119 . onChange ( of: self . playerService. volume) { _, newValue in
107120 // Sync local volume value when not actively adjusting
@@ -175,11 +188,12 @@ struct PlayerBar: View {
175188
176189 private var seekBarView : some View {
177190 HStack ( spacing: 10 ) {
178- // Elapsed time - show seek position while dragging, actual progress otherwise
179- Text ( self . formatTime ( self . isSeeking ? self . seekValue * self . playerService. duration : self . playerService . progress ) )
191+ // Elapsed time - use cached formatted string when not seeking
192+ Text ( self . isSeeking ? self . formatTime ( self . seekValue * self . playerService. duration) : self . formattedProgress )
180193 . font ( . system( size: 11 ) )
181194 . foregroundStyle ( . secondary)
182195 . frame ( minWidth: 45 , alignment: . trailing)
196+ . monospacedDigit ( )
183197
184198 // Seek slider
185199 Slider ( value: self . $seekValue, in: 0 ... 1 ) { editing in
@@ -193,11 +207,12 @@ struct PlayerBar: View {
193207 }
194208 . controlSize ( . small)
195209
196- // Remaining time
197- Text ( " - \( self . formatTime ( self . playerService. duration - ( self . isSeeking ? self . seekValue * self . playerService. duration : self . playerService . progress ) ) ) " )
210+ // Remaining time - use cached formatted string when not seeking
211+ Text ( self . isSeeking ? " - \( self . formatTime ( self . playerService. duration - self . seekValue * self . playerService. duration) ) " : self . formattedRemaining )
198212 . font ( . system( size: 11 ) )
199213 . foregroundStyle ( . secondary)
200214 . frame ( minWidth: 45 , alignment: . leading)
215+ . monospacedDigit ( )
201216 }
202217 }
203218
0 commit comments