From 255e10bbe5790fac3636b2a1eea3b808a5d1772d Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 10 May 2023 13:44:27 -0700 Subject: [PATCH] * New Tile Server * More Emoji * Signal Strength indicators for lora * Restrict tile overlays to zoom levels --- Meshtastic/Enums/AppSettingsEnums.swift | 11 ++++++- Meshtastic/Extensions/FileManager.swift | 4 +-- Meshtastic/Views/Bluetooth/Connect.swift | 13 ++++---- .../Views/Helpers/ConnectedDevice.swift | 4 +-- .../Helpers/LoRaSignalStrengthIndicator.swift | 31 +++++++++++++++++++ .../Views/Helpers/Node/NodeInfoView.swift | 22 ++++++------- .../Views/Map/Custom/MapViewSwiftUI.swift | 9 +++--- .../Views/Messages/UserMessageList.swift | 1 - Meshtastic/Views/Nodes/DeviceMetricsLog.swift | 16 ++++++---- .../Views/Nodes/EnvironmentMetricsLog.swift | 14 +++++---- Meshtastic/Views/Nodes/NodeList.swift | 23 +++++++------- Meshtastic/Views/Nodes/NodeMap.swift | 1 - Meshtastic/Views/Nodes/PositionLog.swift | 10 +++--- Meshtastic/Views/Settings/AppSettings.swift | 18 +++++------ en.lproj/Localizable.strings | 2 +- 15 files changed, 111 insertions(+), 68 deletions(-) diff --git a/Meshtastic/Enums/AppSettingsEnums.swift b/Meshtastic/Enums/AppSettingsEnums.swift index d805bdfd..be2c2850 100644 --- a/Meshtastic/Enums/AppSettingsEnums.swift +++ b/Meshtastic/Enums/AppSettingsEnums.swift @@ -148,6 +148,7 @@ enum MapTileServerLinks: String, CaseIterable, Identifiable { case usgsTopo case usgsImageryTopo case usgsImageryOnly + case terrain case toner case watercolor var id: String { self.rawValue } @@ -173,8 +174,10 @@ enum MapTileServerLinks: String, CaseIterable, Identifiable { return "[USGS](https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer) [National Map](http://nationalmap.gov/) imagery and topographic overlay." case .usgsImageryOnly: return "[USGS](https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer) [National Map](http://nationalmap.gov/) imagery only overlay." + case .terrain: + return "[Map Tiles](http://maps.stamen.com/#terrain/) by [Stamen Design](https://stamen.com), under [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/). Data © [OpenStreetMap](http://www.openstreetmap.org) contributors under [CC-BY-SA](http://creativecommons.org/licenses/by-sa/2.0/)." case .toner: - return "[Stamen Design's](https://github.com/stamen/toner-carto) black and white map tiles." + return "[Map Tiles](http://maps.stamen.com/#toner/) by [Stamen Design](https://stamen.com), under [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/). Data © [OpenStreetMap](http://www.openstreetmap.org) contributors under [CC-BY-SA](http://creativecommons.org/licenses/by-sa/2.0/)." case .watercolor: return "Cooper Hewitt, Smithsonian Design Museum's [Watercolor Maptiles](https://watercolormaps.collection.cooperhewitt.org/) is a open-source mapping tool created by Stamen Design and built on [OpenStreetMap](http://www.openstreetmap.org) data." } @@ -199,6 +202,8 @@ enum MapTileServerLinks: String, CaseIterable, Identifiable { return "USGS Topo Imagery" case .usgsImageryOnly: return "USGS Imagery Only" + case .terrain: + return "Terrain" case .toner: return "Toner" case .watercolor: @@ -225,6 +230,8 @@ enum MapTileServerLinks: String, CaseIterable, Identifiable { return "https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer/tile/{z}/{y}/{x}" case .usgsImageryOnly: return "https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}" + case .terrain: + return "https://stamen-tiles-d.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png" case .toner: return "https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png" case .watercolor: @@ -252,6 +259,8 @@ enum MapTileServerLinks: String, CaseIterable, Identifiable { return [Int](6...15) case .usgsImageryOnly: return [Int](6...15) + case .terrain: + return [Int](0...15) case .toner: return [Int](0...18) case .watercolor: diff --git a/Meshtastic/Extensions/FileManager.swift b/Meshtastic/Extensions/FileManager.swift index 36e58395..2970bad4 100644 --- a/Meshtastic/Extensions/FileManager.swift +++ b/Meshtastic/Extensions/FileManager.swift @@ -52,11 +52,11 @@ public extension FileManager { do { accumulatedSize += try contentItemURL.regularFileAllocatedSize() } catch { - print("❤️ \(error.localizedDescription)") + print("💥 File Manager Error: \(error.localizedDescription)") } } - if let error = enumeratorError { print("❤️ AllocatedSizeOfDirectory enumeratorError = \(error.localizedDescription)") } + if let error = enumeratorError { print("💥 AllocatedSizeOfDirectory enumeratorError = \(error.localizedDescription)") } return Double(accumulatedSize).toBytes diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 8cd3c98c..70fb6101 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -49,12 +49,10 @@ struct Connect: View { Section(header: Text("connected.radio").font(.title)) { if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected { HStack { - Image(systemName: "antenna.radiowaves.left.and.right") - .resizable() - .symbolRenderingMode(.hierarchical) - .foregroundColor(.green) - .frame(width: 60, height: 60) - .padding(.trailing) + VStack(alignment: .center) { + CircleText(text: node?.user?.shortName ?? "???", color: Color(UIColor(hex: UInt32(node?.num ?? 0))), circleSize: 80, fontSize: (node?.user?.shortName ?? "???").isEmoji() ? 52 : 30, textColor: UIColor(hex: UInt32(node?.num ?? 0)).isLight() ? .black : .white ) + } + .padding(.trailing) VStack(alignment: .leading) { if node != nil { Text(bleManager.connectedPeripheral.longName).font(.title2) @@ -74,7 +72,8 @@ struct Connect: View { } } } - .font(.caption).foregroundColor(Color.gray) + .font(.caption) + .foregroundColor(Color.gray) .padding([.top, .bottom]) .swipeActions { diff --git a/Meshtastic/Views/Helpers/ConnectedDevice.swift b/Meshtastic/Views/Helpers/ConnectedDevice.swift index ce0f5e66..f3373654 100644 --- a/Meshtastic/Views/Helpers/ConnectedDevice.swift +++ b/Meshtastic/Views/Helpers/ConnectedDevice.swift @@ -8,7 +8,7 @@ import SwiftUI struct ConnectedDevice: View { var bluetoothOn: Bool var deviceConnected: Bool - var name: String? + var name: String var body: some View { @@ -20,7 +20,7 @@ struct ConnectedDevice: View { .imageScale(.large) .foregroundColor(.green) .symbolRenderingMode(.hierarchical) - Text(name!).font(.callout).foregroundColor(.gray) + Text(name).font(name.isEmoji() ? .title : .callout).foregroundColor(.gray) } else { Image(systemName: "antenna.radiowaves.left.and.right.slash") diff --git a/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift b/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift index 56357168..5f88d6d5 100644 --- a/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift +++ b/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift @@ -69,3 +69,34 @@ func getLoRaSignalStrength(snr: Float, rssi: Int32) -> LoRaSignalStrength { return .fair } } + +func getRssiColor(rssi: Int32) -> Color { + if rssi > -115 { + /// Good + return .green + } else if rssi > -115 && rssi < -120 { + /// Fair + return .yellow + } else if rssi > -126 { + /// Bad + return .orange + } else { + // None + return .red + } +} + +func getSnrColor(snr: Float) -> Color { + if snr > -7 { + /// Good + return .green + } else if snr < -7 && snr > -13 { + /// Fair + return .yellow + } else if snr >= -14 { + /// Bad + return .orange + } else { + return .red + } +} diff --git a/Meshtastic/Views/Helpers/Node/NodeInfoView.swift b/Meshtastic/Views/Helpers/Node/NodeInfoView.swift index 255d6788..0c3b95d4 100644 --- a/Meshtastic/Views/Helpers/Node/NodeInfoView.swift +++ b/Meshtastic/Views/Helpers/Node/NodeInfoView.swift @@ -51,10 +51,10 @@ struct NodeInfoView: View { LoRaSignalStrengthIndicator(signalStrength: signalStrength) Text("Signal \(signalStrength.description)").font(.title) Text("SNR \(String(format: "%.2f", node.snr))dB") - .foregroundColor(.gray) + .foregroundColor(getSnrColor(snr: node.snr)) .font(.title3) Text("RSSI \(node.rssi)dB") - .foregroundColor(.gray) + .foregroundColor(getRssiColor(rssi: node.rssi)) .font(.title3) } Divider() @@ -141,35 +141,35 @@ struct NodeInfoView: View { VStack(alignment: .center) { CircleText(text: node.user?.shortName ?? "???", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 65, fontSize: (node.user?.shortName ?? "???").isEmoji() ? 42 : 20, textColor: UIColor(hex: UInt32(node.num)).isLight() ? .black : .white ) } - Divider() - VStack { - if node.user != nil { + + if node.user != nil { + Divider() + VStack { Image(node.user!.hwModel ?? "unset".localized) .resizable() .frame(width: 75, height: 75) .cornerRadius(5) Text(String(node.user!.hwModel ?? "unset".localized)) - .font(.caption).fixedSize() + .font(.caption2).fixedSize() } } - Divider() if node.snr != 0 { + Divider() VStack(alignment: .center) { let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi) LoRaSignalStrengthIndicator(signalStrength: signalStrength) Text("Signal \(signalStrength.description)").font(.footnote) Text("SNR \(String(format: "%.2f", node.snr))dB") - .foregroundColor(.gray) + .foregroundColor(getSnrColor(snr: node.snr)) .font(.caption2) Text("RSSI \(node.rssi)dB") - .foregroundColor(.gray) + .foregroundColor(getRssiColor(rssi: node.rssi)) .font(.caption2) } - Divider() } let deviceMetrics = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0")) if deviceMetrics?.count ?? 0 >= 1 { - + Divider() let mostRecent = deviceMetrics?.lastObject as? TelemetryEntity VStack(alignment: .center) { BatteryGauge(batteryLevel: Double(mostRecent?.batteryLevel ?? 0)) diff --git a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift index 1bfaa379..bd4e9e36 100644 --- a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift +++ b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift @@ -105,8 +105,8 @@ struct MapViewSwiftUI: UIViewRepresentable { if !UserDefaults.enableOfflineMapsMBTiles { let overlay = TileOverlay() overlay.canReplaceMapContent = false - //overlay.minimumZ = 0 - //overlay.maximumZ = 17 + overlay.minimumZ = UserDefaults.mapTileServer.zoomRange.startIndex + overlay.maximumZ = UserDefaults.mapTileServer.zoomRange.endIndex mapView.addOverlay(overlay, level: UserDefaults.mapTilesAboveLabels ? .aboveLabels : .aboveRoads) } case .satellite: @@ -199,7 +199,6 @@ struct MapViewSwiftUI: UIViewRepresentable { print("Annotation Count: \(annotationCount) Map Annotations: \(mapView.annotations.count)") mapView.removeAnnotations(mapView.annotations) mapView.addAnnotations(waypoints) - mapView.addAnnotations(showNodeHistory ? positions : latest) } if userTrackingMode == MKUserTrackingMode.none { mapView.showsUserLocation = false @@ -209,14 +208,15 @@ struct MapViewSwiftUI: UIViewRepresentable { if latest.count == 1 { mapView.fit(annotations: showNodeHistory ? positions : latest, andShow: true) } else { + mapView.addAnnotations(showNodeHistory ? positions : latest) mapView.fitAllAnnotations() } } } else { + mapView.addAnnotations(showNodeHistory ? positions : latest) mapView.showsUserLocation = true } - mapView.setUserTrackingMode(userTrackingMode, animated: true) } @@ -381,7 +381,6 @@ struct MapViewSwiftUI: UIViewRepresentable { if view.tag > 0 { parent.onWaypointEdit(view.tag) } - print(waypointAnnotation) default: break } diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index 667dff78..edf84dfc 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -204,7 +204,6 @@ struct UserMessageList: View { .id(message.messageId) .alert(isPresented: $showDeleteMessageAlert) { Alert(title: Text("Are you sure you want to delete this message?"), message: Text("This action is permanent."), primaryButton: .destructive(Text("Delete")) { - print("OK button tapped") if deleteMessageId > 0 { let message = user.messageList.first(where: { $0.messageId == deleteMessageId }) context.delete(message!) diff --git a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift index 5a7075bb..c34862f2 100644 --- a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift +++ b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift @@ -119,11 +119,13 @@ struct DeviceMetricsLog: View { } else { ScrollView { let columns = [ - GridItem(.flexible(minimum: 30, maximum: 60), spacing: 0.1), - GridItem(.flexible(minimum: 30, maximum: 60), spacing: 0.1), + //GridItem(.flexible(minimum: 30, maximum: 60), spacing: 0.1), + GridItem(.flexible(minimum: 30, maximum: 45), spacing: 0.1), + GridItem(.flexible(minimum: 30, maximum: 50), spacing: 0.1), GridItem(.flexible(minimum: 30, maximum: 70), spacing: 0.1), GridItem(.flexible(minimum: 30, maximum: 65), spacing: 0.1), - GridItem(spacing: 0) + GridItem(.flexible(minimum: 130, maximum: 200), spacing: 0.1) + ] LazyVGrid(columns: columns, alignment: .leading, spacing: 1) { GridRow { @@ -159,7 +161,7 @@ struct DeviceMetricsLog: View { Text("\(String(format: "%.2f", dm.airUtilTx))%") .font(.caption) Text(dm.time?.formattedDate(format: dateFormatString) ?? "Unknown time") - .font(.caption2) + .font(.caption) } } } @@ -177,7 +179,8 @@ struct DeviceMetricsLog: View { .buttonStyle(.bordered) .buttonBorderShape(.capsule) .controlSize(.large) - .padding() + .padding(.bottom) + .padding(.trailing) .confirmationDialog( "are.you.sure", isPresented: $isPresentingClearLogConfirm, @@ -200,7 +203,8 @@ struct DeviceMetricsLog: View { .buttonStyle(.bordered) .buttonBorderShape(.capsule) .controlSize(.large) - .padding() + .padding(.bottom) + .padding(.trailing) } .navigationTitle("device.metrics.log") .navigationBarTitleDisplayMode(.inline) diff --git a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift index 881e54cd..2856554d 100644 --- a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift +++ b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift @@ -108,10 +108,10 @@ struct EnvironmentMetricsLog: View { } else { ScrollView { let columns = [ + GridItem(.flexible(minimum: 30, maximum: 50), spacing: 0.1), GridItem(.flexible(minimum: 30, maximum: 60), spacing: 0.1), GridItem(.flexible(minimum: 30, maximum: 60), spacing: 0.1), - GridItem(.flexible(minimum: 30, maximum: 60), spacing: 0.1), - GridItem(.flexible(minimum: 30, maximum: 60), spacing: 0.1), + GridItem(.flexible(minimum: 30, maximum: 50), spacing: 0.1), GridItem(spacing: 0) ] LazyVGrid(columns: columns, alignment: .leading, spacing: 1, pinnedViews: [.sectionHeaders]) { @@ -146,7 +146,7 @@ struct EnvironmentMetricsLog: View { Text("\(String(format: "%.2f", em.gasResistance))") .font(.caption) Text(em.time?.formattedDate(format: dateFormatString) ?? "unknown.age".localized) - .font(.caption2) + .font(.caption) } } } @@ -160,12 +160,13 @@ struct EnvironmentMetricsLog: View { Button(role: .destructive) { isPresentingClearLogConfirm = true } label: { - Label("Clear Log", systemImage: "trash.fill") + Label("clear.log", systemImage: "trash.fill") } .buttonStyle(.bordered) .buttonBorderShape(.capsule) .controlSize(.large) - .padding() + .padding(.bottom) + .padding(.trailing) .confirmationDialog( "are.you.sure", isPresented: $isPresentingClearLogConfirm, @@ -186,7 +187,8 @@ struct EnvironmentMetricsLog: View { .buttonStyle(.bordered) .buttonBorderShape(.capsule) .controlSize(.large) - .padding() + .padding(.bottom) + .padding(.leading) } .navigationTitle("Environment Metrics Log") .navigationBarTitleDisplayMode(.inline) diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 45ffb00f..f04291e2 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -38,13 +38,15 @@ struct NodeList: View { CircleText(text: node.user?.shortName ?? "???", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 65, fontSize: (node.user?.shortName ?? "???").isEmoji() ? 44 : 22, brightness: 0.0, textColor: UIColor(hex: UInt32(node.num)).isLight() ? .black : .white) .padding(.trailing, 5) VStack(alignment: .leading) { - Text(node.user?.longName ?? "unknown".localized).font(.headline) + Text(node.user?.longName ?? "unknown".localized) + .fontWeight(.medium) + .font(.callout) if connected { - HStack(alignment: .bottom) { + HStack { Image(systemName: "repeat.circle.fill") - .font(.title3) + .font(.callout) .symbolRenderingMode(.hierarchical) - Text("connected").font(.subheadline) + Text("connected").font(.callout) .foregroundColor(.green) } } @@ -56,28 +58,27 @@ struct NodeList: View { let nodeCoord = CLLocation(latitude: lastPostion.nodeCoordinate!.latitude, longitude: lastPostion.nodeCoordinate!.longitude) let metersAway = nodeCoord.distance(from: myCoord) Image(systemName: "lines.measurement.horizontal") - .font(.title3) + .font(.footnote) .symbolRenderingMode(.hierarchical) - - DistanceText(meters: metersAway).font(.subheadline) + DistanceText(meters: metersAway).font(.footnote) } } } if node.channel > 0 { HStack(alignment: .bottom) { Image(systemName: "fibrechannel") - .font(.title3) + .font(.footnote) .symbolRenderingMode(.hierarchical) Text("Channel: \(node.channel)") - .font(.subheadline) + .font(.footnote) } } HStack(alignment: .bottom) { Image(systemName: "clock.badge.checkmark.fill") - .font(.title3) + .font(.caption) .symbolRenderingMode(.hierarchical) LastHeardText(lastHeard: node.lastHeard) - .font(.subheadline) + .font(.caption) } } .frame(maxWidth: .infinity, alignment: .leading) diff --git a/Meshtastic/Views/Nodes/NodeMap.swift b/Meshtastic/Views/Nodes/NodeMap.swift index f271c24d..2390711b 100644 --- a/Meshtastic/Views/Nodes/NodeMap.swift +++ b/Meshtastic/Views/Nodes/NodeMap.swift @@ -166,7 +166,6 @@ struct NodeMap: View { .pickerStyle(DefaultPickerStyle()) .onChange(of: (selectedTileServer)) { newSelectedTileServer in UserDefaults.mapTileServer = newSelectedTileServer - //tileManager.removeAll() selectedMapLayer = .standard } Text("Attribution:") diff --git a/Meshtastic/Views/Nodes/PositionLog.swift b/Meshtastic/Views/Nodes/PositionLog.swift index 71928eae..87488d6b 100644 --- a/Meshtastic/Views/Nodes/PositionLog.swift +++ b/Meshtastic/Views/Nodes/PositionLog.swift @@ -121,12 +121,13 @@ struct PositionLog: View { Button(role: .destructive) { isPresentingClearLogConfirm = true } label: { - Label("Clear Log", systemImage: "trash.fill") + Label("clear.log", systemImage: "trash.fill") } .buttonStyle(.bordered) .buttonBorderShape(.capsule) .controlSize(.large) - .padding() + .padding(.bottom) + .padding(.trailing) .confirmationDialog( "are.you.sure", isPresented: $isPresentingClearLogConfirm, @@ -143,10 +144,8 @@ struct PositionLog: View { } Button { - exportString = positionToCsvFile(positions: node.positions!.array as? [PositionEntity] ?? []) isExporting = true - } label: { Label("save", systemImage: "square.and.arrow.down") @@ -154,7 +153,8 @@ struct PositionLog: View { .buttonStyle(.bordered) .buttonBorderShape(.capsule) .controlSize(.large) - .padding() + .padding(.bottom) + .padding(.leading) } .fileExporter( isPresented: $isExporting, diff --git a/Meshtastic/Views/Settings/AppSettings.swift b/Meshtastic/Views/Settings/AppSettings.swift index 20c89de8..3da32607 100644 --- a/Meshtastic/Views/Settings/AppSettings.swift +++ b/Meshtastic/Views/Settings/AppSettings.swift @@ -35,29 +35,30 @@ struct AppSettings: View { let speed = Measurement(value: locationHelper.locationManager.location?.speed ?? 0, unit: UnitSpeed.kilometersPerHour) HStack { Label("Accuracy \(accuracy.formatted())", systemImage: "scope") - .font(.callout) + .font(.footnote) Label("Sats \(LocationHelper.satsInView)", systemImage: "sparkles") - .font(.callout) + .font(.footnote) } - Label("Coordinates \(String(format: "%.5f", locationHelper.locationManager.location?.coordinate.latitude ?? 0)), \(String(format: "%.5f", locationHelper.locationManager.location?.coordinate.longitude ?? 0))", systemImage: "mappin") - .font(.callout) + Label("Coordinate \(String(format: "%.5f", locationHelper.locationManager.location?.coordinate.latitude ?? 0)), \(String(format: "%.5f", locationHelper.locationManager.location?.coordinate.longitude ?? 0))", systemImage: "mappin") + .font(.footnote) .textSelection(.enabled) if locationHelper.locationManager.location?.verticalAccuracy ?? 0 > 0 { Label("Altitude \(altitiude.formatted())", systemImage: "mountain.2") - .font(.callout) + .font(.footnote) } if locationHelper.locationManager.location?.courseAccuracy ?? 0 > 0 { Label("Heading \(String(format: "%.2f", locationHelper.locationManager.location?.course ?? 0))°", systemImage: "location.circle") - .font(.callout) + .font(.footnote) } if locationHelper.locationManager.location?.speedAccuracy ?? 0 > 0 { Label("Speed \(speed.formatted())", systemImage: "speedometer") - .font(.callout) + .font(.footnote) } Toggle(isOn: $provideLocation) { Label("provide.location", systemImage: "location.circle.fill") + .font(.footnote) } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) @@ -74,10 +75,9 @@ struct AppSettings: View { } Text("phone.gps.interval.description") - .font(.caption) + .font(.caption2) .foregroundColor(.gray) } - } TilesView() } diff --git a/en.lproj/Localizable.strings b/en.lproj/Localizable.strings index 1ecdb327..8f22be14 100644 --- a/en.lproj/Localizable.strings +++ b/en.lproj/Localizable.strings @@ -45,7 +45,7 @@ "channel.utilization"="Channel Utilization"; "channels"="Channels"; "clear.app.data"="Clear App Data"; -"clear.log"="Clear Log"; +"clear.log"="Clear"; "close"="Close"; "config.save.confirm"="After config values save the node will reboot."; "communicating"="Communicating with device. .";