diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 7bd5cdf7..2d46d94e 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -46,6 +46,7 @@ DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */; }; DD2553572855B02500E55709 /* LoRaConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2553562855B02500E55709 /* LoRaConfig.swift */; }; DD2553592855B52700E55709 /* PositionConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2553582855B52700E55709 /* PositionConfig.swift */; }; + DD268D8E2BCC90E2008073AE /* RouteEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD268D8D2BCC90E2008073AE /* RouteEnums.swift */; }; DD2AD8A8296D2DF9001FF0E7 /* MapViewSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */; }; DD33DB622B3D27C7003E1EA0 /* FirmwareApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD33DB612B3D27C7003E1EA0 /* FirmwareApi.swift */; }; DD3501892852FC3B000FC853 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3501882852FC3B000FC853 /* Settings.swift */; }; @@ -287,6 +288,7 @@ DD2553562855B02500E55709 /* LoRaConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoRaConfig.swift; sourceTree = ""; }; DD2553582855B52700E55709 /* PositionConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionConfig.swift; sourceTree = ""; }; DD268D8C2BCC7D11008073AE /* MeshtasticDataModelV 35.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 35.xcdatamodel"; sourceTree = ""; }; + DD268D8D2BCC90E2008073AE /* RouteEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteEnums.swift; sourceTree = ""; }; DD295CE92B323ED9002CC4AC /* MeshtasticDataModelV22.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV22.xcdatamodel; sourceTree = ""; }; DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewSwiftUI.swift; sourceTree = ""; }; DD2CC2E52ABFE04E00EDFDA7 /* MeshtasticDataModelV19.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV19.xcdatamodel; sourceTree = ""; }; @@ -723,6 +725,7 @@ DDB6ABE528B1406100384BA1 /* LoraConfigEnums.swift */, DD3CC6BF28E7A60700FA9159 /* MessagingEnums.swift */, DDB6ABE128B13FB500384BA1 /* PositionConfigEnums.swift */, + DD268D8D2BCC90E2008073AE /* RouteEnums.swift */, DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */, DD1925B828CDA93900720036 /* SerialConfigEnums.swift */, DD994B68295F88B60013760A /* IntervalEnums.swift */, @@ -1328,6 +1331,7 @@ DDCE4E2C2869F92900BE9F8F /* UserConfig.swift in Sources */, DDB75A212A12B954006ED576 /* LoRaSignalStrength.swift in Sources */, DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */, + DD268D8E2BCC90E2008073AE /* RouteEnums.swift in Sources */, DDB6ABE428B13FFF00384BA1 /* DisplayEnums.swift in Sources */, DD4975A52B147BA90026544E /* AmbientLightingConfig.swift in Sources */, D93068D92B81509C0066FBC8 /* TapbackResponses.swift in Sources */, diff --git a/Meshtastic/Enums/RouteEnums.swift b/Meshtastic/Enums/RouteEnums.swift new file mode 100644 index 00000000..ab2451cc --- /dev/null +++ b/Meshtastic/Enums/RouteEnums.swift @@ -0,0 +1,53 @@ +// +// RouteEnums.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 4/14/24. +// + +import Foundation +import SwiftUI + +enum ActivityType: Int, CaseIterable, Identifiable { + case walking = 0 + case hiking = 1 + case biking = 2 + case driving = 3 + case overlanding = 4 + case skiing = 5 + + var id: Int { self.rawValue } + var description: String { + switch self { + case .walking: + return "routes.activitytype.walking".localized + case .hiking: + return "routes.activitytype.hiking".localized + case .biking: + return "routes.activitytype.biking".localized + case .driving: + return "routes.activitytype.driving".localized + case .overlanding: + return "routes.activitytype.overlanding".localized + case .skiing: + return "routes.activitytype.skiing".localized + } + } + + var fileNameString: String { + switch self { + case .walking: + return "routes.activitytype.filename.walking".localized + case .hiking: + return "routes.activitytype.filename.hiking".localized + case .biking: + return "routes.activitytype.filename.biking".localized + case .driving: + return "routes.activitytype.filename.driving".localized + case .overlanding: + return "routes.activitytype.filename.overlanding".localized + case .skiing: + return "routes.activitytype.filename.skiing".localized + } + } +} diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 35.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 35.xcdatamodel/contents index 296e4582..1abcf420 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 35.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 35.xcdatamodel/contents @@ -328,7 +328,10 @@ + + + diff --git a/Meshtastic/Views/Settings/RouteRecorder.swift b/Meshtastic/Views/Settings/RouteRecorder.swift index 3fba7f8b..5bdf6f52 100644 --- a/Meshtastic/Views/Settings/RouteRecorder.swift +++ b/Meshtastic/Views/Settings/RouteRecorder.swift @@ -17,13 +17,13 @@ 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? @State var color: Color = .blue + @State var activity: Int = 1 var body: some View { VStack { @@ -87,7 +87,7 @@ struct RouteRecorder: View { Text("Recording route") .font(.title) Spacer() - Text("\(locationsHandler.count)") + Text("\(Image(systemName: "mappin.and.ellipse")) \(locationsHandler.count)") .foregroundColor(.red) .font(.title2) } @@ -146,6 +146,22 @@ struct RouteRecorder: View { GPSStatus(largeFont: .body, smallFont: .callout) } .listStyle(.plain) + if recording == nil { + HStack(alignment: .center) { + Spacer() + Image(systemName: "figure.hiking") + .symbolRenderingMode(.multicolor) + .font(.title3) + .foregroundColor(.accentColor) + Text("activity") + Picker(selection: $activity, label: Text("Activity")) { + ForEach(ActivityType.allCases) { r in + Text(r.description) + } + } + Spacer() + } + } HStack { Spacer() if !locationsHandler.isRecording && !locationsHandler.isRecordingPaused { @@ -210,17 +226,19 @@ struct RouteRecorder: View { if locationsHandler.isRecording || locationsHandler.isRecordingPaused { /// We are recording or paused, show finish button Button { + + if let rec = recording { + rec.enabled = true + rec.distance = locationsHandler.distanceTraveled + rec.elevationGain = locationsHandler.elevationGain + context.refresh(rec, mergeChanges:true) + } locationsHandler.isRecording = false locationsHandler.isRecordingPaused = false locationsHandler.distanceTraveled = 0.0 locationsHandler.elevationGain = 0.0 locationsHandler.locationsArray.removeAll() locationsHandler.recordingStarted = nil - if let rec = recording { - rec.enabled = true - context.refresh(rec, mergeChanges:true) - } - do { try context.save() print("💾 Saved a route finish") @@ -254,7 +272,7 @@ struct RouteRecorder: View { } } } - .presentationDetents([.fraction(0.30), .fraction(0.65)]) + .presentationDetents([.fraction(0.45), .fraction(0.65)]) .presentationDragIndicator(.hidden) .interactiveDismissDisabled(false) .onAppear { diff --git a/Meshtastic/Views/Settings/Routes.swift b/Meshtastic/Views/Settings/Routes.swift index 34e8225f..6f47c9ea 100644 --- a/Meshtastic/Views/Settings/Routes.swift +++ b/Meshtastic/Views/Settings/Routes.swift @@ -143,7 +143,8 @@ struct Routes: View { } } } - .badge(route.locations?.count ?? 0) + .badge(Text("\(Image(systemName: "mappin.and.ellipse")) \(route.locations?.count ?? 0)")) + .font(.headline) .swipeActions { Button(role: .destructive) { context.delete(route) @@ -167,35 +168,35 @@ struct Routes: View { return location.locationCoordinate ?? LocationHelper.DefaultLocation }) Form { - HStack { - Text("Name") - Spacer() - TextField( - "Name", - text: $name, - axis: .vertical - ) - .foregroundColor(Color.gray) - .onChange(of: name, perform: { _ in - let totalBytes = name.utf8.count - // Only mess with the value if it is too big - if totalBytes > 100 { - name = String(name.dropLast()) - } - }) + TextField( + "Name", + text: $name, + axis: .vertical + ) + .foregroundColor(Color.gray) + .onChange(of: name, perform: { _ in + let totalBytes = name.utf8.count + // Only mess with the value if it is too big + + if totalBytes > 100 { + name = String(name.dropLast()) + } + }) + + Toggle(isOn: $enabled) { + Label("enabled", systemImage: "point.topleft.filled.down.to.point.bottomright.curvepath") + Text("Show on the mesh map.") } - Toggle("Enabled", isOn: $enabled) - .toggleStyle(.switch) + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) ColorPicker("Color", selection: $color, supportsOpacity: false) - .padding(5) TextField( "Notes", text: $notes, axis: .vertical ) - .lineLimit(4...6) + .lineLimit(3...5) .foregroundColor(Color.gray) } .onAppear { diff --git a/de.lproj/Localizable.strings b/de.lproj/Localizable.strings index 8807fc05..74b5ecd2 100644 --- a/de.lproj/Localizable.strings +++ b/de.lproj/Localizable.strings @@ -7,6 +7,7 @@ */ "about"="Über"; "about.meshtastic"="Über Meshtastic"; +"activity"="Activity"; "admin"="admin"; "admin.log"="Admin Log"; "ago"="her"; @@ -112,6 +113,7 @@ "email.address"="Email Adresse"; "enabled"="Aktiviert"; "encrypted"="Verschlüsselt"; +"export"="Export"; "external.notification"="Externe Benachrichtigung"; "external.notification.config"="Einstellungen der externen Benachrichtigung"; "finish"="Finish"; diff --git a/en.lproj/Localizable.strings b/en.lproj/Localizable.strings index 98a7733f..600bba22 100644 --- a/en.lproj/Localizable.strings +++ b/en.lproj/Localizable.strings @@ -7,6 +7,7 @@ */ "about"="About"; "about.meshtastic"="About Meshtastic"; +"activity"="Activity"; "admin"="Admin"; "admin.log"="Admin Message Log"; "ago"="ago"; @@ -113,6 +114,7 @@ "email.address"="Email Address"; "enabled"="Enabled"; "encrypted"="Encrypted"; +"export"="Export"; "external.notification"="External Notification"; "external.notification.config"="External Notification Config"; "finish"="Finish"; @@ -288,6 +290,18 @@ "ringtone.config"="Ringtone Config"; "route.recorder"="Route Recorder"; "routes"="Routes"; +"routes.activitytype.walking"="Walking"; +"routes.activitytype.hiking"="Hiking"; +"routes.activitytype.biking"="Biking"; +"routes.activitytype.driving"="Driving"; +"routes.activitytype.overlanding"="Overlanding"; +"routes.activitytype.skiing"="Skiing"; +"routes.activitytype.filename.walking"="walk"; +"routes.activitytype.filename.hiking"="hike"; +"routes.activitytype.filename.biking"="bike tour"; +"routes.activitytype.filename.driving"="drive"; +"routes.activitytype.filename.overlanding"="overland drive"; +"routes.activitytype.filename.skiing"="ski tour"; "routing.acknowledged"="Acknowledged"; "routing.noroute"="No Route"; "routing.gotnak"="Received a negative acknowledgment"; diff --git a/fr.lproj/Localizable.strings b/fr.lproj/Localizable.strings index ee20ea01..c745da8f 100644 --- a/fr.lproj/Localizable.strings +++ b/fr.lproj/Localizable.strings @@ -7,6 +7,7 @@ */ "about"="À propos"; "about.meshtastic"="À propos de Meshtastic"; +"activity"="Activity"; "admin"="Administrateur"; "admin.log"="Journal des messages d'administration"; "ago"="auparavant"; @@ -90,6 +91,7 @@ "email.address"="Adresse mail"; "enabled"="Activé"; "encrypted"="Encrypté"; +"export"="Export"; "external.notification"="Notification extérieure"; "external.notification.config"="Configuration de la notification extérieure"; "finish"="Terminer"; diff --git a/he.lproj/Localizable.strings b/he.lproj/Localizable.strings index ab80c974..c0aee4fd 100644 --- a/he.lproj/Localizable.strings +++ b/he.lproj/Localizable.strings @@ -7,6 +7,7 @@ */ "about"="אודות"; "about.meshtastic"="אודות משטסטיק"; +"activity"="Activity"; "admin"="אדמין"; "admin.log"="היסטוריית הודעות אדמין"; "ago"="עברו"; @@ -113,6 +114,7 @@ "email.address"="כתובת דואר אלקטרוני"; "enabled"="מופעל"; "encrypted"="מוצפן"; +"export"="Export"; "external.notification"="נוטיפיקציה חיצונית"; "external.notification.config"="הגדרות נוטיפיקציה חיצונית"; "finish"="סיים"; diff --git a/pl.lproj/Localizable.strings b/pl.lproj/Localizable.strings index 6a6e1df5..08fb636e 100644 --- a/pl.lproj/Localizable.strings +++ b/pl.lproj/Localizable.strings @@ -9,6 +9,7 @@ */ "about"="O programie"; "about.meshtastic"="O Meshtastic"; +"activity"="Activity"; "admin"="Administrator"; "admin.log"="Log administratora"; "ago"="temu"; @@ -114,6 +115,7 @@ "email.address"="Adres Email"; "enabled"="Włączony"; "encrypted"="Zaszyfrowany"; +"export"="Export"; "external.notification"="Zewnętrzne Powiadomienie"; "external.notification.config"="Konfiguracja Zewnętrznego Powiadomienia"; "finish"="Finish"; diff --git a/se.lproj/Localizable.strings b/se.lproj/Localizable.strings index 4fffdbfc..aba94b74 100644 --- a/se.lproj/Localizable.strings +++ b/se.lproj/Localizable.strings @@ -7,6 +7,7 @@ */ "about"="Om"; "about.meshtastic"="Om Meshtastic"; +"activity"="Activity"; "admin"="Administratör"; "admin.log"="Administratörsmeddelandelogg"; "ago"="sedan"; @@ -113,6 +114,7 @@ "email.address"="E-postadress"; "enabled"="Aktiverad"; "encrypted"="Krypterad"; +"export"="Export"; "external.notification"="Extern Notifikation"; "external.notification.config"="Konfiguration av Extern Notifikation"; "finish"="Avsluta"; diff --git a/zh-Hans.lproj/Localizable.strings b/zh-Hans.lproj/Localizable.strings index 935c3985..4779190c 100644 --- a/zh-Hans.lproj/Localizable.strings +++ b/zh-Hans.lproj/Localizable.strings @@ -7,6 +7,7 @@ */ "about"="关于"; "about.meshtastic"="关于 Meshtastic"; +"activity"="Activity"; "admin"="管理员"; "admin.log"="管理员消息日志"; "ago"="ago"; @@ -112,6 +113,7 @@ "email.address"="邮件地址"; "enabled"="启用"; "encrypted"="加密"; +"export"="Export"; "external.notification"="外部通知"; "external.notification.config"="外部通知配置"; "finish"="Finish"; diff --git a/zh-Hant-TW.lproj/Localizable.strings b/zh-Hant-TW.lproj/Localizable.strings index f3f007c2..18545ef6 100644 --- a/zh-Hant-TW.lproj/Localizable.strings +++ b/zh-Hant-TW.lproj/Localizable.strings @@ -7,6 +7,7 @@ */ "about"="關於"; "about.meshtastic"="關於 Meshtastic"; +"activity"="Activity"; "admin"="管理員"; "admin.log"="管理員消息紀錄檔"; "ago"="ago"; @@ -111,6 +112,7 @@ "email.address"="電子信箱"; "enabled"="啟用"; "encrypted"="加密"; +"export"="Export"; "external.notification"="外部通知"; "external.notification.config"="外部通知設定"; "finish"="完成";