Skip to content

Commit 8c94052

Browse files
committed
Update fitness details and improve strings
1 parent 4794b6f commit 8c94052

10 files changed

Lines changed: 162 additions & 130 deletions

File tree

InfiniLink/BLE/BLECharacteristicHandler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ struct BLECharacteristicHandler {
1818
let notificationManager = NotificationManager.shared
1919
let remindersManager = RemindersManager.shared
2020
let deviceManager = DeviceManager.shared
21-
let fitnessCalculator = FitnessCalculator.shared
2221
let persistenceController = PersistenceController.shared
22+
let fitnessCalculator = FitnessCalculator()
2323

2424
@AppStorage("filterHeartRateData") var filterHeartRateData: Bool = false
2525
@AppStorage("remindOnStepGoalCompletion") var remindOnStepGoalCompletion = true

InfiniLink/BLE/BLEManager.swift

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -187,36 +187,32 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
187187
}
188188

189189
func removeDevice(device: Device? = nil) {
190-
Task {
191-
await deviceManager.removeDevice(device ?? pairedDevice)
192-
unpair(device: device)
193-
}
190+
deviceManager.removeDevice(device ?? pairedDevice)
191+
unpair(device: device)
194192
}
195193

196194
func unpair(device: Device? = nil) {
197-
Task {
198-
if let pairedDevice {
199-
// Delete the device object we have said for this watch
200-
await deviceManager.removeDevice(device ?? pairedDevice)
201-
}
202-
// Update the list of user watches
203-
deviceManager.fetchAllDevices()
204-
205-
if let first = deviceManager.watches.first, deviceManager.watches.count <= 1 {
206-
// Switch to the user's next watch
207-
pairedDeviceID = first.uuid
208-
} else {
209-
// The user doesn't have another watch, this will show the welcome view
210-
pairedDeviceID = nil
211-
}
212-
213-
log("Unpaired from \(pairedDevice?.name ?? "InfiniTime")", type: .info, caller: "BLEManager", target: .ble)
214-
215-
if device == nil {
216-
// FIXME: this only disconnects and removes the watch from the recognized device list in the app. If using secure pairing, iOS will still keep the bond
217-
disconnect()
218-
startScanning()
219-
}
195+
if let pairedDevice {
196+
// Delete the device object we have said for this watch
197+
deviceManager.removeDevice(device ?? pairedDevice)
198+
}
199+
// Update the list of user watches
200+
deviceManager.fetchAllDevices()
201+
202+
if let first = deviceManager.watches.first, deviceManager.watches.count <= 1 {
203+
// Switch to the user's next watch
204+
pairedDeviceID = first.uuid
205+
} else {
206+
// The user doesn't have another watch, this will show the welcome view
207+
pairedDeviceID = nil
208+
}
209+
210+
log("Unpaired from \(pairedDevice?.name ?? "InfiniTime")", type: .info, caller: "BLEManager", target: .ble)
211+
212+
if device == nil {
213+
// FIXME: this only disconnects and removes the watch from the recognized device list in the app. If using secure pairing, iOS will still keep the bond
214+
disconnect()
215+
startScanning()
220216
}
221217
}
222218

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

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,45 +28,37 @@ struct StepCalendarView: View {
2828
Section {
2929
VStack(spacing: 16) {
3030
HStack {
31-
ForEach(weekdays, id: \.self) { day in
31+
ForEach(Array(weekdays.enumerated()), id: \.0) { index, day in
3232
Text(day)
3333
.font(.system(size: 14).weight(.bold))
3434
.foregroundStyle(Color.primary.opacity(0.5))
3535
.frame(maxWidth: .infinity)
3636
}
3737
}
38-
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: weekdays.count), spacing: 12) {
38+
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: weekdays.count), spacing: 14) {
3939
ForEach(fetchDates(), id: \.id) { value in
4040
ZStack {
4141
Circle()
42-
.stroke(Color.gray.opacity(0.3), style: value.day == -1 ? StrokeStyle(lineWidth: 1.5, lineCap: .round, dash: [7]) : StrokeStyle(lineWidth: 2))
42+
.stroke(Color.gray.opacity(0.8), style: value.day == -1 ? StrokeStyle(lineWidth: 2.5, lineCap: .round, dash: [7]) : StrokeStyle(lineWidth: 0))
43+
.background(value.day == -1 ? AnyShapeStyle(Color.clear) : background)
44+
.clipShape(Circle())
4345
let label = Text("\(value.day)")
4446
.font(.system(size: 16).weight(.medium))
4547
.opacity(value.day == -1 ? 0 : 1)
46-
if deviceManager.settings.stepsGoal > 0 {
47-
// TODO: change to FetchRequest?
48+
if deviceManager.settings.stepsGoal > 0 && value.day != -1 {
4849
let progress = min(Double(chartManager.stepPoints().first(where: { Calendar.current.isDate(value.date, equalTo: $0.timestamp!, toGranularity: .day)})?.steps ?? 0) / Double(deviceManager.settings.stepsGoal), 1)
4950
PieSlice(progress: progress)
50-
.fill(Color.blue.opacity(0.7))
51-
.overlay {
52-
Circle()
53-
.trim(from: 0, to: CGFloat(progress))
54-
.stroke(Color.blue, lineWidth: 3)
55-
.rotationEffect(Angle(degrees: -90))
56-
}
51+
.fill(Color.blue.opacity(0.8))
5752
label
5853
.foregroundStyle(progress > 0.5 ? Color.white : Color.primary)
5954
} else {
6055
label
6156
}
6257
}
63-
.frame(minWidth: 38, maxWidth: 50, minHeight: 38, maxHeight: 50)
58+
.frame(minWidth: 42, maxWidth: 55, minHeight: 42, maxHeight: 55)
6459
}
6560
}
6661
}
67-
.padding()
68-
.background(background)
69-
.clipShape(RoundedRectangle(cornerRadius: 10))
7062
} header: {
7163
VStack(alignment: .leading, spacing: 7) {
7264
Text("Monthly Overview")
@@ -134,7 +126,7 @@ struct PieSlice: Shape {
134126
var path = Path()
135127
let center = CGPoint(x: rect.midX, y: rect.midY)
136128
let radius = min(rect.width, rect.height) / 2
137-
let startAngle = Angle(degrees: -90) // Start from top
129+
let startAngle = Angle(degrees: -90) // Start from the top
138130
let endAngle = Angle(degrees: -90 + (progress * 360))
139131

140132
path.move(to: center)

InfiniLink/Core/Developer/DeveloperView.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@ struct DeveloperView: View {
7373
bleWriteManager.writeToMusicApp(message: "Song Name", characteristic: trackChar)
7474
}
7575
}
76-
}
77-
Section {
7876
Toggle("Include Song Name", isOn: $includeTestSongName)
7977
Toggle("Include Artist", isOn: $includeTestArtist)
8078
} footer: {

InfiniLink/Core/Exercise/Views/ExerciseDetailView.swift

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,12 @@ struct ExerciseDetailView: View {
3636
let minutes = (totalSeconds % 3600) / 60
3737
let seconds = totalSeconds % 60
3838

39-
print(difference)
4039
if hours > 0 {
41-
return "\(hours) hr \(minutes) min"
40+
return "\(hours) hour\(hours == 1 ? "" : "s") and \(minutes) minute\(minutes == 1 ? "" : "s")"
4241
} else if minutes > 0 {
43-
return "\(minutes) min \(seconds) sec"
42+
return "\(minutes) minute\(minutes == 1 ? "" : "s") and \(seconds) second\(seconds == 1 ? "" : "s")"
4443
} else {
45-
return "\(seconds) sec"
44+
return "\(seconds) second\(seconds == 1 ? "" : "s")"
4645
}
4746
}
4847

@@ -63,42 +62,28 @@ struct ExerciseDetailView: View {
6362
.frame(maxWidth: .infinity)
6463
}
6564
.listRowBackground(Color.clear)
66-
Section {
67-
HStack {
68-
Text("Duration")
69-
Text(timeDifferenceFormatted(startDate: userExercise.startDate!, endDate: userExercise.endDate!))
70-
.foregroundStyle(.gray)
71-
}
72-
HStack {
73-
Text("Start Date")
74-
Text(userExercise.startDate!.formatted())
75-
.foregroundStyle(.gray)
76-
}
77-
HStack {
78-
Text("End Date")
79-
Text(userExercise.endDate!.formatted())
80-
.foregroundStyle(.gray)
81-
}
65+
Section("Time") {
66+
let startDate = userExercise.startDate!
67+
68+
Text("Starting on \(startDate.formatted(.dateTime.day().month())) at \(startDate.formatted(.dateTime.hour().minute())), the exercise lasted \(timeDifferenceFormatted(startDate: startDate, endDate: userExercise.endDate!)).")
69+
}
70+
Section("Heart Rate") {
71+
let heartValues = heartPoints.compactMap({ $0.value })
72+
let min = Int(heartValues.min() ?? 0)
73+
let max = Int(heartValues.max() ?? 0)
74+
8275
if heartPoints.count > 1 {
83-
HStack {
84-
Text("Heart Rate")
85-
Text("\(Int(heartPoints.compactMap({ $0.value }).min() ?? 0)) - \(Int(heartPoints.compactMap({ $0.value }).max() ?? 0))")
86-
.foregroundStyle(.gray)
87-
}
88-
}
89-
if exercise().components.contains(.steps) {
90-
HStack {
91-
Text("Total Steps")
92-
Text(String(userExercise.steps))
93-
.foregroundStyle(.gray)
94-
}
76+
Text("Averaging at \(String(format: "%.0f", Double(heartValues.reduce(0, +)) / Double(heartValues.count))) BPM, your heart rate ranged from \(min) to \(max) BPM.")
77+
} else {
78+
Text("There wasn't any heart rate data recorded for this exercise.")
9579
}
9680
}
97-
if heartPoints.count > 1 {
98-
Section("Heart Rate") {
99-
HeartChartView(showHeader: false)
81+
if exercise().components.contains(.steps) {
82+
Section("Steps") {
83+
let calories = FitnessCalculator().calculateCaloriesBurned(steps: Int(userExercise.steps))
84+
85+
Text("You took \(userExercise.steps) step\(userExercise.steps == 1 ? "" : "s") and burned \(calories > 1 ? String(format: "%.0f", calories) + "calories": "less than one calorie").")
10086
}
101-
.listRowBackground(Color.clear)
10287
}
10388
}
10489
}

InfiniLink/Core/Settings/General/About/AboutSettingsView.swift

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,17 @@ struct AboutSettingsView: View {
3030
AboutRowView("Model Name", value: deviceManager.modelNumber)
3131
AboutRowView("UUID", value: deviceManager.bleUUID)
3232
}
33-
if let timeService = bleManager.currentTimeService{
34-
Section {
35-
Button("Update Device Time") {
36-
BLEWriteManager().setTime(characteristic: timeService)
37-
}
38-
}
39-
}
4033
Section {
4134
AboutRowView("File System", value: deviceManager.blefsVersion)
4235
AboutRowView("Hardware Revision", value: deviceManager.hardwareRevision)
4336
AboutRowView("Settings Version", value: String(deviceManager.settings.version))
4437
}
38+
Section {
39+
Button("Update Device Time") {
40+
BLEWriteManager().setTime(characteristic: bleManager.currentTimeService)
41+
}
42+
.disabled(bleManager.currentTimeService == nil)
43+
}
4544
Section {
4645
Button("About InfiniLink") {
4746
showAppInfoView = true

InfiniLink/Core/Welcome/SetUpDetailsView.swift

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,18 @@ struct SetUpDetailsView: View {
6767
height = ""
6868
}
6969
}
70+
Section {
71+
Picker("Gender", selection: $personalizationController.gender) {
72+
Text("Male").tag(PersonalizationController.Gender.male)
73+
Text("Female").tag(PersonalizationController.Gender.female)
74+
}
75+
}
7076
Section {
7177
HStack(spacing: 12) {
7278
Text("Weight")
7379
TextField("Optional", text: $weight)
7480
.focused($isWeightFocused)
7581
.keyboardType(.decimalPad)
76-
.onSubmit {
77-
// TODO: process
78-
personalizationController.weight = Double(weight)
79-
}
8082
// TODO: do not allow text input
8183
}
8284
.onTapGesture {
@@ -91,10 +93,6 @@ struct SetUpDetailsView: View {
9193
TextField("Optional", text: $height)
9294
.focused($isHeightFocused)
9395
.keyboardType(.decimalPad)
94-
.onSubmit {
95-
// TODO: process
96-
personalizationController.height = Double(height)
97-
}
9896
// TODO: do not allow text input
9997
}
10098
.onTapGesture {
@@ -110,7 +108,7 @@ struct SetUpDetailsView: View {
110108
// Go to next view
111109
nextViewActive = true
112110

113-
// TODO: process
111+
// Is this handled by the onDisappear?
114112
personalizationController.height = Double(height)
115113
personalizationController.weight = Double(weight)
116114
} label: {
@@ -136,11 +134,16 @@ struct SetUpDetailsView: View {
136134
}
137135
}
138136
.onAppear {
139-
if let weight = personalizationController.weight {
140-
self.weight = String(weight)
141-
}
142-
if let height = personalizationController.height {
143-
self.height = String(height)
137+
self.weight = String(personalizationController.calculatedWeight)
138+
self.height = String(personalizationController.calculatedHeight)
139+
}
140+
.onDisappear {
141+
if personalizationController.units == .imperial {
142+
personalizationController.height = (Double(height) ?? 0) * 2.54
143+
personalizationController.weight = (Double(weight) ?? 0) / 2.205
144+
} else {
145+
personalizationController.height = Double(height)
146+
personalizationController.weight = Double(weight)
144147
}
145148
}
146149
}

0 commit comments

Comments
 (0)