1 contributor
//
// SidebarChargedDevicesSectionView.swift
// USB Meter
//
// Created by Codex on 10/04/2026.
//
import SwiftUI
struct SidebarChargedDevicesSectionView: View {
let title: String
let mode: ChargedDeviceLibraryMode
let chargedDevices: [ChargedDeviceSummary]
let emptyStateText: String
let tint: Color
let isExpanded: Bool
let onToggle: () -> Void
let onAdd: () -> Void
var body: some View {
Section(header: headerView) {
if isExpanded {
// Library overview row — navigates to the full management library
NavigationLink(destination: SidebarChargedDeviceLibraryView(mode: mode)) {
libraryRow
}
.buttonStyle(.plain)
.transition(.opacity.combined(with: .move(edge: .top)))
ForEach(chargedDevices) { chargedDevice in
NavigationLink(destination: ChargedDeviceDetailView(chargedDeviceID: chargedDevice.id)) {
ChargedDeviceSidebarCardView(chargedDevice: chargedDevice)
}
.buttonStyle(.plain)
.transition(.opacity.combined(with: .move(edge: .top)))
}
}
}
}
private var libraryRow: some View {
HStack(spacing: 12) {
Image(systemName: mode == .device ? "square.grid.2x2" : "bolt.circle")
.font(.system(size: 16, weight: .semibold))
.foregroundColor(tint)
.frame(width: 36, height: 36)
.background(tint.opacity(0.14))
.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
VStack(alignment: .leading, spacing: 2) {
Text("All \(title)")
.font(.subheadline.weight(.semibold))
.foregroundColor(.primary)
let count = chargedDevices.count
Text("\(count) \(count == 1 ? mode.singularTitle.lowercased() : mode.title.lowercased())")
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
}
.padding(.vertical, 4)
}
private var headerView: some View {
HStack(alignment: .firstTextBaseline, spacing: 10) {
Button(action: onToggle) {
HStack(alignment: .firstTextBaseline, spacing: 4) {
Image(systemName: "chevron.right")
.font(.caption.weight(.semibold))
.foregroundColor(.secondary)
.rotationEffect(.degrees(isExpanded ? 90 : 0))
.animation(.easeInOut(duration: 0.22), value: isExpanded)
Text(title)
.font(.headline)
}
}
.buttonStyle(.plain)
Spacer()
Button(action: onAdd) {
Image(systemName: "plus.circle.fill")
.font(.body.weight(.semibold))
.foregroundColor(tint)
}
.buttonStyle(.plain)
Text("\(chargedDevices.count)")
.font(.caption.weight(.bold))
.padding(.horizontal, 10)
.padding(.vertical, 6)
.meterCard(tint: tint, fillOpacity: 0.18, strokeOpacity: 0.24, cornerRadius: 999)
}
}
}
private struct ChargedDeviceSidebarCardView: View {
let chargedDevice: ChargedDeviceSummary
var body: some View {
HStack(alignment: .top, spacing: 12) {
ChargedDeviceQRCodeView(qrIdentifier: chargedDevice.qrIdentifier, side: 54)
VStack(alignment: .leading, spacing: 6) {
HStack {
ChargedDeviceIdentityLabelView(
chargedDevice: chargedDevice,
iconPointSize: 17
)
.font(.headline)
if chargedDevice.activeSession != nil {
Spacer()
Text("Live")
.font(.caption.weight(.bold))
.foregroundColor(.green)
}
}
Text(chargedDevice.identityTitle)
.font(.caption.weight(.semibold))
.foregroundColor(.secondary)
if chargedDevice.isCharger {
if let chargerMaximumPowerWatts = chargedDevice.chargerMaximumPowerWatts {
Text("Max power: \(chargerMaximumPowerWatts.format(decimalDigits: 2)) W")
.font(.caption2)
.foregroundColor(.secondary)
} else {
Text("Wireless charger")
.font(.caption2)
.foregroundColor(.secondary)
}
} else {
Text(chargedDevice.supportedChargingModes.map(\.title).joined(separator: " + "))
.font(.caption2)
.foregroundColor(.secondary)
if let estimatedCapacityWh = chargedDevice.estimatedBatteryCapacityWh {
Text("Capacity: \(estimatedCapacityWh.format(decimalDigits: 2)) Wh")
.font(.caption2)
.foregroundColor(.secondary)
} else {
Text("Capacity: learning")
.font(.caption2)
.foregroundColor(.secondary)
}
}
}
}
.padding(.vertical, 4)
}
}