Show connection progress at app startup instead of flashing screens

This commit is contained in:
Ian Gulliver
2026-10-20 14:20:35 -07:00
parent da7f952855
commit a2571763b4
3 changed files with 80 additions and 26 deletions
+32 -12
View File
@@ -198,6 +198,9 @@ final class Connection {
private func start() async {
let old = store
while !stopped, !Tailnet.shared.running {
try? await Task.sleep(for: .milliseconds(500))
}
while !stopped, !(await attempt(old)) {
try? await Task.sleep(for: .seconds(2))
}
@@ -251,7 +254,7 @@ final class Connection {
} catch {
await store.stop()
if !stopped {
phase = .failed("byre failed to start: \(errorText(error))")
phase = .failed(explain(error, origin))
}
return false
}
@@ -437,15 +440,27 @@ struct ConnectView: View {
}
}
struct FatalView: View {
let message: String
struct ConnectingView: View {
let step: String
var problem: String?
var body: some View {
Text(message)
.foregroundStyle(Palette.danger)
.textSelection(.enabled)
.padding(24)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
VStack(alignment: .leading, spacing: 10) {
HStack(spacing: 10) {
ProgressView()
.controlSize(.small)
Text(step)
}
if let problem {
Text("Retrying: \(problem)")
.foregroundStyle(Palette.muted)
.textSelection(.enabled)
.fixedSize(horizontal: false, vertical: true)
}
}
.frame(width: 460, alignment: .leading)
.padding(.vertical, 24)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
@@ -477,20 +492,25 @@ struct ServerWindow: View {
@ViewBuilder
private var content: some View {
if !Tailnet.shared.signedIn {
if Tailnet.shared.needsLogin {
TailnetLoginView()
} else if !Tailnet.shared.running {
ConnectingView(step: "Starting Tailscale…")
} else if let connection {
let step = "Connecting to \(serverName(connection.origin.absoluteString))…"
switch connection.phase {
case .starting:
Color.clear
case .failed(let message):
FatalView(message: message)
ConnectingView(step: step)
case .failed(let problem):
ConnectingView(step: step, problem: problem)
case .running(let store):
MainView()
.environment(store)
.environment(connection.overlays)
.id(ObjectIdentifier(store))
}
} else if !Tailnet.shared.searched {
ConnectingView(step: "Looking for byre servers on the tailnet…")
} else {
ConnectView(form: form) { connected in
form.serverText = ""