Showing 4 changed files with 55 additions and 54 deletions
+14 -1
USB Meter/Model/BluetoothSerial.swift
@@ -35,7 +35,14 @@ final class BluetoothSerial : NSObject, ObservableObject {
35 35
     var macAddress: MACAddress
36 36
     private var manager: CBCentralManager
37 37
     private var radio: BluetoothRadio
38
-    @Published var RSSI: Int
38
+    @Published var RSSI: Int {
39
+        didSet {
40
+            minRSSI = Swift.min(minRSSI, RSSI)
41
+            maxRSSI = Swift.max(maxRSSI, RSSI)
42
+        }
43
+    }
44
+    @Published private(set) var minRSSI: Int
45
+    @Published private(set) var maxRSSI: Int
39 46
     
40 47
     private var expectedResponseLength = 0
41 48
     private var wdTimer: Timer?
@@ -58,6 +65,8 @@ final class BluetoothSerial : NSObject, ObservableObject {
58 65
         self.radio = radio
59 66
         self.manager = manager
60 67
         self.RSSI = RSSI
68
+        self.minRSSI = RSSI
69
+        self.maxRSSI = RSSI
61 70
         Timer.scheduledTimer(withTimeInterval: 3, repeats: true, block: {_ in
62 71
             if peripheral.state == .connected {
63 72
                 peripheral.readRSSI()
@@ -145,6 +154,8 @@ final class BluetoothSerial : NSObject, ObservableObject {
145 154
     func connectionEstablished () {
146 155
         resetCommunicationState(reason: "connectionEstablished()", clearCharacteristics: true)
147 156
         track("Connection established for '\(peripheral.identifier)'")
157
+        minRSSI = RSSI
158
+        maxRSSI = RSSI
148 159
         operationalState = .peripheralConnected
149 160
         peripheral.discoverServices(BluetoothRadioServicesUUIDS[radio])
150 161
     }
@@ -152,6 +163,8 @@ final class BluetoothSerial : NSObject, ObservableObject {
152 163
     func connectionClosed () {
153 164
         track("Connection closed for '\(peripheral.identifier)' while peripheral state is \(peripheral.state.rawValue)")
154 165
         resetCommunicationState(reason: "connectionClosed()", clearCharacteristics: true)
166
+        minRSSI = RSSI
167
+        maxRSSI = RSSI
155 168
         operationalState = .peripheralNotConnected
156 169
     }
157 170
 
+5 -1
USB Meter/Model/Meter.swift
@@ -329,8 +329,12 @@ class Meter : NSObject, ObservableObject, Identifiable {
329 329
         return "Screen \(currentScreen)"
330 330
     }
331 331
 
332
+    var deviceModelName: String {
333
+        reportedModelName.isEmpty ? modelString : reportedModelName
334
+    }
335
+
332 336
     var deviceModelSummary: String {
333
-        let baseName = reportedModelName.isEmpty ? modelString : reportedModelName
337
+        let baseName = deviceModelName
334 338
         if modelNumber != 0 {
335 339
             return "\(baseName) (\(modelNumber))"
336 340
         }
+13 -21
USB Meter/Views/Meter/LiveView.swift
@@ -136,19 +136,19 @@ struct LiveView: View {
136 136
                     detailText: "Measured resistance"
137 137
                 )
138 138
 
139
-                if shouldShowChargerTile {
140
-                    liveMetricCard(
141
-                        title: "Charger",
142
-                        symbol: "bolt.badge.checkmark",
143
-                        color: .purple,
144
-                        value: meter.chargerTypeDescription,
145
-                        detailText: chargerTypeDetailText,
146
-                        valueFont: .system(compactLayout ? .subheadline : .headline, design: .rounded).weight(.bold),
147
-                        valueLineLimit: 2,
148
-                        valueMonospacedDigits: false,
149
-                        valueMinimumScaleFactor: 0.70
150
-                    )
151
-                }
139
+                liveMetricCard(
140
+                    title: "RSSI",
141
+                    symbol: "dot.radiowaves.left.and.right",
142
+                    color: .mint,
143
+                    value: "\(meter.btSerial.RSSI) dBm",
144
+                    range: MetricRange(
145
+                        minLabel: "Min",
146
+                        maxLabel: "Max",
147
+                        minValue: "\(meter.btSerial.minRSSI) dBm",
148
+                        maxValue: "\(meter.btSerial.maxRSSI) dBm"
149
+                    ),
150
+                    valueFont: .system(compactLayout ? .subheadline : .headline, design: .rounded).weight(.bold)
151
+                )
152 152
             }
153 153
         }
154 154
         .frame(maxWidth: .infinity, alignment: .topLeading)
@@ -176,14 +176,6 @@ struct LiveView: View {
176 176
             )
177 177
     }
178 178
 
179
-    private var shouldShowChargerTile: Bool {
180
-        meter.supportsChargerDetection
181
-    }
182
-
183
-    private var chargerTypeDetailText: String {
184
-        meter.chargerTypeDescription == "Unknown" ? "No charging profile detected" : "Detected charging profile"
185
-    }
186
-
187 179
     private var showsCompactMetricRange: Bool {
188 180
         compactLayout && (availableSize?.height ?? 0) >= 380
189 181
     }
+23 -31
USB Meter/Views/Meter/MeterView.swift
@@ -139,35 +139,9 @@ struct MeterView: View {
139 139
     private func connectionCard(compact: Bool = false, showsActions: Bool = false) -> some View {
140 140
         VStack(alignment: .leading, spacing: compact ? 12 : 18) {
141 141
             HStack(alignment: .top) {
142
-                VStack(alignment: .leading, spacing: 6) {
143
-                    Text(meter.name)
144
-                        .font(.system(compact ? .title3 : .title2, design: .rounded).weight(.bold))
145
-                    Text(meter.deviceModelSummary)
146
-                        .font(.subheadline.weight(.semibold))
147
-                        .foregroundColor(.secondary)
148
-                }
142
+                meterIdentity(compact: compact)
149 143
                 Spacer()
150
-                Group {
151
-                    if compact {
152
-                        HStack(spacing: 8) {
153
-                            statusBadge
154
-                            if meter.operationalState > .notPresent {
155
-                                Text("RSSI \(meter.btSerial.RSSI)")
156
-                                    .font(.caption)
157
-                                    .foregroundColor(.secondary)
158
-                            }
159
-                        }
160
-                    } else {
161
-                        VStack(alignment: .trailing, spacing: 6) {
162
-                            statusBadge
163
-                            if meter.operationalState > .notPresent {
164
-                                Text("RSSI \(meter.btSerial.RSSI)")
165
-                                    .font(.caption)
166
-                                    .foregroundColor(.secondary)
167
-                            }
168
-                        }
169
-                    }
170
-                }
144
+                statusBadge
171 145
             }
172 146
 
173 147
             if compact {
@@ -191,6 +165,21 @@ struct MeterView: View {
191 165
         .meterCard(tint: meter.color, fillOpacity: 0.22, strokeOpacity: 0.24)
192 166
     }
193 167
 
168
+    private func meterIdentity(compact: Bool) -> some View {
169
+        HStack(alignment: .firstTextBaseline, spacing: 8) {
170
+            Text(meter.name)
171
+                .font(.system(compact ? .title3 : .title2, design: .rounded).weight(.bold))
172
+                .lineLimit(1)
173
+                .minimumScaleFactor(0.8)
174
+
175
+            Text(meter.deviceModelName)
176
+                .font((compact ? Font.caption : .subheadline).weight(.semibold))
177
+                .foregroundColor(.secondary)
178
+                .lineLimit(1)
179
+                .minimumScaleFactor(0.8)
180
+        }
181
+    }
182
+
194 183
     private func actionGrid(compact: Bool = false, embedded: Bool = false) -> some View {
195 184
         let currentActionHeight = compact ? CGFloat(86) : actionButtonHeight
196 185
 
@@ -377,7 +366,7 @@ private struct MeterInfoView: View {
377 366
             VStack(spacing: 14) {
378 367
                 MeterInfoCard(title: "Overview", tint: meter.color) {
379 368
                     MeterInfoRow(label: "Name", value: meter.name)
380
-                    MeterInfoRow(label: "Displayed Model", value: meter.deviceModelSummary)
369
+                    MeterInfoRow(label: "Device Model", value: meter.deviceModelName)
381 370
                     MeterInfoRow(label: "Advertised Model", value: meter.modelString)
382 371
                     MeterInfoRow(label: "Working Voltage", value: meter.documentedWorkingVoltage)
383 372
                     MeterInfoRow(label: "Temperature Unit", value: meter.temperatureUnitDescription)
@@ -386,7 +375,7 @@ private struct MeterInfoView: View {
386 375
                 MeterInfoCard(title: "Identifiers", tint: .blue) {
387 376
                     MeterInfoRow(label: "MAC", value: meter.btSerial.macAddress.description)
388 377
                     if meter.modelNumber != 0 {
389
-                        MeterInfoRow(label: "Model Code", value: "\(meter.modelNumber)")
378
+                        MeterInfoRow(label: "Model Identifier", value: "\(meter.modelNumber)")
390 379
                     }
391 380
                 }
392 381
 
@@ -409,6 +398,9 @@ private struct MeterInfoView: View {
409 398
                         if !meter.firmwareVersion.isEmpty {
410 399
                             MeterInfoRow(label: "Firmware", value: meter.firmwareVersion)
411 400
                         }
401
+                        if meter.supportsChargerDetection {
402
+                            MeterInfoRow(label: "Detected Charger", value: meter.chargerTypeDescription)
403
+                        }
412 404
                         if meter.serialNumber != 0 {
413 405
                             MeterInfoRow(label: "Serial", value: "\(meter.serialNumber)")
414 406
                         }
@@ -434,7 +426,7 @@ private struct MeterInfoView: View {
434 426
             )
435 427
             .ignoresSafeArea()
436 428
         )
437
-        .navigationBarTitle("Meter Info")
429
+        .navigationBarTitle("Device Info")
438 430
         .navigationBarItems(trailing: RSSIView(RSSI: meter.btSerial.RSSI).frame(width: 18, height: 18))
439 431
     }
440 432
 }