USB-Meter / USB Meter / Views / ChargedDevices / SidebarChargedDevicesSectionView.swift
1 contributor
150 lines | 5.745kb
//
//  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)
    }
}