Skip to content

Commit bb59169

Browse files
committed
Add DFU log tab, begin work on directions, improve performance, fix bugs
1 parent daa8ed4 commit bb59169

21 files changed

Lines changed: 379 additions & 70 deletions

InfiniLink.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
E0599A112CB5553B00D64E0B /* FSFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0599A102CB5553B00D64E0B /* FSFile.swift */; };
5050
E05D2E722D7E8801004A6CE0 /* EmptyChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E05D2E712D7E8801004A6CE0 /* EmptyChartView.swift */; };
5151
E05D2E752D7EA95B004A6CE0 /* ChartType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E05D2E742D7EA95B004A6CE0 /* ChartType.swift */; };
52+
E05D2E772D8093D7004A6CE0 /* DirectionsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E05D2E762D8093D7004A6CE0 /* DirectionsManager.swift */; };
5253
E05DA4C12D13752C00A49203 /* DebugLogManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E05DA4C02D13752C00A49203 /* DebugLogManager.swift */; };
5354
E064D40A2D77F32F008500AE /* CalendarDay.swift in Sources */ = {isa = PBXBuildFile; fileRef = E064D4092D77F32F008500AE /* CalendarDay.swift */; };
5455
E078ECFB2D4E6D9800560364 /* Zip in Frameworks */ = {isa = PBXBuildFile; productRef = E078ECFA2D4E6D9800560364 /* Zip */; };
@@ -177,6 +178,7 @@
177178
E0599A102CB5553B00D64E0B /* FSFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FSFile.swift; sourceTree = "<group>"; };
178179
E05D2E712D7E8801004A6CE0 /* EmptyChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyChartView.swift; sourceTree = "<group>"; };
179180
E05D2E742D7EA95B004A6CE0 /* ChartType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartType.swift; sourceTree = "<group>"; };
181+
E05D2E762D8093D7004A6CE0 /* DirectionsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectionsManager.swift; sourceTree = "<group>"; };
180182
E05DA4C02D13752C00A49203 /* DebugLogManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugLogManager.swift; sourceTree = "<group>"; };
181183
E064D4092D77F32F008500AE /* CalendarDay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarDay.swift; sourceTree = "<group>"; };
182184
E06973AA2B35E6F4009C2F7D /* InfiniLink.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = InfiniLink.entitlements; sourceTree = "<group>"; };
@@ -509,6 +511,7 @@
509511
E08F2F342CC89A530094217A /* MapSearch.swift */,
510512
E0E772AE2CCD552100D60C24 /* NumbersOnly.swift */,
511513
E05DA4C02D13752C00A49203 /* DebugLogManager.swift */,
514+
E05D2E762D8093D7004A6CE0 /* DirectionsManager.swift */,
512515
);
513516
path = Utils;
514517
sourceTree = "<group>";
@@ -833,6 +836,7 @@
833836
E0A7C07A2CB1AAAC0042A12D /* BatterySettingsView.swift in Sources */,
834837
E07D8F162CBE1F6F005C1325 /* RemindersManager.swift in Sources */,
835838
E08F2F332CC899E30094217A /* SetWeatherLocationView.swift in Sources */,
839+
E05D2E772D8093D7004A6CE0 /* DirectionsManager.swift in Sources */,
836840
E07D8F182CBE2071005C1325 /* ActionView.swift in Sources */,
837841
E09696E32D2F807700CCCBF8 /* HeartChartView.swift in Sources */,
838842
E0B85D5E2CB628E200D85122 /* ExerciseDetailView.swift in Sources */,

InfiniLink/BLE/BLECharacteristicHandler.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,10 @@ struct BLECharacteristicHandler {
211211
SleepController.shared.sleep = SleepData(startDate: timestamp, endDate: timestamp.addingTimeInterval(Double(minutesAsleep * 60)))
212212
case bleManager.cbuuidList.dfuPacket:
213213
guard let data = characteristic.value else { break }
214-
log("Response from DFU Packet characteristic: \(String(decoding: data, as: UTF8.self))")
214+
log("Packet char: \(String(decoding: data, as: UTF8.self))", target: .dfu)
215215
case bleManager.cbuuidList.dfuControlPoint:
216216
guard let data = characteristic.value else { break }
217-
log("Response from DFU Control Point: \(String(decoding: data, as: UTF8.self))")
217+
log("Control point: \(String(decoding: data, as: UTF8.self))", target: .dfu)
218218
default:
219219
break
220220
}

InfiniLink/BLE/BLEWriteManager.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,16 @@ struct BLEWriteManager {
136136
}
137137
}
138138

139-
func writeNavigationUpdate() {
139+
func writeNavigationUpdate(icon: String, instructions: String, distance: String, progress: UInt8) {
140140
guard bleManager.infiniTime != nil else { return }
141141
guard bleManager.navigationFlagsCharacteristic != nil && bleManager.navigationNarrativeCharacteristic != nil && bleManager.navigationDistanceCharacteristic != nil && bleManager.navigationProgressCharacteristic != nil && bleManager.infiniTime != nil else { return }
142142

143-
guard let icon = "fork".data(using: .ascii) else { return }
144-
guard let narrative = "At the roundabout take the first exit".data(using: .ascii) else { return }
145-
guard let distance = "20ft".data(using: .ascii) else { return }
143+
guard let icon = icon.data(using: .ascii) else { return }
144+
guard let narrative = instructions.data(using: .ascii) else { return }
145+
guard let distance = distance.data(using: .ascii) else { return }
146146

147147
var progress = Data()
148-
progress.append(UInt8(23))
148+
progress.append(progress)
149149

150150
bleManager.infiniTime.writeValue(narrative, for: bleManager.navigationNarrativeCharacteristic, type: .withResponse)
151151
bleManager.infiniTime.writeValue(distance, for: bleManager.navigationDistanceCharacteristic, type: .withResponse)

InfiniLink/Core/Components/Charts/Heart/HeartChartView.swift

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,35 @@ struct HeartChartView: View {
1919

2020
@AppStorage("heartRateChartDataSelection") private var dataSelection = 0
2121

22-
func heartPoints() -> [HeartChartDataPoint] {
23-
let now = Date()
22+
func heartPoints(currentDay: Bool = false) -> [HeartChartDataPoint] {
2423
let calendar = Calendar.current
24+
let now = Date()
2525

2626
let points = chartManager.heartPoints().map { point in
27-
let timestamp = point.timestamp ?? Date() // Should we catch this date?
27+
let timestamp = point.timestamp ?? now // Should we catch this date?
2828
let dataPoint = HeartChartDataPoint(date: timestamp, value: point.value)
2929

3030
return dataPoint
3131
}
32-
return points.filter { point in
32+
let granularity: Calendar.Component = {
33+
if currentDay {
34+
return .day
35+
}
36+
3337
switch dataSelection {
3438
case 1:
35-
if calendar.isDate(point.date, equalTo: now, toGranularity: .day) {
36-
return true
37-
}
39+
return .day
3840
case 2:
39-
if calendar.isDate(point.date, equalTo: now, toGranularity: .weekOfYear) {
40-
return true
41-
}
41+
return .weekOfYear
4242
case 3:
43-
if calendar.isDate(point.date, equalTo: now, toGranularity: .month) {
44-
return true
45-
}
43+
return .month
4644
default:
47-
if calendar.isDate(point.date, equalTo: now, toGranularity: .hour) {
48-
return true
49-
}
45+
return .hour
5046
}
51-
52-
return false
47+
}()
48+
49+
return points.filter { point in
50+
return calendar.isDate(point.date, equalTo: now, toGranularity: granularity)
5351
}
5452
}
5553
var earliestDate: Date {
@@ -120,9 +118,11 @@ struct HeartChartView: View {
120118
}
121119
}
122120
.listRowBackground(Color.clear)
123-
Section {
124-
Text("Today your heart rate reached a high of \(max), and dropped to a low of \(min) BPM.")
125-
// Text("Is a heart point in an exercise in the last day: \(ExerciseViewModel.shared.isDateDuringExercise(Date()))")
121+
if heartPoints(currentDay: true).count >= 3 {
122+
Section {
123+
Text("Today your heart rate reached a high of \(max), and dropped to a low of \(min) BPM.")
124+
// Text("Is a heart point in an exercise in the last day: \(ExerciseViewModel.shared.isDateDuringExercise(Date()))")
125+
}
126126
}
127127
}
128128
}

InfiniLink/Core/Components/Charts/Steps/StepChartView.swift

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,9 @@ struct StepChartView: View {
5959
}
6060

6161
var streak: Int {
62-
var streak = 0
63-
64-
// Add limit to week or month to avoid iterating through thousands of points?
65-
for point in chartManager.stepPoints().reversed().prefix(7) {
66-
if point.steps >= deviceManager.settings.stepsGoal {
67-
streak += 1
68-
} else {
69-
break
70-
}
71-
}
72-
73-
return streak
62+
return chartManager.stepPoints().reversed().prefix(7).filter({
63+
return $0.steps >= deviceManager.settings.stepsGoal
64+
}).count
7465
}
7566
var earliestDate: Date {
7667
stepChartPoints().compactMap({ $0.date }).min() ?? Date()

InfiniLink/Core/Developer/DebugLogsView.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,21 @@ struct DebugLogsView: View {
1414

1515
var body: some View {
1616
TabView(selection: $logSelection) {
17+
logs(for: .app)
18+
.tabItem {
19+
Label("App", systemImage: "doc")
20+
}
21+
.tag("app")
1722
logs(for: .ble)
1823
.tabItem {
1924
Label("BLE", systemImage: "radiowaves.right")
2025
}
2126
.tag("ble")
22-
logs(for: .app)
27+
logs(for: .dfu)
2328
.tabItem {
24-
Label("App", systemImage: "doc")
29+
Label("DFU", systemImage: "arrow.up.doc")
2530
}
26-
.tag("app")
31+
.tag("dfu")
2732
}
2833
.navigationTitle("\(logSelection == "ble" ? "BLE" : NSLocalizedString("App", comment: "")) Logs")
2934
}

InfiniLink/Core/Developer/DeveloperView.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ struct DeveloperView: View {
5454
bleWriteManager.writeCurrentWeatherData(currentTemperature: Double.random(in: -2...50), minimumTemperature: Double.random(in: -2...50), maximumTemperature: Double.random(in: -2...50), location: "Location", icon: UInt8.random(in: 0...8))
5555
}
5656
Button("Test Navigation") {
57-
bleWriteManager.writeNavigationUpdate()
57+
bleWriteManager.writeNavigationUpdate(
58+
icon: "turn-right",
59+
instructions: "The destination is on your right",
60+
distance: "112 ft",
61+
progress: 98
62+
)
5863
}
5964
}
6065
Section {

InfiniLink/Core/DeviceView.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,12 @@ struct DeviceView: View {
182182
} label: {
183183
ListRowView(title: "Notifications", icon: "bell.badge.fill", iconColor: .red)
184184
}
185-
NavigationLink {
186-
DirectionsView()
187-
} label: {
188-
ListRowView(title: "Navigation", icon: "map.fill", iconColor: .blue)
185+
if #available(iOS 17, *) {
186+
NavigationLink {
187+
DirectionsView()
188+
} label: {
189+
ListRowView(title: "Navigation", icon: "map.fill", iconColor: .blue)
190+
}
189191
}
190192
NavigationLink {
191193
WeatherView()

InfiniLink/Core/DirectionsView.swift

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,116 @@
66
//
77

88
import SwiftUI
9+
import MapKit
910

1011
struct DirectionsView: View {
12+
@StateObject private var directionsManager = DirectionsManager.shared
13+
@ObservedObject private var locationManager = LocationManager.shared
14+
@ObservedObject private var mapSearch = MapSearch()
15+
16+
@FocusState private var isSearching: Bool
17+
// TODO: check
18+
@State private var region = MKCoordinateRegion(
19+
center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194),
20+
span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
21+
)
22+
1123
var body: some View {
12-
List {
13-
24+
VStack {
25+
if locationManager.canGetUserLocation() {
26+
VStack {
27+
if directionsManager.isLoading || mapSearch.isLoading {
28+
ProgressView("Loading...")
29+
} else {
30+
List {
31+
Section {
32+
ForEach(mapSearch.locationResults, id: \.description) { location in
33+
Button {
34+
directionsManager.cancelRoute()
35+
locationManager.getCoordinateFrom(address: "\(location.title), \(location.subtitle)") { coordinate, error in
36+
if let coordinate {
37+
directionsManager.getDirections(to: coordinate)
38+
mapSearch.locationResults = []
39+
} else if let error {
40+
print("Error getting coordinate: \(error.localizedDescription)")
41+
}
42+
}
43+
} label: {
44+
VStack(alignment: .leading, spacing: 4) {
45+
Text(location.title)
46+
.foregroundStyle(Color.primary)
47+
.fontWeight(.semibold)
48+
if !location.subtitle.isEmpty {
49+
Text(location.subtitle)
50+
.foregroundStyle(.gray)
51+
}
52+
}
53+
}
54+
}
55+
}
56+
directions
57+
mapView
58+
}
59+
}
60+
}
61+
.searchable(text: $mapSearch.searchTerm)
62+
} else {
63+
Text("To start a route, you need to enable \"Always Allow\" location permissions for InfiniLink in Settings.")
64+
}
65+
}
66+
.navigationTitle("Directions")
67+
.onChange(of: locationManager.location) { location in
68+
if let location {
69+
directionsManager.updateLocation(location)
70+
region.center = location.coordinate
71+
}
72+
}
73+
}
74+
75+
var directions: some View {
76+
Group {
77+
if !directionsManager.steps.isEmpty {
78+
Section {
79+
VStack {
80+
let instructions = directionsManager.steps[directionsManager.currentStepIndex].instructions
81+
if !instructions.isEmpty {
82+
Text(instructions)
83+
.font(.title2.weight(.bold))
84+
Text("In \(directionsManager.distanceToNextStep) meters")
85+
} else {
86+
ProgressView()
87+
}
88+
}
89+
.frame(maxWidth: .infinity)
90+
.padding()
91+
}
92+
}
93+
Section {
94+
ForEach(directionsManager.steps, id: \.instructions) { step in
95+
VStack(alignment: .leading, spacing: 4) {
96+
Text(step.instructions)
97+
.foregroundStyle(Color.primary)
98+
.fontWeight(.semibold)
99+
Text(directionsManager.convertedDistance(step.distance))
100+
.foregroundStyle(.gray)
101+
}
102+
}
103+
}
14104
}
15-
.navigationTitle("Navigation")
105+
}
106+
107+
var mapView: some View {
108+
Section {
109+
Map(coordinateRegion: $region, showsUserLocation: true, userTrackingMode: .constant(.follow))
110+
.frame(height: 400)
111+
}
112+
.listRowInsets(EdgeInsets())
16113
}
17114
}
18115

19116
#Preview {
20-
DirectionsView()
117+
NavigationStack {
118+
DirectionsView()
119+
.navigationBarTitleDisplayMode(.inline)
120+
}
21121
}

InfiniLink/Core/Settings/Notifications/NotificationsSettingsView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ struct NotificationsSettingsView: View {
1515
@AppStorage("waterReminder") var waterReminder = true
1616
@AppStorage("waterReminderAmount") var waterReminderAmount = 7
1717
@AppStorage("standUpReminder") var standUpReminder = true
18-
@AppStorage("heartRangeReminder") var heartRangeReminder = true
18+
@AppStorage("heartRangeReminder") var heartRangeReminder = false
1919
@AppStorage("minHeartRange") var minHeartRange = 40
20-
@AppStorage("maxHeartRange") var maxHeartRange = 150
20+
@AppStorage("maxHeartRange") var maxHeartRange = 200
2121
@AppStorage("watchNotifications") var watchNotifications = true
2222
@AppStorage("enableReminders") var enableReminders = true
2323
@AppStorage("enableCalendarNotifications") var enableCalendarNotifications = true

0 commit comments

Comments
 (0)