mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Localize route recorder buttons
Actually record data with the route recorder Add version number to about view Make speed faster
This commit is contained in:
parent
91407e65ea
commit
7302dc3e35
11 changed files with 148 additions and 56 deletions
|
|
@ -180,6 +180,7 @@
|
|||
DDF6B2482A9AEBF500BA6931 /* StoreForward.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF6B2472A9AEBF500BA6931 /* StoreForward.swift */; };
|
||||
DDF924CA26FBB953009FE055 /* ConnectedDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF924C926FBB953009FE055 /* ConnectedDevice.swift */; };
|
||||
DDFEB3BB29900C1200EE7472 /* CurrentConditionsCompact.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFEB3BA29900C1200EE7472 /* CurrentConditionsCompact.swift */; };
|
||||
DDFFA7472B3A7F3C004730DB /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFFA7462B3A7F3C004730DB /* Bundle.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
|
@ -421,6 +422,7 @@
|
|||
DDF6B24B2A9C2FC800BA6931 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
DDF924C926FBB953009FE055 /* ConnectedDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectedDevice.swift; sourceTree = "<group>"; };
|
||||
DDFEB3BA29900C1200EE7472 /* CurrentConditionsCompact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentConditionsCompact.swift; sourceTree = "<group>"; };
|
||||
DDFFA7462B3A7F3C004730DB /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -905,6 +907,7 @@
|
|||
DDB75A0E2A05920E006ED576 /* FileManager.swift */,
|
||||
DDB75A102A059258006ED576 /* Url.swift */,
|
||||
DD1933772B084F4200771CD5 /* Measurement.swift */,
|
||||
DDFFA7462B3A7F3C004730DB /* Bundle.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1123,6 +1126,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DDDB444829F8A9C900EE2349 /* String.swift in Sources */,
|
||||
DDFFA7472B3A7F3C004730DB /* Bundle.swift in Sources */,
|
||||
DD5E520C298EE33B00D21B61 /* portnums.pb.swift in Sources */,
|
||||
DD457188293C7E63000C49FB /* BLESignalStrengthIndicator.swift in Sources */,
|
||||
DDFEB3BB29900C1200EE7472 /* CurrentConditionsCompact.swift in Sources */,
|
||||
|
|
@ -1486,7 +1490,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.2.17;
|
||||
MARKETING_VERSION = 2.2.18;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -1520,7 +1524,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.2.17;
|
||||
MARKETING_VERSION = 2.2.18;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -1642,7 +1646,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.2.17;
|
||||
MARKETING_VERSION = 2.2.18;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
@ -1675,7 +1679,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.2.17;
|
||||
MARKETING_VERSION = 2.2.18;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
|
|||
22
Meshtastic/Extensions/Bundle.swift
Normal file
22
Meshtastic/Extensions/Bundle.swift
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// Bundle.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Created by Garth Vander Houwen on 12/25/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Bundle {
|
||||
public var appName: String { getInfo("CFBundleName") }
|
||||
public var displayName: String { getInfo("CFBundleDisplayName") }
|
||||
public var language: String { getInfo("CFBundleDevelopmentRegion") }
|
||||
public var identifier: String { getInfo("CFBundleIdentifier") }
|
||||
public var copyright: String { getInfo("NSHumanReadableCopyright").replacingOccurrences(of: "\\\\n", with: "\n") }
|
||||
|
||||
public var appBuild: String { getInfo("CFBundleVersion") }
|
||||
public var appVersionLong: String { getInfo("CFBundleShortVersionString") }
|
||||
//public var appVersionShort: String { getInfo("CFBundleShortVersion") }
|
||||
|
||||
fileprivate func getInfo(_ str: String) -> String { infoDictionary?[str] as? String ?? "⚠️" }
|
||||
}
|
||||
|
|
@ -8,11 +8,10 @@
|
|||
import SwiftUI
|
||||
import CoreLocation
|
||||
|
||||
|
||||
// Shared state that manages the `CLLocationManager` and `CLBackgroundActivitySession`.
|
||||
@available(iOS 17.0, macOS 14.0, *)
|
||||
@MainActor class LocationsHandler: ObservableObject {
|
||||
|
||||
|
||||
static let shared = LocationsHandler() // Create a single, shared instance of the object.
|
||||
private let manager: CLLocationManager
|
||||
private var background: CLBackgroundActivitySession?
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
position.longitudeI = nodeInfo.position.longitudeI
|
||||
position.altitude = nodeInfo.position.altitude
|
||||
position.satsInView = Int32(nodeInfo.position.satsInView)
|
||||
position.speed = Int32(nodeInfo.position.groundSpeed)
|
||||
position.speed = Int32(nodeInfo.position.groundSpeed * UInt32(3.6))
|
||||
position.heading = Int32(nodeInfo.position.groundTrack)
|
||||
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
|
||||
var newPostions = [PositionEntity]()
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
position.longitudeI = positionMessage.longitudeI
|
||||
position.altitude = positionMessage.altitude
|
||||
position.satsInView = Int32(positionMessage.satsInView)
|
||||
position.speed = Int32(positionMessage.groundSpeed)
|
||||
position.speed = Int32(positionMessage.groundSpeed * UInt32(3.6))
|
||||
position.heading = Int32(positionMessage.groundTrack)
|
||||
if positionMessage.timestamp != 0 {
|
||||
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.timestamp)))
|
||||
|
|
|
|||
|
|
@ -50,6 +50,12 @@ struct AboutMeshtastic: View {
|
|||
}
|
||||
}
|
||||
.font(.title2)
|
||||
|
||||
Text("Version: \(Bundle.main.appVersionLong) (\(Bundle.main.appBuild)) ")
|
||||
|
||||
Text(Bundle.main.copyright)
|
||||
.font(.system(size: 10, weight: .thin))
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
|
||||
Section(header: Text("Project information")) {
|
||||
|
|
|
|||
|
|
@ -11,53 +11,51 @@ import MapKit
|
|||
import CoreLocation
|
||||
import CoreMotion
|
||||
|
||||
struct TimerDisplayObject {
|
||||
var seconds: Int = 0
|
||||
var minutes: Int = 0
|
||||
var hours: Int = 0
|
||||
|
||||
var display: String {
|
||||
if self.seconds == 0 {
|
||||
"\(String(format: "%02d", self.hours)):\(String(format: "%02d", self.minutes)):00"
|
||||
} else {
|
||||
"\(String(format: "%02d", self.hours)):\(String(format: "%02d", self.minutes)):\(String(format: "%02d", self.seconds))"
|
||||
}
|
||||
}
|
||||
|
||||
var timeMinuteCalculator: Float { Float(hours*60+seconds/60+minutes) }
|
||||
}
|
||||
|
||||
@available(iOS 17.0, macOS 14.0, *)
|
||||
struct RouteRecorder: View {
|
||||
|
||||
@ObservedObject var locationsHandler: LocationsHandler = LocationsHandler.shared
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@State private var position: MapCameraPosition = .userLocation(followsHeading: true, fallback: .automatic)
|
||||
//@State var mapStyle: MapStyle = MapStyle.hybrid(elevation: .realistic, pointsOfInterest: .all, showsTraffic: true)
|
||||
@State var mapStyle: MapStyle = MapStyle.standard(elevation: .realistic)
|
||||
@State var isShowingDetails = false
|
||||
@Namespace var namespace
|
||||
@Namespace var routerecorderscope
|
||||
@State var recording: RouteEntity?
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
VStack {
|
||||
ZStack {
|
||||
Map(position: $position, scope: routerecorderscope) {
|
||||
UserAnnotation()
|
||||
// ForEach(locations, id: \.id) { location in
|
||||
// Marker(location.name, systemImage: location.icon, coordinate: location.location)
|
||||
// .tint(location.colour)
|
||||
// }
|
||||
/// Route Lines
|
||||
let lineCoords = locationsHandler.locationsArray.compactMap({(position) -> CLLocationCoordinate2D in
|
||||
return position.coordinate
|
||||
})
|
||||
let gradient = LinearGradient(
|
||||
colors: [.blue],
|
||||
startPoint: .leading, endPoint: .trailing
|
||||
)
|
||||
let dashed = StrokeStyle(
|
||||
lineWidth: 3,
|
||||
lineCap: .round, lineJoin: .round, dash: [10, 10]
|
||||
)
|
||||
MapPolyline(coordinates: lineCoords)
|
||||
.stroke(gradient, style: dashed)
|
||||
|
||||
}
|
||||
.mapStyle(mapStyle)
|
||||
}
|
||||
.ignoresSafeArea(.all, edges: [.top, .leading, .trailing])
|
||||
.mapScope(routerecorderscope)
|
||||
.mapControls {
|
||||
MapUserLocationButton()
|
||||
MapCompass()
|
||||
MapScaleView()
|
||||
MapPitchToggle()
|
||||
}
|
||||
.mapStyle(.hybrid(elevation: .realistic, showsTraffic: true))
|
||||
// .mapControls {
|
||||
// MapScaleView(scope: routerecorderscope)
|
||||
// MapUserLocationButton(scope: routerecorderscope)
|
||||
// MapPitchToggle(scope: routerecorderscope)
|
||||
// MapCompass(scope: routerecorderscope)
|
||||
// }
|
||||
.transition(.slide)
|
||||
.mapControlVisibility(.visible)
|
||||
.safeAreaInset(edge: .bottom) {
|
||||
ZStack {
|
||||
VStack {
|
||||
|
|
@ -90,12 +88,16 @@ struct RouteRecorder: View {
|
|||
HStack (alignment: .center) {
|
||||
Image(systemName: "record.circle.fill")
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.font(.title3)
|
||||
.font(.title)
|
||||
.foregroundColor(.red)
|
||||
Text("Recording route - \(locationsHandler.count) locations")
|
||||
.font(.title3)
|
||||
Text("Recording route")
|
||||
.font(.title)
|
||||
Spacer()
|
||||
Text("\(locationsHandler.count)")
|
||||
.foregroundColor(.red)
|
||||
.font(.title2)
|
||||
}
|
||||
.padding(.top)
|
||||
.padding()
|
||||
} else if locationsHandler.isRecordingPaused {
|
||||
HStack (alignment: .center) {
|
||||
|
||||
|
|
@ -104,18 +106,17 @@ struct RouteRecorder: View {
|
|||
.font(.title3)
|
||||
.foregroundColor(.red)
|
||||
Text("Route recording paused")
|
||||
.font(.title3)
|
||||
.font(.title)
|
||||
}
|
||||
.padding(.top)
|
||||
}
|
||||
|
||||
|
||||
if locationsHandler.isRecording || locationsHandler.isRecordingPaused {
|
||||
Divider()
|
||||
HStack {
|
||||
VStack {
|
||||
Text(locationsHandler.recordingStarted ?? Date(), style: .timer)
|
||||
.font(.largeTitle)
|
||||
.font(.title)
|
||||
.fixedSize()
|
||||
Text("Time")
|
||||
.font(.callout)
|
||||
|
|
@ -126,7 +127,7 @@ struct RouteRecorder: View {
|
|||
VStack {
|
||||
let distance = Measurement(value: locationsHandler.distanceTraveled, unit: UnitLength.meters)
|
||||
Text("\(distance.formatted())")
|
||||
.font(.largeTitle)
|
||||
.font(.title)
|
||||
.fixedSize()
|
||||
Text("Distance")
|
||||
.font(.callout)
|
||||
|
|
@ -137,12 +138,11 @@ struct RouteRecorder: View {
|
|||
VStack {
|
||||
let gain = Measurement(value: locationsHandler.elevationGain, unit: UnitLength.meters)
|
||||
Text(gain.formatted())
|
||||
.font(.largeTitle)
|
||||
.font(.title)
|
||||
Text("Elev. Gain")
|
||||
.font(.callout)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
|
||||
}
|
||||
.frame(maxHeight: 90)
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ struct RouteRecorder: View {
|
|||
HStack {
|
||||
Spacer()
|
||||
if !locationsHandler.isRecording && !locationsHandler.isRecordingPaused {
|
||||
/// We are not recording or paused, show start recording button a new recording
|
||||
/// We are not recording or paused, show start recording button
|
||||
Button {
|
||||
locationsHandler.isRecording = true
|
||||
locationsHandler.count = 0
|
||||
|
|
@ -163,8 +163,23 @@ struct RouteRecorder: View {
|
|||
locationsHandler.elevationGain = 0.0
|
||||
locationsHandler.locationsArray.removeAll()
|
||||
locationsHandler.recordingStarted = Date()
|
||||
let newRoute = RouteEntity(context: context)
|
||||
newRoute.name = String("Route Recording - \(Date().formatted())")
|
||||
newRoute.id = Int32.random(in: Int32(Int8.max) ... Int32.max)
|
||||
newRoute.color = Int64(UIColor.random.hex)
|
||||
newRoute.date = Date()
|
||||
newRoute.enabled = true
|
||||
self.recording = newRoute
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Saved a new route")
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving RouteEntity from the Route Recorder \(nsError)")
|
||||
}
|
||||
} label: {
|
||||
Label("start", systemImage: "start")
|
||||
Label("start", systemImage: "play")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
|
|
@ -184,7 +199,7 @@ struct RouteRecorder: View {
|
|||
.controlSize(.large)
|
||||
.padding(.bottom)
|
||||
} else if locationsHandler.isRecordingPaused {
|
||||
/// We are recording show pause button
|
||||
/// We are paused show resume button
|
||||
Button {
|
||||
locationsHandler.isRecording = true
|
||||
locationsHandler.isRecordingPaused = false
|
||||
|
|
@ -198,8 +213,7 @@ struct RouteRecorder: View {
|
|||
}
|
||||
|
||||
if locationsHandler.isRecording || locationsHandler.isRecordingPaused {
|
||||
|
||||
/// We are recording show pause button
|
||||
/// We are recording or paused, show finish button
|
||||
Button {
|
||||
locationsHandler.isRecording = false
|
||||
locationsHandler.isRecordingPaused = false
|
||||
|
|
@ -215,7 +229,7 @@ struct RouteRecorder: View {
|
|||
.controlSize(.large)
|
||||
.padding(.bottom)
|
||||
}
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
Button(role: .cancel) {
|
||||
isShowingDetails = false
|
||||
} label: {
|
||||
|
|
@ -225,14 +239,41 @@ struct RouteRecorder: View {
|
|||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding(.bottom)
|
||||
#endif
|
||||
Spacer()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
.presentationDetents([.fraction(0.30), .fraction(0.65)])
|
||||
.presentationDragIndicator(.hidden)
|
||||
.interactiveDismissDisabled(false)
|
||||
.onChange(of: locationsHandler.locationsArray.last) { newLoc in
|
||||
if locationsHandler.isRecording {
|
||||
if let loc = newLoc {
|
||||
if recording != nil {
|
||||
let locationEntity = LocationEntity(context: context)
|
||||
locationEntity.routeLocation = recording
|
||||
locationEntity.id = Int32(locationsHandler.count)
|
||||
locationEntity.altitude = Int32(loc.altitude)
|
||||
locationEntity.heading = Int32(loc.course)
|
||||
locationEntity.speed = Int32(loc.speed)
|
||||
locationEntity.latitudeI = Int32(loc.coordinate.latitude * 1e7)
|
||||
locationEntity.longitudeI = Int32(loc.coordinate.longitude * 1e7)
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Saved a new route location")
|
||||
//print("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num)")
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving LocationEntity from the Route Recorder \(nsError)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.presentationDetents([.fraction(0.65)])
|
||||
.presentationDragIndicator(.hidden)
|
||||
.interactiveDismissDisabled()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
"encrypted"="Verschlüsselt";
|
||||
"external.notification"="Externe Benachrichtigung";
|
||||
"external.notification.config"="Einstellungen der externen Benachrichtigung";
|
||||
"finish"="Finish";
|
||||
"firmware.version"="Firmware Version";
|
||||
"firmware.version.unsupported"="Nicht unterstützte Firmware Version erkannt. Kann nicht verbinden.";
|
||||
"gas"="Gas";
|
||||
|
|
@ -213,6 +214,7 @@
|
|||
"on.boot"="Nur beim Starten";
|
||||
"options"="Optionen";
|
||||
"password"="Passwort";
|
||||
"pause"="Pause";
|
||||
"phone.gps"="Telefon GPS";
|
||||
"phone.gps.interval.description"="Wie häufig das Telefon den Standort an das Gerät sendet. Standortaktualisierungen an das Mesh werden vom Gerät verwaltet.";
|
||||
"position"="Position";
|
||||
|
|
@ -228,8 +230,10 @@
|
|||
"reply"="Antworten";
|
||||
"received.ack"="Empfangsbestätigung";
|
||||
"received.ack.real"="Recipient Ack";
|
||||
"resume"="Resume";
|
||||
"ringtone"="Ringtone";
|
||||
"ringtone.config"="Ringtone Config";
|
||||
"route.recorder"="Route Recorder";
|
||||
"routes"="Routes";
|
||||
"routing.acknowledged"="Bestätigt";
|
||||
"routing.noroute"="Keine Route";
|
||||
|
|
@ -264,6 +268,7 @@
|
|||
"set.region"="Setze LoRa Region";
|
||||
"standard"="Standard";
|
||||
"standard.muted"="Standard Muted";
|
||||
"start"="Start";
|
||||
"storeforward"="Store & Forward";
|
||||
"storeforward.config"="Store & Forward Config";
|
||||
"storeforward.heartbeat"="Send Heartbeat";
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
"encrypted"="Encrypted";
|
||||
"external.notification"="External Notification";
|
||||
"external.notification.config"="External Notification Config";
|
||||
"finish"="Finish";
|
||||
"firmware.version"="Firmware Version";
|
||||
"firmware.version.unsupported"="Unsupported Firmware Version Detected, unable to connect to device.";
|
||||
"gas"="Gas";
|
||||
|
|
@ -217,6 +218,7 @@
|
|||
"on.boot"="On Boot Only";
|
||||
"options"="Options";
|
||||
"password"="Password";
|
||||
"pause"="Pause";
|
||||
"phone.gps"="Phone GPS";
|
||||
"phone.gps.interval.description"="How frequently your phone will send your location to the device, location updates to the mesh are managed by the device.";
|
||||
"position"="Position";
|
||||
|
|
@ -232,8 +234,10 @@
|
|||
"reboot.node"="Reboot node?";
|
||||
"received.ack"="Received Ack";
|
||||
"received.ack.real"="Recipient Ack";
|
||||
"resume"="Resume";
|
||||
"ringtone"="Ringtone";
|
||||
"ringtone.config"="Ringtone Config";
|
||||
"route.recorder"="Route Recorder";
|
||||
"routes"="Routes";
|
||||
"routing.acknowledged"="Acknowledged";
|
||||
"routing.noroute"="No Route";
|
||||
|
|
@ -268,6 +272,7 @@
|
|||
"set.region"="Set LoRa Region";
|
||||
"standard"="Standard";
|
||||
"standard.muted"="Standard Muted";
|
||||
"start"="Start";
|
||||
"storeforward"="Store & Forward";
|
||||
"storeforward.config"="Store & Forward Config";
|
||||
"storeforward.heartbeat"="Send Heartbeat";
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
"encrypted"="Zaszyfrowany";
|
||||
"external.notification"="Zewnętrzne Powiadomienie";
|
||||
"external.notification.config"="Konfiguracja Zewnętrznego Powiadomienia";
|
||||
"finish"="Finish";
|
||||
"firmware.version"="Wersja Oprogramowania";
|
||||
"firmware.version.unsupported"="Wykryto nieobsługiwany wersję oprogramowania, brak możliwości połączenia z urządzeniem.";
|
||||
"gas"="Gaz";
|
||||
|
|
@ -214,6 +215,7 @@
|
|||
"on.boot"="Tylko przy uruchomieniu";
|
||||
"options"="Opcje";
|
||||
"password"="Hasło";
|
||||
"pause"="Pause";
|
||||
"phone.gps"="GPS telefonu";
|
||||
"phone.gps.interval.description"="Jak często Twój telefon będzie wysyłał swoją lokalizację do urządzenia, aktualizacje lokalizacji w sieci są zarządzane przez urządzenie.";
|
||||
"position"="Pozycja";
|
||||
|
|
@ -229,8 +231,10 @@
|
|||
"reboot.node"="Uruchomić ponownie węzeł?";
|
||||
"received.ack"="Odebrano potwierdzenie";
|
||||
"received.ack.real"="Odbiorca potwierdzenia";
|
||||
"resume"="Resume";
|
||||
"ringtone"="Dzwonek";
|
||||
"ringtone.config"="Konfiguracja dzwonka";
|
||||
"route.recorder"="Route Recorder";
|
||||
"routes"="Routes";
|
||||
"routing.acknowledged"="Potwierdzono";
|
||||
"routing.noroute"="Brak trasy";
|
||||
|
|
@ -265,6 +269,7 @@
|
|||
"set.region"="Ustaw region LoRa";
|
||||
"standard"="Standardowy";
|
||||
"standard.muted"="Standardowy wyłączony";
|
||||
"start"="Start";
|
||||
"storeforward"="Store & Forward";
|
||||
"storeforward.config"="Store & Forward Config";
|
||||
"storeforward.heartbeat"="Send Heartbeat";
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
"encrypted"="加密";
|
||||
"external.notification"="外部通知";
|
||||
"external.notification.config"="外部通知配置";
|
||||
"finish"="Finish";
|
||||
"firmware.version"="固件版本";
|
||||
"firmware.version.unsupported"="检测到不支持的固件版本,无法连接到电台。";
|
||||
"gas"="Gas";
|
||||
|
|
@ -213,6 +214,7 @@
|
|||
"on.boot"="仅在启动时";
|
||||
"options"="选项";
|
||||
"password"="密码";
|
||||
"pause"="Pause";
|
||||
"phone.gps"="手机 GPS";
|
||||
"phone.gps.interval.description"="电台通过手机获取定位的时间间隔,但是向 Mesh 网络中刷新定位的时间间隔由电台控制。";
|
||||
"position"="定位";
|
||||
|
|
@ -228,8 +230,10 @@
|
|||
"reboot.node"="重启节点?";
|
||||
"received.ack"="收到确认";
|
||||
"received.ack.real"="收件人确认";
|
||||
"resume"="Resume";
|
||||
"ringtone"="铃声";
|
||||
"ringtone.config"="铃声设置";
|
||||
"route.recorder"="Route Recorder";
|
||||
"routes"="Routes";
|
||||
"routing.acknowledged"="确认";
|
||||
"routing.noroute"="找不到目标";
|
||||
|
|
@ -264,6 +268,7 @@
|
|||
"set.region"="设置 LoRa 区域";
|
||||
"standard"="标准";
|
||||
"standard.muted"="标准静音";
|
||||
"start"="Start";
|
||||
"ssid"="SSID";
|
||||
"storeforward"="储存 & 转发";
|
||||
"storeforward.config"="储存 & 转发设置";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue