Skip to content

Commit 0dc424c

Browse files
committed
fix: start coder connect progress indicator immediately
1 parent 62c3d0a commit 0dc424c

File tree

2 files changed

+53
-21
lines changed

2 files changed

+53
-21
lines changed

Coder-Desktop/Coder-Desktop/VPN/VPNProgress.swift

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ struct VPNProgressView: View {
1313
var body: some View {
1414
VStack {
1515
CircularProgressView(value: value)
16-
// We estimate that the last half takes 8 seconds
16+
// We estimate the duration of the last 35%
1717
// so it doesn't appear stuck
18-
.autoComplete(threshold: 0.5, duration: 8)
18+
.autoComplete(threshold: 0.65, duration: 8)
19+
// We estimate the duration of the first 25% (spawning Helper)
20+
// so it doesn't appear stuck
21+
.autoStart(until: 0.25, duration: 2)
1922
Text(progressMessage)
2023
.multilineTextAlignment(.center)
2124
}
@@ -46,16 +49,16 @@ struct VPNProgressView: View {
4649
guard let downloadProgress = progress.downloadProgress else {
4750
// We can't make this illegal state unrepresentable because XPC
4851
// doesn't support enums with associated values.
49-
return 0.05
52+
return 0.15
5053
}
5154
// 35MB if the server doesn't give us the expected size
5255
let totalBytes = downloadProgress.totalBytesToWrite ?? 35_000_000
5356
let downloadPercent = min(1.0, Float(downloadProgress.totalBytesWritten) / Float(totalBytes))
54-
return 0.4 * downloadPercent
57+
return 0.25 + (0.35 * downloadPercent)
5558
case .validating:
56-
return 0.43
59+
return 0.63
5760
case .startingTunnel:
58-
return 0.50
61+
return 0.65
5962
}
6063
}
6164
}

Coder-Desktop/Coder-Desktop/Views/CircularProgressView.swift

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,24 @@ import SwiftUI
33
struct CircularProgressView: View {
44
let value: Float?
55

6-
var strokeWidth: CGFloat = 4
7-
var diameter: CGFloat = 22
6+
var strokeWidth: CGFloat
7+
var diameter: CGFloat
88
var primaryColor: Color = .secondary
99
var backgroundColor: Color = .secondary.opacity(0.3)
1010

11-
var autoCompleteThreshold: Float?
12-
var autoCompleteDuration: TimeInterval?
11+
private var autoComplete: (threshold: Float, duration: TimeInterval)?
12+
private var autoStart: (until: Float, duration: TimeInterval)?
13+
14+
@State private var currentProgress: Float = 0
15+
16+
init(value: Float? = nil,
17+
strokeWidth: CGFloat = 4,
18+
diameter: CGFloat = 22)
19+
{
20+
self.value = value
21+
self.strokeWidth = strokeWidth
22+
self.diameter = diameter
23+
}
1324

1425
var body: some View {
1526
ZStack {
@@ -19,13 +30,23 @@ struct CircularProgressView: View {
1930
.stroke(backgroundColor, style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round))
2031

2132
Circle()
22-
.trim(from: 0, to: CGFloat(displayValue(for: value)))
33+
.trim(from: 0, to: CGFloat(displayValue(for: currentProgress)))
2334
.stroke(primaryColor, style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round))
2435
.rotationEffect(.degrees(-90))
25-
.animation(autoCompleteAnimation(for: value), value: value)
2636
}
2737
.frame(width: diameter, height: diameter)
28-
38+
.onAppear {
39+
if let autoStart, value == 0 {
40+
withAnimation(.easeOut(duration: autoStart.duration)) {
41+
currentProgress = autoStart.until
42+
}
43+
}
44+
}
45+
.onChange(of: value) {
46+
withAnimation(currentAnimation(for: value)) {
47+
currentProgress = value
48+
}
49+
}
2950
} else {
3051
IndeterminateSpinnerView(
3152
diameter: diameter,
@@ -40,31 +61,39 @@ struct CircularProgressView: View {
4061
}
4162

4263
private func displayValue(for value: Float) -> Float {
43-
if let threshold = autoCompleteThreshold,
64+
if let threshold = autoComplete?.threshold,
4465
value >= threshold, value < 1.0
4566
{
4667
return 1.0
4768
}
4869
return value
4970
}
5071

51-
private func autoCompleteAnimation(for value: Float) -> Animation? {
52-
guard let threshold = autoCompleteThreshold,
53-
let duration = autoCompleteDuration,
54-
value >= threshold, value < 1.0
72+
private func currentAnimation(for value: Float) -> Animation {
73+
guard let autoComplete,
74+
value >= autoComplete.threshold, value < 1.0
5575
else {
76+
// Use the auto-start animation if it's running, otherwise default.
77+
if let autoStart {
78+
return .easeOut(duration: autoStart.duration)
79+
}
5680
return .default
5781
}
5882

59-
return .easeOut(duration: duration)
83+
return .easeOut(duration: autoComplete.duration)
6084
}
6185
}
6286

6387
extension CircularProgressView {
6488
func autoComplete(threshold: Float, duration: TimeInterval) -> CircularProgressView {
6589
var view = self
66-
view.autoCompleteThreshold = threshold
67-
view.autoCompleteDuration = duration
90+
view.autoComplete = (threshold: threshold, duration: duration)
91+
return view
92+
}
93+
94+
func autoStart(until value: Float, duration: TimeInterval) -> CircularProgressView {
95+
var view = self
96+
view.autoStart = (until: value, duration: duration)
6897
return view
6998
}
7099
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy