Finishing adding activity type to the route recorder

This commit is contained in:
Garth Vander Houwen 2024-04-15 07:28:23 -07:00
parent 0f26c3c8eb
commit 70d89c093b
13 changed files with 136 additions and 29 deletions

View file

@ -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 = "<group>"; };
DD2553582855B52700E55709 /* PositionConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionConfig.swift; sourceTree = "<group>"; };
DD268D8C2BCC7D11008073AE /* MeshtasticDataModelV 35.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 35.xcdatamodel"; sourceTree = "<group>"; };
DD268D8D2BCC90E2008073AE /* RouteEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteEnums.swift; sourceTree = "<group>"; };
DD295CE92B323ED9002CC4AC /* MeshtasticDataModelV22.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV22.xcdatamodel; sourceTree = "<group>"; };
DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewSwiftUI.swift; sourceTree = "<group>"; };
DD2CC2E52ABFE04E00EDFDA7 /* MeshtasticDataModelV19.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV19.xcdatamodel; sourceTree = "<group>"; };
@ -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 */,

View file

@ -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
}
}
}

View file

@ -328,7 +328,10 @@
<entity name="RouteEntity" representedClassName="RouteEntity" syncable="YES" codeGenerationType="class">
<attribute name="color" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="distance" optional="YES" attributeType="Double" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="elevationGain" optional="YES" attributeType="Double" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="endDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="notes" optional="YES" attributeType="String"/>

View file

@ -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 {

View file

@ -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 {

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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"="סיים";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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"="完成";