summaryrefslogtreecommitdiff
path: root/macos/Sources/Features/Update/UpdateBadge.swift
blob: fd1eb34989c3e57293d7bf26ba54ac88541e3ab5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import SwiftUI

/// A badge view that displays the current state of an update operation.
///
/// Shows different visual indicators based on the update state:
/// - Progress ring for downloading/extracting with progress
/// - Animated rotating icon for checking/installing
/// - Static icon for other states
struct UpdateBadge: View {
    /// The update view model that provides the current state and progress
    @ObservedObject var model: UpdateViewModel
    
    /// Current rotation angle for animated icon states
    @State private var rotationAngle: Double = 0
    
    var body: some View {
        switch model.state {
        case .downloading(let download):
            if let expectedLength = download.expectedLength, expectedLength > 0 {
                let progress = Double(download.progress) / Double(expectedLength)
                ProgressRingView(progress: progress)
            } else {
                Image(systemName: "arrow.down.circle")
            }
            
        case .extracting(let extracting):
            ProgressRingView(progress: extracting.progress)
            
        case .checking, .installing:
            if let iconName = model.iconName {
                Image(systemName: iconName)
                    .rotationEffect(.degrees(rotationAngle))
                    .onAppear {
                        withAnimation(.linear(duration: 2.5).repeatForever(autoreverses: false)) {
                            rotationAngle = 360
                        }
                    }
                    .onDisappear {
                        rotationAngle = 0
                    }
            }
            
        default:
            if let iconName = model.iconName {
                Image(systemName: iconName)
            }
        }
    }
}

/// A circular progress indicator with a stroke-based ring design.
///
/// Displays a partially filled circle that represents progress from 0.0 to 1.0.
fileprivate struct ProgressRingView: View {
    /// The current progress value, ranging from 0.0 (empty) to 1.0 (complete)
    let progress: Double
    
    /// The width of the progress ring stroke
    let lineWidth: CGFloat = 2
    
    var body: some View {
        ZStack {
            Circle()
                .stroke(Color.primary.opacity(0.2), lineWidth: lineWidth)
            
            Circle()
                .trim(from: 0, to: progress)
                .stroke(Color.primary, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
                .rotationEffect(.degrees(-90))
                .animation(.easeInOut(duration: 0.2), value: progress)
        }
    }
}