Meshtastic-Apple/Meshtastic/Views/Messages/Messages.swift
2026-04-16 12:10:00 -07:00

133 lines
3.7 KiB
Swift

//
// Messages.swift
// Meshtastic
//
// Copyright(c) Garth Vander Houwen 8/29/23.
//
import SwiftUI
import SwiftData
import OSLog
import TipKit
struct Messages: View {
@Environment(\.modelContext) private var context
@Environment(\.colorScheme) private var colorScheme
@ObservedObject var router: Router
@Binding var unreadChannelMessages: Int
@Binding var unreadDirectMessages: Int
@State var node: NodeInfoEntity?
@State private var userSelection: UserEntity? // Nothing selected by default.
@State private var channelSelection: ChannelEntity? // Nothing selected by default.
@State private var columnVisibility = NavigationSplitViewVisibility.all
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
List(selection: $router.messagesState) {
NavigationLink(value: MessagesNavigationState.channels()) {
Spacer()
Label {
Text("Channels")
.badge(unreadChannelMessages)
.font(.title2)
.padding()
} icon: {
Image(systemName: "person.2")
.symbolRenderingMode(.hierarchical)
.foregroundColor(.accentColor)
.font(.title2)
.padding()
}
}
.alignmentGuide(.listRowSeparatorLeading) {
$0[.leading]
}
NavigationLink(value: MessagesNavigationState.directMessages()) {
Spacer()
Label {
Text("Direct Messages")
.badge(unreadDirectMessages)
.font(.title2)
.padding()
} icon: {
Image(systemName: "person")
.symbolRenderingMode(.hierarchical)
.foregroundColor(.accentColor)
.font(.title2)
.padding()
}
}
.alignmentGuide(.listRowSeparatorLeading) {
$0[.leading]
}
Spacer()
TipView(MessagesTip(), arrowEdge: .top)
.tipViewStyle(PersistentTip())
.listRowSeparator(.hidden)
Spacer()
.listRowSeparator(.hidden)
}
.listStyle(.plain)
.navigationTitle("Messages")
.navigationBarTitleDisplayMode(.large)
.navigationBarItems(leading: MeshtasticLogo())
} content: {
switch router.messagesState {
case .channels(let channelId, let messageId):
ChannelList(node: $node, channelSelection: $channelSelection)
// Removed navigationTitle and navigationBarTitleDisplayMode here.
// ChannelList.swift now handles this within its own NavigationStack.
case .directMessages(let userNum, let messageId):
UserList(node: $node, userSelection: $userSelection)
// Removed navigationTitle here. UserList will handle this.
case nil:
Text("Select a conversation type")
}
} detail: {
if let myInfo = node?.myInfo, let channelSelection {
ChannelMessageList(myInfo: myInfo, channel: channelSelection)
// The toolbar is now defined inside ChannelMessageList.swift
} else if let userSelection {
UserMessageList(user: userSelection)
} else if case .channels = router.messagesState {
Text("Select a channel")
} else if case .directMessages = router.messagesState {
Text("Select a conversation")
}
}.onChange(of: router.messagesState) {
setupNavigationState()
}
}
private func setupNavigationState() {
let nodeId = Int64(UserDefaults.preferredPeripheralNum)
if nodeId > 0 {
node = getNodeInfo(id: nodeId, context: context)
}
guard let state = router.messagesState else {
channelSelection = nil
userSelection = nil
return
}
switch state {
case .channels(channelId: let channelId, messageId: _):
if let channelId {
channelSelection = node?.myInfo?.channels.first { $0.id == channelId }
} else {
channelSelection = nil
userSelection = nil
}
case .directMessages(userNum: let userNum, messageId: _):
if let userNum {
userSelection = getUser(id: userNum, context: context)
} else {
channelSelection = nil
userSelection = nil
}
}
}
}