Files
andros d8a6299600 Identify own messages reliably and tidy the Setup screen
Recognise own messages by id (prefix and case insensitive) or by
node number, so chat bubbles align right with the accent colour even
when the message only carries fromNodeNum. Fetch /api/v1/status and
/api/status in parallel and merge them, since MeshMonitor 4 dropped
localNode from the legacy endpoint.

Add a "How to create a token" link, plus Source code and Report a
bug links to the Settings screen. Default the server port to 8080
(MeshMonitor's Docker default). Add PRIVACY.md, refresh the README
and ignore CLAUDE.md.
2026-05-07 10:01:15 +02:00

65 lines
1.6 KiB
Swift

import SwiftUI
struct ChannelListView: View {
@Environment(APIClient.self) private var api
@Environment(MeshDataStore.self) private var store
var body: some View {
Group {
if store.loading && store.channels.isEmpty {
ProgressView("Loading channels…")
} else if let error = store.error, store.channels.isEmpty {
ContentUnavailableView {
Label("Connection error", systemImage: "wifi.exclamationmark")
} description: {
Text(error)
} actions: {
Button("Retry") { Task { await store.refresh(api: api) } }
}
} else if store.channels.isEmpty {
ContentUnavailableView("No channels", systemImage: "number")
} else {
List(store.channels) { ch in
NavigationLink {
ChatView(target: .channel(ch.id, name: ch.displayName))
} label: {
ChannelRow(channel: ch)
}
}
}
}
.navigationTitle("Channels")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
Task { await store.refresh(api: api) }
} label: {
Image(systemName: "arrow.clockwise")
}
.disabled(store.loading)
}
}
.refreshable { await store.refresh(api: api) }
.task {
if store.channels.isEmpty { await store.refresh(api: api) }
}
}
}
private struct ChannelRow: View {
let channel: Channel
var body: some View {
HStack {
Image(systemName: "number.circle.fill")
.foregroundStyle(.tint)
.font(.title2)
VStack(alignment: .leading) {
Text(channel.displayName).font(.body)
Text(channel.roleName).font(.caption).foregroundStyle(.secondary)
}
Spacer()
}
.padding(.vertical, 2)
}
}