Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 60 additions & 34 deletions OpenParsec/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ struct MainView: View {

// Host page vars
@State var hostCountStr: String = "0 hosts"
@State var refreshTime: String = "Last refreshed at 1/1/1970 12:00 AM"
@State var refreshTime: String = ""

@State var hosts: [IdentifiableHostInfo] = []

Expand All @@ -30,14 +30,15 @@ struct MainView: View {
@State var pollTimer: Timer?

@State var isRefreshing: Bool = false
@State var refreshError: String?

@State var inSettings: Bool = false
@State var sessionExpired: Bool = false

@State private var lastHostShown: String?

var busy: Bool {
isConnecting || isRefreshing || inSettings
isConnecting || inSettings
}

init(_ controller: ContentView?) {
Expand Down Expand Up @@ -88,6 +89,8 @@ struct MainView: View {
.font(.system(size: 20, weight: .medium))
Button(action: refreshHosts, label: { Image(systemName: "arrow.clockwise") })
.padding(4)
.disabled(isRefreshing)
.opacity(isRefreshing ? 0.4 : 1)
} else if page == .friends {
Text(friendCountStr)
.multilineTextAlignment(.center)
Expand Down Expand Up @@ -117,7 +120,7 @@ struct MainView: View {
.foregroundColor(Color("Foreground"))
Spacer()
Button(action: logout) {
Text("Sign in")
Text("Sign In")
.fontWeight(.semibold)
.foregroundColor(Color("AccentColor"))
.frame(minWidth: 44, minHeight: 44)
Expand All @@ -131,10 +134,39 @@ struct MainView: View {
.frame(maxWidth: 400)
.padding(.horizontal)
}
Text(refreshTime)
.multilineTextAlignment(.center)
.opacity(0.5)
if let lastHost = lastHostShown {
if let refreshError = refreshError {
HStack {
Text(refreshError)
.foregroundColor(Color("Foreground"))
Spacer()
Button(action: refreshHosts) {
Text("Retry")
.fontWeight(.semibold)
.foregroundColor(Color("AccentColor"))
.frame(minWidth: 44, minHeight: 44)
.contentShape(Rectangle())
}
}
.padding(.horizontal, 12)
.padding(.vertical, 2)
.background(Rectangle().fill(Color("BackgroundPrompt")))
.cornerRadius(8)
.frame(maxWidth: 400)
.padding(.horizontal)
}
if isRefreshing {
HStack(spacing: 8) {
ActivityIndicator(isAnimating: $isRefreshing, style: .medium, tint: UIColor(named: "Foreground") ?? .white)
.frame(width: 20, height: 20)
Text("Refreshing hosts...")
.foregroundColor(Color("Foreground"))
}
} else if !refreshTime.isEmpty {
Text(refreshTime)
.multilineTextAlignment(.center)
.opacity(0.5)
}
if let lastHost = lastHostShown, !isConnecting {
VStack(spacing: 0) {
HStack {
VStack(alignment: .leading, spacing: 4) {
Expand Down Expand Up @@ -233,6 +265,11 @@ struct MainView: View {
.frame(maxWidth: 400)
.background(Rectangle().fill(Color("BackgroundCard")))
.cornerRadius(8)
.contextMenu {
Button(action: { UIPasteboard.general.string = i.hostname }) {
Label("Copy Name", systemImage: "doc.on.doc")
}
}
}
}
.padding()
Expand Down Expand Up @@ -394,24 +431,6 @@ struct MainView: View {
.padding()
}
}
if isRefreshing {
ZStack {
Rectangle() // Darken background
.fill(Color.black)
.opacity(0.5)
.edgesIgnoringSafeArea(.all)
VStack {
ActivityIndicator(isAnimating: $isRefreshing, style: .large, tint: .white)
.padding()
Text("Refreshing hosts...")
.multilineTextAlignment(.center)
}
.padding()
.background(Rectangle().fill(Color("BackgroundPrompt")))
.cornerRadius(8)
.padding()
}
}
}
.foregroundColor(Color("Foreground"))
}
Expand Down Expand Up @@ -449,14 +468,14 @@ struct MainView: View {
}

func refreshHosts() {
guard !isRefreshing else { return }
withAnimation {
isRefreshing = true

let clinfo = NetworkHandler.clinfo
if clinfo == nil {
isRefreshing = false
baseAlertText = "Error gathering hosts: Invalid session"
showBaseAlert = true
sessionExpired = true
return
}

Expand All @@ -475,14 +494,19 @@ struct MainView: View {
if let data = data {
guard let statusCode = (response as? HTTPURLResponse)?.statusCode else { return }
if statusCode == 401 {
refreshError = nil
sessionExpired = true
return
}
let decoder = JSONDecoder()

if statusCode == 200 { // 200 OK
sessionExpired = false
guard let info: HostInfoList = try? decoder.decode(HostInfoList.self, from: data) else { return }
guard let info: HostInfoList = try? decoder.decode(HostInfoList.self, from: data) else {
refreshError = "Couldn't refresh hosts: bad response"
return
}
refreshError = nil
hosts.removeAll()
if let datas = info.data {
datas.forEach { h in
Expand All @@ -498,14 +522,16 @@ struct MainView: View {
hostCountStr = "\(hosts.count) \(grammar)"

let formatter = DateFormatter()
formatter.dateFormat = "M/d/yyyy h:mm a"
formatter.dateStyle = .short
formatter.timeStyle = .short
refreshTime = "Last refreshed at \(formatter.string(from: Date()))"
} else if statusCode == 403 { // 403 Forbidden
guard let info: ErrorInfo = try? decoder.decode(ErrorInfo.self, from: data) else { return }

baseAlertText = "Error gathering hosts: \(info.error)"
showBaseAlert = true
} else if statusCode == 403, let info: ErrorInfo = try? decoder.decode(ErrorInfo.self, from: data) { // 403 Forbidden
refreshError = "Couldn't refresh hosts: \(info.error)"
} else {
refreshError = "Couldn't refresh hosts (HTTP \(statusCode))"
}
} else {
refreshError = "Can't reach Parsec"
}
}
}
Expand Down
Loading