Showing 3 changed files with 220 additions and 268 deletions
+0 -3
USB Meter.xcodeproj/project.pbxproj
@@ -20,7 +20,6 @@
20 20
 		43554B32244449B5004E66F5 /* MeasurementPointView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43554B31244449B5004E66F5 /* MeasurementPointView.swift */; };
21 21
 		43554B3424444B0E004E66F5 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43554B3324444B0E004E66F5 /* Date.swift */; };
22 22
 		4360A34D241CBB3800B464F9 /* RSSIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4360A34C241CBB3800B464F9 /* RSSIView.swift */; };
23
-		4360A34F241D5CF100B464F9 /* MeterSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4360A34E241D5CF100B464F9 /* MeterSettingsView.swift */; };
24 23
 		437D47D12415F91B00B7768E /* LiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437D47D02415F91B00B7768E /* LiveView.swift */; };
25 24
 		437D47D32415FB7E00B7768E /* Decimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437D47D22415FB7E00B7768E /* Decimal.swift */; };
26 25
 		437D47D52415FD8C00B7768E /* RecordingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437D47D42415FD8C00B7768E /* RecordingView.swift */; };
@@ -98,7 +97,6 @@
98 97
 		43554B31244449B5004E66F5 /* MeasurementPointView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementPointView.swift; sourceTree = "<group>"; };
99 98
 		43554B3324444B0E004E66F5 /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = "<group>"; };
100 99
 		4360A34C241CBB3800B464F9 /* RSSIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSSIView.swift; sourceTree = "<group>"; };
101
-		4360A34E241D5CF100B464F9 /* MeterSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeterSettingsView.swift; sourceTree = "<group>"; };
102 100
 		437D47D02415F91B00B7768E /* LiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveView.swift; sourceTree = "<group>"; };
103 101
 		437D47D22415FB7E00B7768E /* Decimal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decimal.swift; sourceTree = "<group>"; };
104 102
 		437D47D42415FD8C00B7768E /* RecordingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingView.swift; sourceTree = "<group>"; };
@@ -279,7 +277,6 @@
279 277
 			isa = PBXGroup;
280 278
 			children = (
281 279
 				4383B469240FE4A600DAAEBF /* MeterView.swift */,
282
-				4360A34E241D5CF100B464F9 /* MeterSettingsView.swift */,
283 280
 				437D47D02415F91B00B7768E /* LiveView.swift */,
284 281
 				437D47D42415FD8C00B7768E /* RecordingView.swift */,
285 282
 				437D47D62415FDF300B7768E /* ControlView.swift */,
+0 -257
USB Meter/Views/Meter/MeterSettingsView.swift
@@ -1,257 +0,0 @@
1
-//
2
-//  SettingsView.swift
3
-//  USB Meter
4
-//
5
-//  Created by Bogdan Timofte on 14/03/2020.
6
-//  Copyright © 2020 Bogdan Timofte. All rights reserved.
7
-//
8
-
9
-import SwiftUI
10
-
11
-struct MeterSettingsView: View {
12
-    
13
-    @EnvironmentObject private var meter: Meter
14
-    @Environment(\.dismiss) private var dismiss
15
-
16
-    private static let isMacIPadApp: Bool = ProcessInfo.processInfo.isiOSAppOnMac
17
-
18
-    @State private var editingName = false
19
-    @State private var editingScreenTimeout = false
20
-    @State private var editingScreenBrightness = false
21
-
22
-    var body: some View {
23
-        VStack(spacing: 0) {
24
-            if Self.isMacIPadApp {
25
-                macSettingsHeader
26
-            }
27
-            ScrollView {
28
-            VStack (spacing: 14) {
29
-                settingsCard(title: "Name", tint: meter.color) {
30
-                    HStack {
31
-                        Spacer()
32
-                        if !editingName {
33
-                            Text(meter.name)
34
-                                .foregroundColor(.secondary)
35
-                        }
36
-                        ChevronView(rotate: $editingName)
37
-                    }
38
-                    if editingName {
39
-                        EditNameView(editingName: $editingName, newName: meter.name)
40
-                    }
41
-                }
42
-
43
-                if meter.operationalState == .dataIsAvailable && meter.supportsManualTemperatureUnitSelection {
44
-                    settingsCard(title: "Meter Temperature Unit", tint: .orange) {
45
-                        Text("TC66 temperature is shown as degrees without assuming Celsius or Fahrenheit. Keep this matched to the unit configured on the device so you can interpret the reading correctly.")
46
-                            .font(.footnote)
47
-                            .foregroundColor(.secondary)
48
-                        Picker("", selection: $meter.tc66TemperatureUnitPreference) {
49
-                            ForEach(TemperatureUnitPreference.allCases) { unit in
50
-                                Text(unit.title).tag(unit)
51
-                            }
52
-                        }
53
-                        .pickerStyle(SegmentedPickerStyle())
54
-                    }
55
-                }
56
-
57
-                if meter.operationalState == .dataIsAvailable {
58
-                    settingsCard(
59
-                        title: meter.reportsCurrentScreenIndex ? "Screen Controls" : "Page Controls",
60
-                        tint: .indigo
61
-                    ) {
62
-                        if meter.reportsCurrentScreenIndex {
63
-                            Text("Use these controls when you want to change the screen shown on the device without crowding the main meter view.")
64
-                                .font(.footnote)
65
-                                .foregroundColor(.secondary)
66
-                        } else {
67
-                            Text("Use these controls when you want to switch device pages without crowding the main meter view.")
68
-                                .font(.footnote)
69
-                                .foregroundColor(.secondary)
70
-                        }
71
-
72
-                        ControlView(showsHeader: false)
73
-                    }
74
-                }
75
-
76
-                if meter.operationalState == .dataIsAvailable && meter.supportsUMSettings {
77
-                    settingsCard(title: "Screen Timeout", tint: .purple) {
78
-                        HStack {
79
-                            Spacer()
80
-                            if !editingScreenTimeout {
81
-                                Text(meter.screenTimeout != 0 ? "\(meter.screenTimeout) Minutes" : "Off")
82
-                                    .foregroundColor(.secondary)
83
-                            }
84
-                            ChevronView(rotate: $editingScreenTimeout)
85
-                        }
86
-                        if editingScreenTimeout {
87
-                            EditScreenTimeoutView()
88
-                        }
89
-                    }
90
-
91
-                    settingsCard(title: "Screen Brightness", tint: .yellow) {
92
-                        HStack {
93
-                            Spacer()
94
-                            if !editingScreenBrightness {
95
-                                Text("\(meter.screenBrightness)")
96
-                                    .foregroundColor(.secondary)
97
-                            }
98
-                            ChevronView(rotate: $editingScreenBrightness)
99
-                        }
100
-                        if editingScreenBrightness {
101
-                            EditScreenBrightnessView()
102
-                        }
103
-                    }
104
-                }
105
-            }
106
-            .padding()
107
-        }
108
-        .background(
109
-            LinearGradient(
110
-                colors: [meter.color.opacity(0.14), Color.clear],
111
-                startPoint: .topLeading,
112
-                endPoint: .bottomTrailing
113
-            )
114
-            .ignoresSafeArea()
115
-        )
116
-        }
117
-        .modifier(IOSOnlySettingsNavBar(
118
-            apply: !Self.isMacIPadApp,
119
-            rssi: meter.btSerial.averageRSSI
120
-        ))
121
-    }
122
-
123
-    // MARK: - Custom navigation header for Designed-for-iPad on Mac
124
-
125
-    private var macSettingsHeader: some View {
126
-        HStack(spacing: 12) {
127
-            Button {
128
-                dismiss()
129
-            } label: {
130
-                HStack(spacing: 4) {
131
-                    Image(systemName: "chevron.left")
132
-                        .font(.body.weight(.semibold))
133
-                    Text("Back")
134
-                }
135
-                .foregroundColor(.accentColor)
136
-            }
137
-            .buttonStyle(.plain)
138
-
139
-            Text("Meter Settings")
140
-                .font(.headline)
141
-                .lineLimit(1)
142
-
143
-            Spacer()
144
-
145
-            if meter.operationalState > .notPresent {
146
-                RSSIView(RSSI: meter.btSerial.averageRSSI)
147
-                    .frame(width: 18, height: 18)
148
-            }
149
-        }
150
-        .padding(.horizontal, 16)
151
-        .padding(.vertical, 10)
152
-        .background(
153
-            Rectangle()
154
-                .fill(.ultraThinMaterial)
155
-                .ignoresSafeArea(edges: .top)
156
-        )
157
-        .overlay(alignment: .bottom) {
158
-            Rectangle()
159
-                .fill(Color.secondary.opacity(0.12))
160
-                .frame(height: 1)
161
-        }
162
-    }
163
-
164
-    private func settingsCard<Content: View>(
165
-        title: String,
166
-        tint: Color,
167
-        @ViewBuilder content: () -> Content
168
-    ) -> some View {
169
-        VStack(alignment: .leading, spacing: 12) {
170
-            Text(title)
171
-                .font(.headline)
172
-            content()
173
-        }
174
-        .padding(18)
175
-        .meterCard(tint: tint, fillOpacity: 0.18, strokeOpacity: 0.24)
176
-    }
177
-}
178
-
179
-struct EditNameView: View {
180
-    
181
-    @EnvironmentObject private var meter: Meter
182
-    
183
-    @Binding var editingName: Bool
184
-    @State var newName: String
185
-    
186
-    var body: some View {
187
-        TextField("Name", text: self.$newName, onCommit: {
188
-            self.meter.name = self.newName
189
-            self.editingName = false
190
-        })
191
-            .textFieldStyle(RoundedBorderTextFieldStyle())
192
-            .lineLimit(1)
193
-            .disableAutocorrection(true)
194
-            .multilineTextAlignment(.center)
195
-    }
196
-}
197
-
198
-struct EditScreenTimeoutView: View {
199
-    
200
-    @EnvironmentObject private var meter: Meter
201
-    
202
-    var body: some View {
203
-        Picker("", selection: self.$meter.screenTimeout ) {
204
-            Text("1").tag(1)
205
-            Text("2").tag(2)
206
-            Text("3").tag(3)
207
-            Text("4").tag(4)
208
-            Text("5").tag(5)
209
-            Text("6").tag(6)
210
-            Text("7").tag(7)
211
-            Text("8").tag(8)
212
-            Text("9").tag(9)
213
-            Text("Off").tag(0)
214
-        }
215
-        .pickerStyle( SegmentedPickerStyle() )
216
-    }
217
-}
218
-
219
-struct EditScreenBrightnessView: View {
220
-    
221
-    @EnvironmentObject private var meter: Meter
222
-    
223
-    var body: some View {
224
-        Picker("", selection: self.$meter.screenBrightness ) {
225
-            Text("0").tag(0)
226
-            Text("1").tag(1)
227
-            Text("2").tag(2)
228
-            Text("3").tag(3)
229
-            Text("4").tag(4)
230
-            Text("5").tag(5)
231
-        }
232
-        .pickerStyle( SegmentedPickerStyle() )
233
-    }
234
-}
235
-
236
-// MARK: - Conditional navigation bar modifier (skipped on Designed-for-iPad / Mac)
237
-
238
-private struct IOSOnlySettingsNavBar: ViewModifier {
239
-    let apply: Bool
240
-    let rssi: Int
241
-
242
-    @ViewBuilder
243
-    func body(content: Content) -> some View {
244
-        if apply {
245
-            content
246
-                .navigationBarTitle("Meter Settings")
247
-                .toolbar {
248
-                    ToolbarItem(placement: .navigationBarTrailing) {
249
-                        RSSIView(RSSI: rssi).frame(width: 18, height: 18)
250
-                    }
251
-                }
252
-        } else {
253
-            content
254
-                .navigationBarHidden(true)
255
-        }
256
-    }
257
-}
+220 -8
USB Meter/Views/Meter/MeterView.swift
@@ -15,12 +15,14 @@ struct MeterView: View {
15 15
         case connection
16 16
         case live
17 17
         case chart
18
+        case settings
18 19
 
19 20
         var title: String {
20 21
             switch self {
21 22
             case .connection: return "Home"
22 23
             case .live: return "Live"
23 24
             case .chart: return "Chart"
25
+            case .settings: return "Settings"
24 26
             }
25 27
         }
26 28
 
@@ -29,6 +31,7 @@ struct MeterView: View {
29 31
             case .connection: return "house.fill"
30 32
             case .live: return "waveform.path.ecg"
31 33
             case .chart: return "chart.xyaxis.line"
34
+            case .settings: return "gearshape.fill"
32 35
             }
33 36
         }
34 37
     }
@@ -45,6 +48,9 @@ struct MeterView: View {
45 48
     @State private var navBarTitle: String = "Meter"
46 49
     @State private var navBarShowRSSI: Bool = false
47 50
     @State private var navBarRSSI: Int = 0
51
+    @State private var editingName = false
52
+    @State private var editingScreenTimeout = false
53
+    @State private var editingScreenBrightness = false
48 54
     private var myBounds: CGRect { UIScreen.main.bounds }
49 55
     private let actionStripPadding: CGFloat = 10
50 56
     private let actionDividerWidth: CGFloat = 1
@@ -129,11 +135,6 @@ struct MeterView: View {
129 135
                     .frame(width: 18, height: 18)
130 136
             }
131 137
 
132
-            NavigationLink(destination: MeterSettingsView().environmentObject(meter)) {
133
-                Image(systemName: "gearshape.fill")
134
-                    .foregroundColor(.accentColor)
135
-            }
136
-            .buttonStyle(.plain)
137 138
         }
138 139
         .padding(.horizontal, 16)
139 140
         .padding(.vertical, 10)
@@ -270,6 +271,8 @@ struct MeterView: View {
270 271
             } else {
271 272
                 landscapeConnectionPage
272 273
             }
274
+        case .settings:
275
+            landscapeSettingsPage(size: size)
273 276
         }
274 277
     }
275 278
 
@@ -290,6 +293,8 @@ struct MeterView: View {
290 293
             } else {
291 294
                 portraitConnectionPage(size: size)
292 295
             }
296
+        case .settings:
297
+            portraitSettingsPage(size: size)
293 298
         }
294 299
     }
295 300
 
@@ -410,6 +415,166 @@ struct MeterView: View {
410 415
         }
411 416
     }
412 417
 
418
+    @ViewBuilder
419
+    private func portraitSettingsPage(size: CGSize) -> some View {
420
+        settingsTabContent
421
+    }
422
+
423
+    @ViewBuilder
424
+    private func landscapeSettingsPage(size: CGSize) -> some View {
425
+        settingsTabContent
426
+    }
427
+
428
+    private var settingsTabContent: some View {
429
+        VStack(spacing: 0) {
430
+            if Self.isMacIPadApp {
431
+                settingsMacHeader
432
+            }
433
+            ScrollView {
434
+                VStack(spacing: 14) {
435
+                    settingsCard(title: "Name", tint: meter.color) {
436
+                        HStack {
437
+                            Spacer()
438
+                            if !editingName {
439
+                                Text(meter.name)
440
+                                    .foregroundColor(.secondary)
441
+                            }
442
+                            ChevronView(rotate: $editingName)
443
+                        }
444
+                        if editingName {
445
+                            EditNameView(editingName: $editingName, newName: meter.name)
446
+                        }
447
+                    }
448
+
449
+                    if meter.operationalState == .dataIsAvailable && meter.supportsManualTemperatureUnitSelection {
450
+                        settingsCard(title: "Meter Temperature Unit", tint: .orange) {
451
+                            Text("TC66 temperature is shown as degrees without assuming Celsius or Fahrenheit. Keep this matched to the unit configured on the device so you can interpret the reading correctly.")
452
+                                .font(.footnote)
453
+                                .foregroundColor(.secondary)
454
+                            Picker("", selection: $meter.tc66TemperatureUnitPreference) {
455
+                                ForEach(TemperatureUnitPreference.allCases) { unit in
456
+                                    Text(unit.title).tag(unit)
457
+                                }
458
+                            }
459
+                            .pickerStyle(SegmentedPickerStyle())
460
+                        }
461
+                    }
462
+
463
+                    if meter.operationalState == .dataIsAvailable {
464
+                        settingsCard(
465
+                            title: meter.reportsCurrentScreenIndex ? "Screen Controls" : "Page Controls",
466
+                            tint: .indigo
467
+                        ) {
468
+                            if meter.reportsCurrentScreenIndex {
469
+                                Text("Use these controls when you want to change the screen shown on the device without crowding the main meter view.")
470
+                                    .font(.footnote)
471
+                                    .foregroundColor(.secondary)
472
+                            } else {
473
+                                Text("Use these controls when you want to switch device pages without crowding the main meter view.")
474
+                                    .font(.footnote)
475
+                                    .foregroundColor(.secondary)
476
+                            }
477
+
478
+                            ControlView(showsHeader: false)
479
+                        }
480
+                    }
481
+
482
+                    if meter.operationalState == .dataIsAvailable && meter.supportsUMSettings {
483
+                        settingsCard(title: "Screen Timeout", tint: .purple) {
484
+                            HStack {
485
+                                Spacer()
486
+                                if !editingScreenTimeout {
487
+                                    Text(meter.screenTimeout > 0 ? "\(meter.screenTimeout) Minutes" : "Off")
488
+                                        .foregroundColor(.secondary)
489
+                                }
490
+                                ChevronView(rotate: $editingScreenTimeout)
491
+                            }
492
+                            if editingScreenTimeout {
493
+                                EditScreenTimeoutView()
494
+                            }
495
+                        }
496
+
497
+                        settingsCard(title: "Screen Brightness", tint: .yellow) {
498
+                            HStack {
499
+                                Spacer()
500
+                                if !editingScreenBrightness {
501
+                                    Text("\(meter.screenBrightness)")
502
+                                        .foregroundColor(.secondary)
503
+                                }
504
+                                ChevronView(rotate: $editingScreenBrightness)
505
+                            }
506
+                            if editingScreenBrightness {
507
+                                EditScreenBrightnessView()
508
+                            }
509
+                        }
510
+                    }
511
+                }
512
+                .padding()
513
+            }
514
+            .background(
515
+                LinearGradient(
516
+                    colors: [meter.color.opacity(0.14), Color.clear],
517
+                    startPoint: .topLeading,
518
+                    endPoint: .bottomTrailing
519
+                )
520
+                .ignoresSafeArea()
521
+            )
522
+        }
523
+    }
524
+
525
+    private var settingsMacHeader: some View {
526
+        HStack(spacing: 12) {
527
+            Button {
528
+                selectedMeterTab = .connection
529
+            } label: {
530
+                HStack(spacing: 4) {
531
+                    Image(systemName: "chevron.left")
532
+                        .font(.body.weight(.semibold))
533
+                    Text("Back")
534
+                }
535
+                .foregroundColor(.accentColor)
536
+            }
537
+            .buttonStyle(.plain)
538
+
539
+            Text("Meter Settings")
540
+                .font(.headline)
541
+                .lineLimit(1)
542
+
543
+            Spacer()
544
+
545
+            if meter.operationalState > .notPresent {
546
+                RSSIView(RSSI: meter.btSerial.averageRSSI)
547
+                    .frame(width: 18, height: 18)
548
+            }
549
+        }
550
+        .padding(.horizontal, 16)
551
+        .padding(.vertical, 10)
552
+        .background(
553
+            Rectangle()
554
+                .fill(.ultraThinMaterial)
555
+                .ignoresSafeArea(edges: .top)
556
+        )
557
+        .overlay(alignment: .bottom) {
558
+            Rectangle()
559
+                .fill(Color.secondary.opacity(0.12))
560
+                .frame(height: 1)
561
+        }
562
+    }
563
+
564
+    private func settingsCard<Content: View>(
565
+        title: String,
566
+        tint: Color,
567
+        @ViewBuilder content: () -> Content
568
+    ) -> some View {
569
+        VStack(alignment: .leading, spacing: 12) {
570
+            Text(title)
571
+                .font(.headline)
572
+            content()
573
+        }
574
+        .padding(18)
575
+        .meterCard(tint: tint, fillOpacity: 0.18, strokeOpacity: 0.24)
576
+    }
577
+
413 578
     private var availableMeterTabs: [MeterTab] {
414 579
         var tabs: [MeterTab] = [.connection]
415 580
 
@@ -421,6 +586,8 @@ struct MeterView: View {
421 586
             }
422 587
         }
423 588
 
589
+        tabs.append(.settings)
590
+
424 591
         return tabs
425 592
     }
426 593
 
@@ -727,6 +894,54 @@ private struct MeterInfoRow: View {
727 894
     }
728 895
 }
729 896
 
897
+private struct EditNameView: View {
898
+
899
+    @EnvironmentObject private var meter: Meter
900
+
901
+    @Binding var editingName: Bool
902
+    @State var newName: String
903
+
904
+    var body: some View {
905
+        TextField("Name", text: self.$newName, onCommit: {
906
+            self.meter.name = self.newName
907
+            self.editingName = false
908
+        })
909
+            .textFieldStyle(RoundedBorderTextFieldStyle())
910
+            .lineLimit(1)
911
+            .disableAutocorrection(true)
912
+            .multilineTextAlignment(.center)
913
+    }
914
+}
915
+
916
+private struct EditScreenTimeoutView: View {
917
+
918
+    @EnvironmentObject private var meter: Meter
919
+
920
+    var body: some View {
921
+        Picker("", selection: self.$meter.screenTimeout ) {
922
+            ForEach(1...9, id: \.self) { value in
923
+                Text("\(value)").tag(value)
924
+            }
925
+            Text("Off").tag(0)
926
+        }
927
+        .pickerStyle(SegmentedPickerStyle())
928
+    }
929
+}
930
+
931
+private struct EditScreenBrightnessView: View {
932
+
933
+    @EnvironmentObject private var meter: Meter
934
+
935
+    var body: some View {
936
+        Picker("", selection: self.$meter.screenBrightness ) {
937
+            ForEach(0...5, id: \.self) { value in
938
+                Text("\(value)").tag(value)
939
+            }
940
+        }
941
+        .pickerStyle(SegmentedPickerStyle())
942
+    }
943
+}
944
+
730 945
 // MARK: - Conditional navigation bar modifier (skipped on Designed-for-iPad / Mac)
731 946
 
732 947
 private struct IOSOnlyNavBar: ViewModifier {
@@ -747,9 +962,6 @@ private struct IOSOnlyNavBar: ViewModifier {
747 962
                             RSSIView(RSSI: rssi)
748 963
                                 .frame(width: 18, height: 18)
749 964
                         }
750
-                        NavigationLink(destination: MeterSettingsView().environmentObject(meter)) {
751
-                            Image(systemName: "gearshape.fill")
752
-                        }
753 965
                     }
754 966
                 }
755 967
         } else {