Showing 1 changed files with 83 additions and 13 deletions
+83 -13
USB Meter/Views/ContentView.swift
@@ -571,7 +571,7 @@ struct ContentView: View {
571 571
 
572 572
                 if !appData.knownMetersByMAC.isEmpty {
573 573
                     VStack(alignment: .leading, spacing: 10) {
574
-                        Text("Connected Meters")
574
+                        Text("Known Meters")
575 575
                             .font(.headline)
576 576
                         ForEach(Array(appData.knownMetersByMAC.values), id: \.macAddress) { known in
577 577
                             meterDebugCard(for: known)
@@ -613,22 +613,92 @@ struct ContentView: View {
613 613
     }
614 614
 
615 615
     private func meterDebugCard(for known: KnownMeterCatalogItem) -> some View {
616
-        VStack(alignment: .leading, spacing: 6) {
617
-            Text(known.displayName)
618
-                .font(.subheadline.weight(.semibold))
619
-            VStack(alignment: .leading, spacing: 2) {
620
-                Text(known.macAddress)
621
-                    .font(.system(.caption, design: .monospaced))
622
-                if let connectedBy = known.connectedByDeviceName, !connectedBy.isEmpty {
623
-                    Text("Connected: \(connectedBy)")
624
-                        .font(.system(.caption2, design: .default))
625
-                        .foregroundColor(.secondary)
616
+        let isLive = appData.meters.values.contains { $0.btSerial.macAddress.description == known.macAddress }
617
+        let connectedElsewhere = isConnectedElsewhere(known)
618
+        let statusText: String = {
619
+            if isLive {
620
+                return "Live on this device"
621
+            } else if connectedElsewhere {
622
+                return "Connected elsewhere"
623
+            } else {
624
+                return "Offline"
625
+            }
626
+        }()
627
+        let statusColor: Color = {
628
+            if isLive {
629
+                return .green
630
+            } else if connectedElsewhere {
631
+                return .indigo
632
+            } else {
633
+                return .secondary
634
+            }
635
+        }()
636
+
637
+        return VStack(alignment: .leading, spacing: 8) {
638
+            HStack {
639
+                Circle()
640
+                    .fill(statusColor)
641
+                    .frame(width: 8, height: 8)
642
+                Text(known.displayName)
643
+                    .font(.subheadline.weight(.semibold))
644
+                Spacer()
645
+                Text(statusText)
646
+                    .font(.caption2)
647
+                    .foregroundColor(statusColor)
648
+            }
649
+
650
+            Text(known.macAddress)
651
+                .font(.system(.caption, design: .monospaced))
652
+                .foregroundColor(.secondary)
653
+
654
+            if let modelType = known.modelType {
655
+                Text("Model: \(modelType)")
656
+                    .font(.caption2)
657
+                    .foregroundColor(.secondary)
658
+            }
659
+
660
+            Divider()
661
+
662
+            if let connectedBy = known.connectedByDeviceName, !connectedBy.isEmpty {
663
+                VStack(alignment: .leading, spacing: 3) {
664
+                    Text("Connection:")
665
+                        .font(.caption.weight(.semibold))
666
+                    Text("Device: \(connectedBy)")
667
+                        .font(.system(.caption2, design: .monospaced))
668
+                    if let connectedAt = known.connectedAt {
669
+                        Text("Since: \(formatDate(connectedAt))")
670
+                            .font(.system(.caption2, design: .monospaced))
671
+                    }
672
+                    if let expiry = known.connectedExpiryAt {
673
+                        let expired = expiry < Date()
674
+                        Text("Expires: \(formatDate(expiry)) \(expired ? "(expired)" : "")")
675
+                            .font(.system(.caption2, design: .monospaced))
676
+                            .foregroundColor(expired ? .orange : .secondary)
677
+                    }
678
+                }
679
+            } else {
680
+                Text("Not connected")
681
+                    .font(.caption2)
682
+                    .foregroundColor(.secondary)
683
+            }
684
+
685
+            if let lastSeenAt = known.lastSeenAt {
686
+                Divider()
687
+                VStack(alignment: .leading, spacing: 3) {
688
+                    Text("Discovery:")
689
+                        .font(.caption.weight(.semibold))
690
+                    Text("Last seen: \(formatDate(lastSeenAt))")
691
+                        .font(.system(.caption2, design: .monospaced))
692
+                    if let seenBy = known.lastSeenByDeviceName, !seenBy.isEmpty {
693
+                        Text("Seen by: \(seenBy)")
694
+                            .font(.system(.caption2, design: .monospaced))
695
+                    }
626 696
                 }
627 697
             }
628 698
         }
629 699
         .frame(maxWidth: .infinity, alignment: .leading)
630
-        .padding(10)
631
-        .meterCard(tint: .cyan, fillOpacity: 0.08, strokeOpacity: 0.12)
700
+        .padding(12)
701
+        .meterCard(tint: statusColor, fillOpacity: 0.08, strokeOpacity: 0.14)
632 702
     }
633 703
 }
634 704