From 2cf72f7d3d851beacd6377c570082d9d56d250fd Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 7 Sep 2023 23:38:53 -0700 Subject: [PATCH] Clean up node details --- Meshtastic.xcodeproj/project.pbxproj | 4 ++++ .../CoreData/NodeInfoEntityExtension.swift | 9 ++++++++ Meshtastic/Views/Helpers/DateTimeText.swift | 10 ++++----- Meshtastic/Views/Helpers/DistanceText.swift | 2 +- Meshtastic/Views/Helpers/LastHeardText.swift | 9 +++++++- .../Views/Helpers/Node/NodeListDetail.swift | 19 ++++++++++++++++ Meshtastic/Views/Nodes/NodeList.swift | 22 ++++++++++--------- en.lproj/Localizable.strings | 2 +- 8 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 Meshtastic/Views/Helpers/Node/NodeListDetail.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 765de0df..697f9463 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -116,6 +116,7 @@ DDB8F4102A9EE5B400230ECE /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8F40F2A9EE5B400230ECE /* Messages.swift */; }; DDB8F4122A9EE5DD00230ECE /* UserList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8F4112A9EE5DD00230ECE /* UserList.swift */; }; DDB8F4142A9EE5F000230ECE /* ChannelList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8F4132A9EE5F000230ECE /* ChannelList.swift */; }; + DDC18AD12AAAE5920083FE1E /* NodeListDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC18AD02AAAE5920083FE1E /* NodeListDetail.swift */; }; DDC2E15826CE248E0042C5E4 /* MeshtasticApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC2E15726CE248E0042C5E4 /* MeshtasticApp.swift */; }; DDC2E15C26CE248F0042C5E4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDC2E15B26CE248F0042C5E4 /* Assets.xcassets */; }; DDC2E15F26CE248F0042C5E4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDC2E15E26CE248F0042C5E4 /* Preview Assets.xcassets */; }; @@ -323,6 +324,7 @@ DDB8F4112A9EE5DD00230ECE /* UserList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserList.swift; sourceTree = ""; }; DDB8F4132A9EE5F000230ECE /* ChannelList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelList.swift; sourceTree = ""; }; DDBA45EC299ED78100DEEDDC /* MeshtasticDataModelV8.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV8.xcdatamodel; sourceTree = ""; }; + DDC18AD02AAAE5920083FE1E /* NodeListDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeListDetail.swift; sourceTree = ""; }; DDC2E15426CE248E0042C5E4 /* Meshtastic.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Meshtastic.app; sourceTree = BUILT_PRODUCTS_DIR; }; DDC2E15726CE248E0042C5E4 /* MeshtasticApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticApp.swift; sourceTree = ""; }; DDC2E15B26CE248F0042C5E4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = ../Assets.xcassets; sourceTree = ""; }; @@ -831,6 +833,7 @@ isa = PBXGroup; children = ( DDDEE5E029DA3E1100A8E078 /* NodeInfoView.swift */, + DDC18AD02AAAE5920083FE1E /* NodeListDetail.swift */, ); path = Node; sourceTree = ""; @@ -1082,6 +1085,7 @@ DD5E520F298EE33B00D21B61 /* cannedmessages.pb.swift in Sources */, DDB75A232A13CDA9006ED576 /* BatteryLevelCompact.swift in Sources */, DDB75A162A0594AD006ED576 /* TileOverlay.swift in Sources */, + DDC18AD12AAAE5920083FE1E /* NodeListDetail.swift in Sources */, DDF924CA26FBB953009FE055 /* ConnectedDevice.swift in Sources */, DD3CC6BE28E4CD9800FA9159 /* BatteryGauge.swift in Sources */, DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */, diff --git a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift index d24f69f1..b57e6ff4 100644 --- a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift @@ -24,4 +24,13 @@ extension NodeInfoEntity { let environmentMetrics = telemetries?.filter{ ($0 as AnyObject).metricsType == 1 } return environmentMetrics?.count ?? 0 > 0 } + + var isOnline: Bool { + + let fifteenMinutesAgo = Calendar.current.date(byAdding: .minute, value: -15, to: Date()) + if lastHeard?.compare(fifteenMinutesAgo!) == .orderedDescending { + return true + } + return false + } } diff --git a/Meshtastic/Views/Helpers/DateTimeText.swift b/Meshtastic/Views/Helpers/DateTimeText.swift index 0fcabf76..6b61afd0 100644 --- a/Meshtastic/Views/Helpers/DateTimeText.swift +++ b/Meshtastic/Views/Helpers/DateTimeText.swift @@ -16,14 +16,14 @@ struct DateTimeText: View { var dateTime: Date? let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date()) - + let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmmssa", options: 0, locale: Locale.current) + var body: some View { + let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mm:ss a") + if dateTime != nil && dateTime! >= sixMonthsAgo! { - - Text("\(dateTime!, style: .date) \(dateTime!, style: .time)") - + Text(" \(dateTime!.formattedDate(format: dateFormatString))") } else { - Text("unknown.age") } } diff --git a/Meshtastic/Views/Helpers/DistanceText.swift b/Meshtastic/Views/Helpers/DistanceText.swift index 0812e14f..67f9419c 100644 --- a/Meshtastic/Views/Helpers/DistanceText.swift +++ b/Meshtastic/Views/Helpers/DistanceText.swift @@ -16,7 +16,7 @@ struct DistanceText: View { var body: some View { let distanceFormatter = MKDistanceFormatter() - Text("distance")+Text(": \(distanceFormatter.string(fromDistance: Double(meters)))") + Text("\(distanceFormatter.string(fromDistance: Double(meters))) away") } } struct DistanceText_Previews: PreviewProvider { diff --git a/Meshtastic/Views/Helpers/LastHeardText.swift b/Meshtastic/Views/Helpers/LastHeardText.swift index 3a207b6d..97acce81 100644 --- a/Meshtastic/Views/Helpers/LastHeardText.swift +++ b/Meshtastic/Views/Helpers/LastHeardText.swift @@ -8,9 +8,16 @@ import SwiftUI struct LastHeardText: View { var lastHeard: Date? let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date()) + + static let formatter: RelativeDateTimeFormatter = { + let formatter = RelativeDateTimeFormatter() + formatter.unitsStyle = .full + return formatter + }() + var body: some View { if lastHeard != nil && lastHeard! >= sixMonthsAgo! { - Text("heard")+Text(" \(lastHeard!, style: .relative) ")+Text("ago") + Text("heard")+Text(" \(LastHeardText.formatter.localizedString(for: lastHeard!, relativeTo: Date.now))") } else { Text("unknown.age") } diff --git a/Meshtastic/Views/Helpers/Node/NodeListDetail.swift b/Meshtastic/Views/Helpers/Node/NodeListDetail.swift new file mode 100644 index 00000000..43dd76f9 --- /dev/null +++ b/Meshtastic/Views/Helpers/Node/NodeListDetail.swift @@ -0,0 +1,19 @@ +// +// NodeListDetail.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 9/7/23. +// + +//import SwiftUI +//import CoreLocation +//import MapKit +// +//struct NodeListDetail: View { +// +// var node: NodeInfoEntity +// +// var body: some View { +// +// } +//} diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 8cd324e5..104412c9 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -61,13 +61,21 @@ struct NodeList: View { .font(.callout) if connected { HStack(alignment: .bottom) { - Image(systemName: "repeat.circle.fill") - .font(.callout) + Image(systemName: "antenna.radiowaves.left.and.right.circle.fill") + .font(.footnote) .symbolRenderingMode(.hierarchical) - Text("connected").font(.callout) .foregroundColor(.green) + Text("connected").font(.caption) } } + HStack(alignment: .bottom) { + Image(systemName: node.isOnline ? "checkmark.circle.fill" : "moon.circle.fill") + .font(.footnote) + .symbolRenderingMode(.hierarchical) + .foregroundColor(node.isOnline ? .green : .orange) + LastHeardText(lastHeard: node.lastHeard) + .font(.caption) + } if node.positions?.count ?? 0 > 0 && (bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral?.num ?? -1 != node.num) { HStack(alignment: .bottom) { let lastPostion = node.positions!.reversed()[0] as! PositionEntity @@ -91,13 +99,6 @@ struct NodeList: View { .font(.footnote) } } - HStack(alignment: .bottom) { - Image(systemName: "clock.badge.checkmark.fill") - .font(.caption) - .symbolRenderingMode(.hierarchical) - LastHeardText(lastHeard: node.lastHeard) - .font(.caption) - } if !connected { HStack(alignment: .bottom) { let preset = ModemPresets(rawValue: Int(connectedNode?.loRaConfig?.modemPreset ?? 0)) LoRaSignalStrengthMeter(snr: node.snr, rssi: node.rssi, preset: preset ?? ModemPresets.longFast, compact: true) @@ -112,6 +113,7 @@ struct NodeList: View { } } .listStyle(.plain) + .navigationSplitViewColumnWidth(300) .navigationTitle(String.localizedStringWithFormat("nodes %@".localized, String(nodes.count))) .navigationBarItems(leading: MeshtasticLogo() diff --git a/en.lproj/Localizable.strings b/en.lproj/Localizable.strings index 97b8db37..f32414d3 100644 --- a/en.lproj/Localizable.strings +++ b/en.lproj/Localizable.strings @@ -50,7 +50,7 @@ "config.save.confirm"="After config values save the node will reboot."; "communicating"="Communicating with device. ."; "connected.radio"="Connected Radio"; -"connected"="Connected"; +"connected"="Bluetooth Connected"; "connecting"="Connecting . ."; "contacts"="Contacts"; "contacts %@"="Contacts (%@)";