rework indicator

This commit is contained in:
spaced4ndy
2024-06-28 15:56:53 +04:00
parent 262d181778
commit 17cf8ee757
3 changed files with 145 additions and 82 deletions
@@ -264,7 +264,8 @@ struct ChatListView: View {
}
struct SubsStatusIndicator: View {
@State private var subs: SMPServerSubs = SMPServerSubs(ssActive: 0, ssPending: 0)
@State private var subs: SMPServerSubs = SMPServerSubs.newSMPServerSubs
@State private var sess: ServerSessions = ServerSessions.newServerSessions
@State private var timer: Timer? = nil
@State private var timerCounter = 0
@State private var showServersSummary = false
@@ -278,7 +279,7 @@ struct SubsStatusIndicator: View {
Button {
showServersSummary = true
} label: {
SubscriptionStatusView(subs: subs)
SubscriptionStatusView(subs: subs, sess: sess)
}
.onAppear {
startInitialTimer()
@@ -293,7 +294,7 @@ struct SubsStatusIndicator: View {
private func startInitialTimer() {
timer = Timer.scheduledTimer(withTimeInterval: initialInterval, repeats: true) { _ in
getSubsSummary()
getServersSummary()
timerCounter += 1
// Switch to the regular timer after the initial phase
if timerCounter * Int(initialInterval) >= Int(initialPhaseDuration) {
@@ -305,7 +306,7 @@ struct SubsStatusIndicator: View {
func switchToRegularTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: regularInterval, repeats: true) { _ in
getSubsSummary()
getServersSummary()
}
}
@@ -314,11 +315,12 @@ struct SubsStatusIndicator: View {
timer = nil
}
private func getSubsSummary() {
private func getServersSummary() {
do {
subs = try getAgentSubsSummary()
let summ = try getAgentServersSummary()
(subs, sess) = (summ.allUsersSMP.smpTotals.subs, summ.allUsersSMP.smpTotals.sessions)
} catch let error {
logger.error("getAgentSubsSummary error: \(responseError(error))")
logger.error("getAgentServersSummary error: \(responseError(error))")
}
}
}
@@ -207,10 +207,10 @@ struct ServersSummaryView: View {
}
}
private func smpServerView(_ server: SMPServerSummary, _ showReconnectButton: Bool, _ statsStartedAt: Date) -> some View {
NavigationLink(tag: server.id, selection: $selectedSMPServer) {
private func smpServerView(_ srvSumm: SMPServerSummary, _ showReconnectButton: Bool, _ statsStartedAt: Date) -> some View {
NavigationLink(tag: srvSumm.id, selection: $selectedSMPServer) {
SMPServerSummaryView(
summary: server,
summary: srvSumm,
showReconnectButton: showReconnectButton,
statsStartedAt: statsStartedAt
)
@@ -218,12 +218,15 @@ struct ServersSummaryView: View {
.navigationBarTitleDisplayMode(.large)
} label: {
HStack {
if let subs = server.subs {
SubscriptionStatusView(subs: subs)
.frame(width: 16, alignment: .center)
.padding(.trailing, 4)
if srvSumm.connected {
SubscriptionStatusView(
subs: srvSumm.subsOrNew,
sess: srvSumm.sessionsOrNew
)
.frame(width: 16, alignment: .center)
.padding(.trailing, 4)
}
Text(serverAddress(server.smpServer))
Text(serverAddress(srvSumm.smpServer))
.lineLimit(1)
}
}
@@ -255,16 +258,16 @@ struct ServersSummaryView: View {
}
}
private func xftpServerView(_ server: XFTPServerSummary, _ statsStartedAt: Date) -> some View {
NavigationLink(tag: server.id, selection: $selectedXFTPServer) {
private func xftpServerView(_ srvSumm: XFTPServerSummary, _ statsStartedAt: Date) -> some View {
NavigationLink(tag: srvSumm.id, selection: $selectedXFTPServer) {
XFTPServerSummaryView(
summary: server,
summary: srvSumm,
statsStartedAt: statsStartedAt
)
.navigationBarTitle("XFTP server")
.navigationBarTitleDisplayMode(.large)
} label: {
Text(serverAddress(server.xftpServer))
Text(serverAddress(srvSumm.xftpServer))
.lineLimit(1)
}
}
@@ -314,43 +317,50 @@ struct ServersSummaryView: View {
struct SubscriptionStatusView: View {
@EnvironmentObject var m: ChatModel
var subs: SMPServerSubs
var sess: ServerSessions
var body: some View {
let netInfo = m.networkInfo
if netInfo.online {
let (color, variableValue, opacity) = onlineIconColor
if #available(iOS 16.0, *) {
Image(systemName: "dot.radiowaves.up.forward", variableValue: variableValue)
.foregroundColor(color)
} else {
Image(systemName: "dot.radiowaves.up.forward")
.foregroundColor(color.opacity(opacity))
}
let (color, variableValue, opacity) = iconColor
if #available(iOS 16.0, *) {
Image(systemName: "dot.radiowaves.up.forward", variableValue: variableValue)
.foregroundColor(color)
} else {
Image(systemName: "dot.radiowaves.up.forward")
.foregroundColor(Color(uiColor: .tertiaryLabel))
.foregroundColor(color.opacity(opacity))
}
}
var onlineIconColor: (Color, Double, Double) {
if subs.ssActive > 0 {
let variableValue = roundToQuarter()
return (.accentColor, variableValue, activeSubsPercentage)
} else {
return (Color(uiColor: .tertiaryLabel), 1, 1)
}
private var iconColor: (Color, Double, Double) {
m.networkInfo.online && (subs.total > 0 || sess.total > 0)
? ( // Status to be displayed based on subs
subs.total > 0
? (
subs.ssActive == 0
? (
sess.ssConnected == 0 ? noConnColor : (.accentColor, activeSubsRounded, subs.shareOfActive)
)
: ( // ssActive > 0
sess.ssConnected == 0
? (.orange, activeSubsRounded, subs.shareOfActive) // This would mean implementation error
: (.accentColor, activeSubsRounded, subs.shareOfActive)
)
)
// subs.total == 0 and sess.total > 0; Status to be displayed based on sessions
: (.accentColor, connectedSessRounded, sess.shareOfConnected)
)
: noConnColor
}
func roundToQuarter() -> Double {
activeSubsPercentage >= 1 ? 1
: activeSubsPercentage <= 0 ? 0
: (activeSubsPercentage * 4).rounded() / 4
}
private var noConnColor: (Color, Double, Double) { (Color(uiColor: .tertiaryLabel), 1, 1) }
var activeSubsPercentage: Double {
let total = subs.ssActive + subs.ssPending
guard total != 0 else { return 0.0 }
return Double(subs.ssActive) / Double(total)
private var activeSubsRounded: Double { roundedToQuarter(subs.shareOfActive) }
private var connectedSessRounded: Double { roundedToQuarter(sess.shareOfConnected) }
private func roundedToQuarter(_ n: Double) -> Double {
n >= 1 ? 1
: n <= 0 ? 0
: (n * 4).rounded() / 4
}
}
@@ -380,8 +390,17 @@ struct SMPServerSummaryView: View {
}
}
if showReconnectButton {
reconnectButtonSection()
if summary.connected && showReconnectButton {
Section {
connectionStatusRow()
reconnectButtonSection()
} footer: {
if summary.subs != nil {
Text("Connection status is displayed based on Message subscriptions.")
} else if summary.sessions != nil {
Text("Connection status is displayed based on Transport sessions.")
}
}
}
if let subs = summary.subs {
@@ -399,35 +418,44 @@ struct SMPServerSummaryView: View {
.alert(item: $alert) { $0.alert }
}
private func connectionStatusRow() -> some View {
HStack {
Text("Connection status")
Spacer()
SubscriptionStatusView(
subs: summary.subsOrNew,
sess: summary.sessionsOrNew
)
}
}
private func reconnectButtonSection() -> some View {
Section {
Button {
alert = SomeAlert(
alert: Alert(
title: Text("Reconnect server?"),
message: Text("Reconnect server to force message delivery. It uses additional traffic."),
primaryButton: .default(Text("Ok")) {
Task {
do {
try await reconnectServer(smpServer: summary.smpServer)
} catch let error {
alert = SomeAlert(
alert: mkAlert(
title: "Error reconnecting server",
message: "\(responseError(error))"
),
id: "error reconnecting server"
)
}
Button {
alert = SomeAlert(
alert: Alert(
title: Text("Reconnect server?"),
message: Text("Reconnect server to force message delivery. It uses additional traffic."),
primaryButton: .default(Text("Ok")) {
Task {
do {
try await reconnectServer(smpServer: summary.smpServer)
} catch let error {
alert = SomeAlert(
alert: mkAlert(
title: "Error reconnecting server",
message: "\(responseError(error))"
),
id: "error reconnecting server"
)
}
},
secondaryButton: .cancel()
),
id: "reconnect server question"
)
} label: {
Text("Reconnect")
}
}
},
secondaryButton: .cancel()
),
id: "reconnect server question"
)
} label: {
Text("Reconnect")
}
}
}
@@ -437,15 +465,12 @@ struct SMPSubsView: View {
var showPending: Bool
var body: some View {
Section {
Section("Message subscriptions") {
infoRow("Active", "\(subs.ssActive)")
infoRow("Pending", "\(subs.ssPending)")
infoRow("Total", "\(subs.ssActive + subs.ssPending)")
} header: {
HStack {
Text("Message subscriptions")
SubscriptionStatusView(subs: subs)
if showPending {
infoRow("Pending", "\(subs.ssPending)")
}
infoRow("Total", "\(subs.total)")
}
}
}
@@ -458,6 +483,7 @@ struct ServerSessionsView: View {
infoRow("Connected", "\(sess.ssConnected)")
infoRow("Errors", "\(sess.ssErrors)")
infoRow("Connecting", "\(sess.ssConnecting)")
infoRow("Total", "\(sess.total)")
}
}
}
+35
View File
@@ -2281,12 +2281,35 @@ public struct SMPServerSummary: Codable, Identifiable {
public var id: String { smpServer }
public var connected: Bool { sessions != nil || subs != nil }
public var sessionsOrNew: ServerSessions { sessions ?? ServerSessions.newServerSessions }
public var subsOrNew: SMPServerSubs { subs ?? SMPServerSubs.newSMPServerSubs }
}
public struct ServerSessions: Codable {
public var ssConnected: Int
public var ssErrors: Int
public var ssConnecting: Int
public init(ssConnected: Int, ssErrors: Int, ssConnecting: Int) {
self.ssConnected = ssConnected
self.ssErrors = ssErrors
self.ssConnecting = ssConnecting
}
static public var newServerSessions = ServerSessions(
ssConnected: 0,
ssErrors: 0,
ssConnecting: 0
)
public var total: Int { ssConnected + ssErrors + ssConnecting }
public var shareOfConnected: Double {
guard total != 0 else { return 0.0 }
return Double(ssConnected) / Double(total)
}
}
public struct SMPServerSubs: Codable {
@@ -2297,6 +2320,18 @@ public struct SMPServerSubs: Codable {
self.ssActive = ssActive
self.ssPending = ssPending
}
static public var newSMPServerSubs = SMPServerSubs(
ssActive: 0,
ssPending: 0
)
public var total: Int { ssActive + ssPending }
public var shareOfActive: Double {
guard total != 0 else { return 0.0 }
return Double(ssActive) / Double(total)
}
}
public struct AgentSMPServerStatsData: Codable {