Files
iKeyMon/Sources/Views/ServerDetailView.swift

99 lines
3.0 KiB
Swift

//
// ServerDetailView.swift
// iKeyMon
//
// Created by tracer on 30.03.25.
//
import SwiftUI
struct ServerDetailView: View {
@Binding var server: Server
var isFetching: Bool
@AppStorage("showIntervalIndicator") private var showIntervalIndicator: Bool = true
private var showPlaceholder: Bool {
server.info == nil
}
@State private var progress: Double = 0
let timer = Timer.publish(every: 1.0 / 60.0, on: .main, in: .common).autoconnect()
var body: some View {
VStack(spacing: 0) {
if showIntervalIndicator {
ProgressView(value: progress)
.progressViewStyle(LinearProgressViewStyle())
.padding(.horizontal)
.frame(height: 2)
}
ZStack(alignment: .topTrailing) {
VStack(spacing: 0) {
Spacer().frame(height: 6)
TabView {
GeneralView(server: resolvedBinding)
.tabItem {
Text("General").unredacted()
}
ResourcesView(server: resolvedBinding)
.tabItem {
Text("Resources").unredacted()
}
ServicesView(server: resolvedBinding)
.tabItem {
Text("Services").unredacted()
}
}
.redacted(reason: showPlaceholder ? .placeholder : [])
.shimmering(active: showPlaceholder)
}
if showPlaceholder || isFetching {
LoadingBadge()
.padding()
}
}
.padding(0)
}
.onReceive(timer) { _ in
guard showIntervalIndicator else { return }
withAnimation(.linear(duration: 1.0 / 60.0)) {
progress += 1.0 / (60.0 * 60.0)
if progress >= 1 { progress = 0 }
}
}
}
private var resolvedBinding: Binding<Server> {
if showPlaceholder {
return .constant(placeholderServer())
}
return $server
}
private func placeholderServer() -> Server {
Server(id: server.id, hostname: server.hostname, info: .placeholder, pingable: server.pingable)
}
}
#Preview {
ServerDetailView(
server: .constant(Server(id: UUID(), hostname: "preview.example.com", info: ServerInfo.placeholder)),
isFetching: false
)
}
private struct LoadingBadge: View {
var body: some View {
HStack(spacing: 6) {
ProgressView()
.scaleEffect(0.5)
Text("Fetching latest data…")
.font(.caption)
}
.padding(8)
.background(.ultraThinMaterial, in: Capsule())
}
}