@@ -9,6 +9,9 @@ import SwiftUI
struct MainView : View {
struct MainView : View {
private static let serverOrderKeyStatic = " serverOrder "
private static let storedServersKeyStatic = " storedServers "
@ State var showAddServerSheet : Bool = false
@ State var showAddServerSheet : Bool = false
@ State private var serverBeingEdited : Server ?
@ State private var serverBeingEdited : Server ?
@ State private var serverToDelete : Server ?
@ State private var serverToDelete : Server ?
@@ -18,27 +21,10 @@ struct MainView: View {
@ State private var progress : Double = 0
@ State private var progress : Double = 0
@ State private var lastRefresh = Date ( )
@ State private var lastRefresh = Date ( )
@ State private var pingTimer : Timer ?
@ State private var pingTimer : Timer ?
private let serverOrderKey = " serverOrder"
private let serverOrderKey = MainView . serverOrderKeyStatic
private let storedServersKey = MainView . storedServersKeyStatic
@ State private var servers : [ Server ] = {
@ State private var servers : [ Server ] = MainView . loadStoredServers ( )
if let data = UserDefaults . standard . data ( forKey : " storedServers " ) ,
let saved = try ? JSONDecoder ( ) . decode ( [ Server ] . self , from : data ) {
if let idStrings = UserDefaults . standard . stringArray ( forKey : " serverOrder " ) {
let idMap = idStrings . compactMap ( UUID . init )
return saved . sorted { a , b in
guard
let i1 = idMap . firstIndex ( of : a . id ) ,
let i2 = idMap . firstIndex ( of : b . id )
else { return false }
return i1 < i2
}
}
return saved
}
return [ ]
} ( )
// @ S t a t e p r i v a t e v a r s e l e c t e d S e r v e r : S e r v e r ?
// @ S t a t e p r i v a t e v a r s e l e c t e d S e r v e r : S e r v e r ?
@ State private var selectedServerID : UUID ?
@ State private var selectedServerID : UUID ?
@@ -112,21 +98,28 @@ struct MainView: View {
Button ( " Cancel " , role : . cancel ) { }
Button ( " Cancel " , role : . cancel ) { }
}
}
. onReceive ( refreshTimer ) { _ in
. onReceive ( refreshTimer ) { _ in
print ( " ⏰ [MainView] Refresh timer fired with \( servers . count ) servers " )
for server in servers {
for server in servers {
print ( " fetching serve r: \( server . hostname ) " )
print ( " ⏰ [MainView] Triggering fetchServerInfo fo r: \( server . hostname ) " )
fetchServerInfo ( for : server . id )
fetchServerInfo ( for : server . id )
}
}
}
}
. onAppear {
. onAppear {
print ( " 👀 [MainView] onAppear - servers in memory: \( servers . count ) " )
if let storedID = UserDefaults . standard . string ( forKey : " selectedServerID " ) ,
if let storedID = UserDefaults . standard . string ( forKey : " selectedServerID " ) ,
let uuid = UUID ( uuidString : storedID ) ,
let uuid = UUID ( uuidString : storedID ) ,
servers . contains ( where : { $0 . id = = uuid } ) {
servers . contains ( where : { $0 . id = = uuid } ) {
print ( " ✅ [MainView] Restored selected server \( uuid ) " )
selectedServerID = uuid
selectedServerID = uuid
} else if selectedServerID = = nil , let first = servers . first {
} else if selectedServerID = = nil , let first = servers . first {
print ( " ✅ [MainView] Selecting first server \( first . hostname ) " )
selectedServerID = first . id
selectedServerID = first . id
} else {
print ( " ℹ ️ [MainView] No stored selection" )
}
}
pingAllServers ( )
pingAllServers ( )
pingTimer = Timer . scheduledTimer ( withTimeInterval : 10.0 , repeats : true ) { _ in
pingTimer = Timer . scheduledTimer ( withTimeInterval : 10.0 , repeats : true ) { _ in
print ( " 📡 [MainView] Ping timer firing " )
pingAllServers ( )
pingAllServers ( )
}
}
}
}
@@ -135,8 +128,12 @@ struct MainView: View {
}
}
private func fetchServerInfo ( for id : UUID ) {
private func fetchServerInfo ( for id : UUID ) {
guard let server = servers . first ( where : { $0 . id = = id } ) ,
guard let server = servers . first ( where : { $0 . id = = id } ) else {
let api = ServerAPI ( server : server ) else {
print ( " ❌ [MainView] fetchServerInfo: server not found for id \( id ) " )
return
}
guard let api = ServerAPI ( server : server ) else {
print ( " ❌ [MainView] fetchServerInfo: could not create API for \( server . hostname ) " )
return
return
}
}
@@ -148,8 +145,9 @@ struct MainView: View {
let info = try await api . fetchServerInfo ( )
let info = try await api . fetchServerInfo ( )
if let index = servers . firstIndex ( where : { $0 . id = = id } ) {
if let index = servers . firstIndex ( where : { $0 . id = = id } ) {
var updated = servers [ index ]
var updated = servers [ index ]
updated . info = try ServerInfo ( from : info as ! Decoder )
updated . info = info
servers [ index ] = updated
servers [ index ] = updated
print ( " ✅ [MainView] Updated server info for \( updated . hostname ) " )
}
}
} catch {
} catch {
print ( " ❌ Failed to fetch server data: \( error ) " )
print ( " ❌ Failed to fetch server data: \( error ) " )
@@ -165,6 +163,7 @@ struct MainView: View {
private func saveServerOrder ( ) {
private func saveServerOrder ( ) {
let ids = servers . map { $0 . id . uuidString }
let ids = servers . map { $0 . id . uuidString }
UserDefaults . standard . set ( ids , forKey : serverOrderKey )
UserDefaults . standard . set ( ids , forKey : serverOrderKey )
print ( " 💾 [MainView] Saved server order with \( ids . count ) entries " )
}
}
private struct PingResponse : Codable {
private struct PingResponse : Codable {
@@ -213,16 +212,41 @@ struct MainView: View {
for ( index , server ) in servers . enumerated ( ) {
for ( index , server ) in servers . enumerated ( ) {
Task {
Task {
let apiKey = KeychainHelper . loadApiKey ( for : server . hostname ) ? . trimmingCharacters ( in : . whitespacesAndNewlines ) ? ? " "
let apiKey = KeychainHelper . loadApiKey ( for : server . hostname ) ? . trimmingCharacters ( in : . whitespacesAndNewlines ) ? ? " "
let api = ServerAPI ( hostname : server . hostname , apiKey : apiKey )
let api = ServerAPI ( hostname : server . hostname , apiKey : apiKey )
let pingable = await api . ping ( )
let pingable = await api . ping ( )
servers [ index ] . pingable = pingable
servers [ index ] . pingable = pingable
}
print ( " 📶 [MainView] Ping \( server . hostname ) : \( pingable ? " online " : " offline " ) " )
}
}
}
}
}
}
private static func loadStoredServers ( ) -> [ Server ] {
let defaults = UserDefaults . standard
guard let data = defaults . data ( forKey : storedServersKeyStatic ) else {
print ( " ℹ ️ [MainView] No storedServers data found" )
return [ ]
}
do {
let saved = try JSONDecoder ( ) . decode ( [ Server ] . self , from : data )
print ( " 📦 [MainView] Loaded \( saved . count ) servers from UserDefaults " )
if let order = defaults . stringArray ( forKey : serverOrderKeyStatic ) {
let idMap = order . compactMap ( UUID . init )
let sorted = saved . sorted { a , b in
guard
let i1 = idMap . firstIndex ( of : a . id ) ,
let i2 = idMap . firstIndex ( of : b . id )
else { return false }
return i1 < i2
}
return sorted
}
return saved
} catch {
print ( " ❌ [MainView] Failed to decode stored servers: \( error ) " )
return [ ]
}
}
}
# Preview {
# Preview {
MainView ( )
MainView ( )