173 lines
5.7 KiB
Swift
173 lines
5.7 KiB
Swift
|
|
import SwiftUI
|
||
|
|
|
||
|
|
struct WatchSetupView: View {
|
||
|
|
@EnvironmentObject var watchManager: WatchSessionManager
|
||
|
|
|
||
|
|
@State private var showManualAdd = false
|
||
|
|
@State private var isSyncing = false
|
||
|
|
@State private var syncMessage = ""
|
||
|
|
|
||
|
|
var body: some View {
|
||
|
|
ScrollView {
|
||
|
|
VStack(spacing: 16) {
|
||
|
|
Image(systemName: "music.note.house.fill")
|
||
|
|
.font(.system(size: 36))
|
||
|
|
.foregroundColor(.pink)
|
||
|
|
|
||
|
|
Text("Navidrome")
|
||
|
|
.font(.headline)
|
||
|
|
|
||
|
|
Text("Set up your server to play music on your watch.")
|
||
|
|
.font(.caption2)
|
||
|
|
.foregroundColor(.gray)
|
||
|
|
.multilineTextAlignment(.center)
|
||
|
|
.padding(.horizontal)
|
||
|
|
|
||
|
|
// Sync from iPhone
|
||
|
|
Button(action: syncFromPhone) {
|
||
|
|
HStack {
|
||
|
|
if isSyncing {
|
||
|
|
ProgressView()
|
||
|
|
.scaleEffect(0.7)
|
||
|
|
}
|
||
|
|
Text(isSyncing ? "Syncing..." : "Sync from iPhone")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.buttonStyle(.borderedProminent)
|
||
|
|
.tint(.pink)
|
||
|
|
.disabled(isSyncing)
|
||
|
|
|
||
|
|
if !syncMessage.isEmpty {
|
||
|
|
Text(syncMessage)
|
||
|
|
.font(.caption2)
|
||
|
|
.foregroundColor(syncMessage.contains("Error") ? .red : .green)
|
||
|
|
}
|
||
|
|
|
||
|
|
Divider()
|
||
|
|
|
||
|
|
// Manual add
|
||
|
|
Button("Add Server Manually") {
|
||
|
|
showManualAdd = true
|
||
|
|
}
|
||
|
|
.font(.caption)
|
||
|
|
|
||
|
|
if watchManager.isPhoneReachable {
|
||
|
|
HStack(spacing: 4) {
|
||
|
|
Circle()
|
||
|
|
.fill(.green)
|
||
|
|
.frame(width: 6, height: 6)
|
||
|
|
Text("iPhone connected")
|
||
|
|
.font(.caption2)
|
||
|
|
.foregroundColor(.gray)
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
HStack(spacing: 4) {
|
||
|
|
Circle()
|
||
|
|
.fill(.orange)
|
||
|
|
.frame(width: 6, height: 6)
|
||
|
|
Text("iPhone not reachable")
|
||
|
|
.font(.caption2)
|
||
|
|
.foregroundColor(.gray)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.padding()
|
||
|
|
}
|
||
|
|
.sheet(isPresented: $showManualAdd) {
|
||
|
|
WatchAddServerView()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private func syncFromPhone() {
|
||
|
|
isSyncing = true
|
||
|
|
syncMessage = ""
|
||
|
|
watchManager.requestServersFromPhone()
|
||
|
|
|
||
|
|
// Check result after delay
|
||
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||
|
|
isSyncing = false
|
||
|
|
if !watchManager.servers.isEmpty {
|
||
|
|
syncMessage = "Synced \(watchManager.servers.count) server(s)"
|
||
|
|
} else if !watchManager.isPhoneReachable {
|
||
|
|
syncMessage = "Error: iPhone not reachable"
|
||
|
|
} else {
|
||
|
|
syncMessage = "Error: No servers found"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Manual Add Server
|
||
|
|
struct WatchAddServerView: View {
|
||
|
|
@EnvironmentObject var watchManager: WatchSessionManager
|
||
|
|
@Environment(\.dismiss) private var dismiss
|
||
|
|
|
||
|
|
@State private var name = ""
|
||
|
|
@State private var url = ""
|
||
|
|
@State private var username = ""
|
||
|
|
@State private var password = ""
|
||
|
|
@State private var isTesting = false
|
||
|
|
@State private var testResult = ""
|
||
|
|
|
||
|
|
var body: some View {
|
||
|
|
ScrollView {
|
||
|
|
VStack(spacing: 10) {
|
||
|
|
Text("Add Server")
|
||
|
|
.font(.headline)
|
||
|
|
|
||
|
|
TextField("Name", text: $name)
|
||
|
|
TextField("URL", text: $url)
|
||
|
|
.textContentType(.URL)
|
||
|
|
TextField("Username", text: $username)
|
||
|
|
SecureField("Password", text: $password)
|
||
|
|
|
||
|
|
Button(action: testAndSave) {
|
||
|
|
if isTesting {
|
||
|
|
ProgressView().scaleEffect(0.7)
|
||
|
|
} else {
|
||
|
|
Text("Connect")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.buttonStyle(.borderedProminent)
|
||
|
|
.tint(.pink)
|
||
|
|
.disabled(url.isEmpty || username.isEmpty || isTesting)
|
||
|
|
|
||
|
|
if !testResult.isEmpty {
|
||
|
|
Text(testResult)
|
||
|
|
.font(.caption2)
|
||
|
|
.foregroundColor(testResult.contains("Success") ? .green : .red)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.padding()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private func testAndSave() {
|
||
|
|
isTesting = true
|
||
|
|
testResult = ""
|
||
|
|
let server = ServerConfig(
|
||
|
|
name: name.isEmpty ? "My Server" : name,
|
||
|
|
url: url.trimmingCharacters(in: CharacterSet(charactersIn: "/")),
|
||
|
|
username: username,
|
||
|
|
password: password
|
||
|
|
)
|
||
|
|
|
||
|
|
Task {
|
||
|
|
let ok = await watchManager.testConnection(server)
|
||
|
|
await MainActor.run {
|
||
|
|
isTesting = false
|
||
|
|
if ok {
|
||
|
|
testResult = "Success!"
|
||
|
|
watchManager.addServer(server)
|
||
|
|
watchManager.setActive(server)
|
||
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||
|
|
dismiss()
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
testResult = "Connection failed"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|