Add connections dashboard
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import Libbox
|
||||
import SwiftUI
|
||||
|
||||
@MainActor
|
||||
public struct ConnectionView: View {
|
||||
private let connection: Connection
|
||||
public init(_ connection: Connection) {
|
||||
self.connection = connection
|
||||
}
|
||||
|
||||
private func format(_ date: Date) -> String {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "HH:mm:ss"
|
||||
return formatter.string(from: date)
|
||||
}
|
||||
|
||||
public func formatInterval(_ createdAt: Date, _ closedAt: Date) -> String {
|
||||
LibboxFormatDuration(Int64((closedAt.timeIntervalSince1970 - createdAt.timeIntervalSince1970) * 1000))
|
||||
}
|
||||
|
||||
@State private var alert: Alert?
|
||||
|
||||
public var body: some View {
|
||||
FormNavigationLink {
|
||||
ConnectionDetailsView(connection)
|
||||
} label: {
|
||||
VStack {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
HStack(alignment: .center) {
|
||||
Text("\(connection.network.uppercased()) \(connection.displayDestination)")
|
||||
Spacer()
|
||||
if connection.closedAt == nil {
|
||||
Text("Active").foregroundStyle(.green)
|
||||
} else {
|
||||
Text("Closed").foregroundStyle(.red)
|
||||
}
|
||||
}
|
||||
.font(.caption2.monospaced().bold())
|
||||
.padding([.bottom], 4)
|
||||
HStack {
|
||||
if let closedAt = connection.closedAt {
|
||||
VStack(alignment: .leading) {
|
||||
Text("↑ \(LibboxFormatBytes(connection.uploadTotal))")
|
||||
Text("↓ \(LibboxFormatBytes(connection.downloadTotal))")
|
||||
}
|
||||
.font(.caption2)
|
||||
VStack(alignment: .leading) {
|
||||
Text(format(connection.createdAt))
|
||||
Text(formatInterval(connection.createdAt, closedAt))
|
||||
}
|
||||
Spacer()
|
||||
VStack(alignment: .trailing) {
|
||||
Text(connection.inboundType + "/" + connection.inbound)
|
||||
Text(connection.chain.reversed().joined(separator: "/"))
|
||||
}
|
||||
} else {
|
||||
VStack(alignment: .leading) {
|
||||
Text("↑ \(LibboxFormatBytes(connection.upload))/s")
|
||||
Text("↓ \(LibboxFormatBytes(connection.download))/s")
|
||||
}
|
||||
.font(.caption2)
|
||||
VStack(alignment: .leading) {
|
||||
Text(LibboxFormatBytes(connection.uploadTotal))
|
||||
Text(LibboxFormatBytes(connection.downloadTotal))
|
||||
}
|
||||
Spacer()
|
||||
VStack(alignment: .trailing) {
|
||||
Text(connection.inboundType + "/" + connection.inbound)
|
||||
Text(connection.chain.reversed().joined(separator: "/"))
|
||||
}
|
||||
}
|
||||
}
|
||||
.font(.caption2.monospaced())
|
||||
}
|
||||
}
|
||||
.foregroundColor(.textColor)
|
||||
#if !os(tvOS)
|
||||
.padding(EdgeInsets(top: 10, leading: 13, bottom: 10, trailing: 13))
|
||||
.background(backgroundColor)
|
||||
.cornerRadius(10)
|
||||
#endif
|
||||
}
|
||||
.background(.clear)
|
||||
}
|
||||
#if !os(tvOS)
|
||||
.buttonStyle(.borderless)
|
||||
#endif
|
||||
.alertBinding($alert)
|
||||
.contextMenu {
|
||||
if connection.closedAt == nil {
|
||||
Button("Close", role: .destructive) {
|
||||
Task {
|
||||
await closeConnection()
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var backgroundColor: Color {
|
||||
#if os(iOS)
|
||||
return Color(uiColor: .secondarySystemGroupedBackground)
|
||||
#elseif os(macOS)
|
||||
return Color(nsColor: .textBackgroundColor)
|
||||
#elseif os(tvOS)
|
||||
return Color.black
|
||||
#endif
|
||||
}
|
||||
|
||||
private nonisolated func closeConnection() async {
|
||||
do {
|
||||
try LibboxNewStandaloneCommandClient()!.closeConnection(connection.id)
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
alert = Alert(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user