diff --git a/Localizable.xcstrings b/Localizable.xcstrings index ce93458d1..6e6beca78 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -524,6 +524,9 @@ } } } + }, + "Administration" : { + }, "Advanced" : { @@ -11186,6 +11189,9 @@ } } } + }, + "Logs" : { + }, "Logs:" : { @@ -15307,6 +15313,9 @@ } } } + }, + "Node" : { + }, "Node Core Data Backup %@/%@ - %@ - %@" : { "localizations" : { @@ -15327,7 +15336,7 @@ "Node Map" : { }, - "Node Number:" : { + "Node Number" : { }, "nodelist.filter.distance %@" : { @@ -17038,6 +17047,9 @@ }, "Recording route" : { + }, + "Refresh device metadata" : { + }, "Region" : { @@ -22100,7 +22112,7 @@ "User Details" : { }, - "User Id:" : { + "User Id" : { }, "user.details" : { diff --git a/Meshtastic.xcodeproj/xcshareddata/xcschemes/WidgetsExtension.xcscheme b/Meshtastic.xcodeproj/xcshareddata/xcschemes/WidgetsExtension.xcscheme index decd8381b..880339bcd 100644 --- a/Meshtastic.xcodeproj/xcshareddata/xcschemes/WidgetsExtension.xcscheme +++ b/Meshtastic.xcodeproj/xcshareddata/xcschemes/WidgetsExtension.xcscheme @@ -89,7 +89,6 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES" - askForAppToLaunch = "Yes" launchAutomaticallySubstyle = "2"> diff --git a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift index 2ff960c57..03cd132f9 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift @@ -20,210 +20,239 @@ struct NodeDetail: View { var columnVisibility = NavigationSplitViewVisibility.all var body: some View { - - let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context) NavigationStack { - GeometryReader { _ in - VStack { - ScrollView { - NodeInfoItem(node: node) - let dm = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0")).lastObject as? TelemetryEntity - if dm?.uptimeSeconds ?? 0 > 0 { - HStack(alignment: .center) { - let now = Date.now - let later = now + TimeInterval(dm!.uptimeSeconds) - let components = (now.. 0 { - Logger.mesh.info("Sent node metadata request from node details") - } - } label: { - Image(systemName: "arrow.clockwise") - .font(.title3) - } - .buttonStyle(.bordered) - .buttonBorderShape(.capsule) - .controlSize(.small) - } - } - Divider() + Spacer() + Text(String(node.num)) + } + + HStack { + Label { + Text("User Id") + } icon: { + Image(systemName: "person") + .symbolRenderingMode(.multicolor) } - VStack { - NavigationLink { - DeviceMetricsLog(node: node) - } label: { - Image(systemName: "flipphone") - .symbolRenderingMode(.hierarchical) - .font(.title) + Spacer() + Text(node.user?.userId ?? "?") + } - Text("Device Metrics Log") - .font(.title3) + if let dm = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0")).lastObject as? TelemetryEntity, dm.uptimeSeconds > 0 { + HStack { + Label { + Text("\("uptime".localized)") + } icon: { + Image(systemName: "checkmark.circle.fill") + .foregroundColor(.green) + .symbolRenderingMode(.hierarchical) } - .disabled(!node.hasDeviceMetrics) - - Divider() - NavigationLink { - if #available (iOS 17, macOS 14, *) { - NodeMapSwiftUI(node: node, showUserLocation: connectedNode?.num ?? 0 == node.num) - } else { - NodeMapMapkit(node: node) - } + Spacer() - } label: { - Image(systemName: "map") - .symbolRenderingMode(.hierarchical) - .font(.title) + let now = Date.now + let later = now + TimeInterval(dm.uptimeSeconds) + let uptime = (now.. 0 { + Logger.mesh.info("Sent node metadata request from node details") } - .disabled(node.traceRoutes?.count ?? 0 == 0) - Divider() - } - NavigationLink { - DetectionSensorLog(node: node) } label: { - Image(systemName: "sensor") - .symbolRenderingMode(.hierarchical) - .font(.title) - - Text("Detection Sensor Log") - .font(.title3) - } - .disabled(!node.hasDetectionSensorMetrics) - Divider() - if node.hasPax { - NavigationLink { - PaxCounterLog(node: node) - } label: { - Image(systemName: "figure.walk.motion") - .symbolRenderingMode(.hierarchical) - .font(.title) - - Text("paxcounter.log") - .font(.title3) + Label { + Text("Refresh device metadata") + } icon: { + Image(systemName: "arrow.clockwise") } - .disabled(!node.hasPax) - Divider() } } - if self.bleManager.connectedPeripheral != nil && node.metadata != nil { - HStack { - if node.metadata?.canShutdown ?? false { - - Button(action: { - showingShutdownConfirm = true - }) { - Label("Power Off", systemImage: "power") - } - .buttonStyle(.bordered) - .buttonBorderShape(.capsule) - .controlSize(.large) - .padding() - .confirmationDialog( - "are.you.sure", - isPresented: $showingShutdownConfirm - ) { - Button("Shutdown Node?", role: .destructive) { - if !bleManager.sendShutdown(fromUser: connectedNode!.user!, toUser: node.user!, adminIndex: connectedNode!.myInfo!.adminIndex) { - Logger.mesh.warning("Shutdown Failed") - } - } - } - } - Button(action: { - showingRebootConfirm = true - }) { - Label("reboot", systemImage: "arrow.triangle.2.circlepath") + if metadata.canShutdown { + Label("Power Off", systemImage: "power") + .onTapGesture { + showingShutdownConfirm = true } - .buttonStyle(.bordered) - .buttonBorderShape(.capsule) - .controlSize(.large) - .padding() - .confirmationDialog("are.you.sure", - isPresented: $showingRebootConfirm + .confirmationDialog( + "are.you.sure", + isPresented: $showingShutdownConfirm ) { - Button("reboot.node", role: .destructive) { - if !bleManager.sendReboot(fromUser: connectedNode!.user!, toUser: node.user!, adminIndex: connectedNode!.myInfo!.adminIndex) { - Logger.mesh.warning("Reboot Failed") + Button("Shutdown Node?", role: .destructive) { + if !bleManager.sendShutdown( + fromUser: connectedNode.user!, + toUser: node.user!, + adminIndex: connectedNode.myInfo!.adminIndex + ) { + Logger.mesh.warning("Shutdown Failed") } } } - } - .padding(5) - Divider() } + Label("reboot", systemImage: "arrow.triangle.2.circlepath") + .onTapGesture { + showingRebootConfirm = true + } + .confirmationDialog( + "are.you.sure", + isPresented: $showingRebootConfirm + ) { + Button("reboot.node", role: .destructive) { + if !bleManager.sendReboot( + fromUser: connectedNode.user!, + toUser: node.user!, + adminIndex: connectedNode.myInfo!.adminIndex + ) { + Logger.mesh.warning("Reboot Failed") + } + } + } } } - .onAppear { - if self.bleManager.context == nil { - self.bleManager.context = context - } + } + .listStyle(.insetGrouped) + .onAppear { + if self.bleManager.context == nil { + self.bleManager.context = context } } - .padding(.bottom, 2) } } } diff --git a/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift b/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift index df40aaa55..e94baf3af 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift @@ -11,23 +11,24 @@ import MapKit struct NodeInfoItem: View { - @ObservedObject var node: NodeInfoEntity - var modemPreset: ModemPresets = ModemPresets(rawValue: UserDefaults.modemPreset) ?? ModemPresets.longFast + @ObservedObject + var node: NodeInfoEntity - var body: some View { - - Divider() + var modemPreset: ModemPresets = ModemPresets( + rawValue: UserDefaults.modemPreset + ) ?? ModemPresets.longFast + var body: some View { HStack { - - VStack(alignment: .center) { - CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 65) - } - if node.user != nil { - Divider() + CircleText( + text: node.user?.shortName ?? "?", + color: Color(UIColor(hex: UInt32(node.num))), + circleSize: 65 + ) + if let user = node.user { VStack(alignment: .center) { - if node.user?.hwModel != "UNSET" { - Image(node.user!.hwModel ?? "unset".localized) + if user.hwModel != "UNSET" { + Image(user.hwModel ?? "unset".localized) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 75, height: 75) @@ -47,8 +48,8 @@ struct NodeInfoItem: View { } } } + if node.snr != 0 && !node.viaMqtt { - Divider() VStack(alignment: .center) { let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi, preset: modemPreset) LoRaSignalStrengthIndicator(signalStrength: signalStrength) @@ -61,41 +62,12 @@ struct NodeInfoItem: View { .font(.caption2) } } + if node.telemetries?.count ?? 0 > 0 { - Divider() BatteryGauge(node: node) + .padding() } + Spacer() } - Divider() - HStack(alignment: .center) { - VStack { - HStack { - Image(systemName: "number") - .font(.title2) - .foregroundColor(.accentColor) - .symbolRenderingMode(.hierarchical) - Text("Node Number:").font(.title2) - } - Text(String(node.num)) - .font(.title3) - .foregroundColor(.gray) - .textSelection(.enabled) - } - Divider() - VStack { - HStack { - Image(systemName: "person") - .font(.title2) - .foregroundColor(.accentColor) - .symbolRenderingMode(.hierarchical) - Text("User Id:").font(.title2) - } - Text(node.user?.userId ?? "?") - .font(.title3) - .foregroundColor(.gray) - .textSelection(.enabled) - } - } - Divider() } } diff --git a/protobufs b/protobufs index 4da558d0f..1198b7dba 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 4da558d0f73c46ef91b74431facee73c09affbfc +Subproject commit 1198b7dbabf9768cb0143d2897707b4c7a51a5da