From 8942e1f8a5e905291a5fb77196231d8098786bf3 Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Tue, 23 Dec 2025 01:52:05 +0530 Subject: [PATCH] Update Numeric Text transition --- .../components/OSD/CircularHUDView.swift | 11 ++--- .../components/OSD/HUDNumericLabel.swift | 40 +++++++++++++++++++ .../components/OSD/VerticalHUDView.swift | 20 +++++++--- 3 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 DynamicIsland/components/OSD/HUDNumericLabel.swift diff --git a/DynamicIsland/components/OSD/CircularHUDView.swift b/DynamicIsland/components/OSD/CircularHUDView.swift index 26e02df..4b48d7d 100644 --- a/DynamicIsland/components/OSD/CircularHUDView.swift +++ b/DynamicIsland/components/OSD/CircularHUDView.swift @@ -74,11 +74,12 @@ struct CircularHUDView: View { if showValue { VStack { Spacer() - Text("\(Int(value * 100))") - .font(.system(size: size * 0.15, weight: .bold, design: .rounded)) - .foregroundStyle(.white.opacity(0.65)) - .contentTransition(.numericText()) - .padding(.bottom, size * 0.03) + HUDNumericLabel( + value: value, + font: .system(size: size * 0.15, weight: .bold, design: .rounded), + color: .white.opacity(0.65) + ) + .padding(.bottom, size * 0.03) } } diff --git a/DynamicIsland/components/OSD/HUDNumericLabel.swift b/DynamicIsland/components/OSD/HUDNumericLabel.swift new file mode 100644 index 0000000..7464008 --- /dev/null +++ b/DynamicIsland/components/OSD/HUDNumericLabel.swift @@ -0,0 +1,40 @@ +#if os(macOS) +import SwiftUI + +/// Shared numeric label for HUD/OSD styles with rolling value animation. +struct HUDNumericLabel: View { + let value: CGFloat + var font: Font + var color: Color + var alignment: Alignment = .center + var width: CGFloat? = nil + var minimumDigits: Int = 3 + var animation: Animation = .interactiveSpring(response: 0.35, dampingFraction: 0.75, blendDuration: 0.15) + + @State private var animatedValue: CGFloat = 0 + + var body: some View { + Text(formattedValue) + .font(font) + .monospacedDigit() + .foregroundStyle(color) + .contentTransition(.numericText()) + .frame(width: width, alignment: alignment) + .onAppear { + animatedValue = value + } + .onChange(of: value) { newValue in + withAnimation(animation) { + animatedValue = newValue + } + } + } + + private var formattedValue: String { + let clamped = max(0, min(100, Int(round(animatedValue * 100)))) + let digits = max(1, minimumDigits) + let format = "%\(digits)d" + return String(format: format, clamped) + } +} +#endif diff --git a/DynamicIsland/components/OSD/VerticalHUDView.swift b/DynamicIsland/components/OSD/VerticalHUDView.swift index 4b6f88f..29b13f3 100644 --- a/DynamicIsland/components/OSD/VerticalHUDView.swift +++ b/DynamicIsland/components/OSD/VerticalHUDView.swift @@ -73,11 +73,14 @@ struct VerticalHUDView: View { // Icon & Text overlay VStack { if showValue { - Text("\(Int(state.value * 100))%") - .font(.system(size: 10, weight: .bold)) - .foregroundStyle(state.value > 0.85 ? (useAccentColor ? .white : .black) : .secondary) - .padding(.top, 8 + (stretchOffset < 0 ? abs(stretchOffset/4) : 0)) - .contentTransition(.numericText()) + HUDNumericLabel( + value: state.value, + font: .system(size: 10, weight: .bold), + color: valueLabelColor, + alignment: .center, + width: hudWidth * 0.8 + ) + .padding(.top, 8 + (stretchOffset < 0 ? abs(stretchOffset/4) : 0)) } Spacer() @@ -225,5 +228,12 @@ struct VerticalHUDView: View { return AnyShapeStyle(useAccentColor ? Color.accentColor : Color.white) } + + private var valueLabelColor: Color { + if state.value > 0.85 { + return useAccentColor ? .white : .black + } + return .secondary + } } #endif