// // SidebarView.swift // USB Meter // import SwiftUI import Combine struct SidebarView: View { @EnvironmentObject private var appData: AppData @State private var isHelpExpanded = false @State private var dismissedAutoHelpReason: SidebarHelpReason? @State private var now = Date() private let helpRefreshTimer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() private let noDevicesHelpDelay: TimeInterval = 12 var body: some View { SidebarListView(backgroundTint: appData.bluetoothManager.managerState.color) { usbMetersSection } helpSection: { helpSection } debugSection: { debugSection } .onAppear { appData.bluetoothManager.start() now = Date() } .onReceive(helpRefreshTimer) { currentDate in now = currentDate } .onChange(of: activeHelpAutoReason) { newReason in if newReason == nil { dismissedAutoHelpReason = nil } } } private var usbMetersSection: some View { SidebarUSBMetersSectionView( meters: appData.meterSummaries, managerState: appData.bluetoothManager.managerState, hasLiveMeters: appData.meters.isEmpty == false, scanStartedAt: appData.bluetoothManager.scanStartedAt, now: now, noDevicesHelpDelay: noDevicesHelpDelay ) } private var helpSection: some View { SidebarHelpSectionView( activeReason: activeHelpAutoReason, isExpanded: helpIsExpanded, bluetoothStatusTint: appData.bluetoothManager.managerState.color, bluetoothStatusText: bluetoothStatusText, cloudSyncHelpTitle: appData.cloudAvailability.helpTitle, cloudSyncHelpMessage: appData.cloudAvailability.helpMessage, onToggle: toggleHelpSection, onOpenSettings: openSettings ) { appData.bluetoothManager.managerState.helpView } deviceHelpDestination: { DeviceHelpView() } } private var debugSection: some View { SidebarDebugSectionView() } private var bluetoothStatusText: String { switch appData.bluetoothManager.managerState { case .poweredOff: return "Off" case .poweredOn: return "On" case .resetting: return "Resetting" case .unauthorized: return "Unauthorized" case .unknown: return "Unknown" case .unsupported: return "Unsupported" @unknown default: return "Other" } } private var helpIsExpanded: Bool { isHelpExpanded || shouldAutoExpandHelp } private var shouldAutoExpandHelp: Bool { guard let activeHelpAutoReason else { return false } return dismissedAutoHelpReason != activeHelpAutoReason } private var activeHelpAutoReason: SidebarHelpReason? { SidebarAutoHelpResolver.activeReason( managerState: appData.bluetoothManager.managerState, cloudAvailability: appData.cloudAvailability, hasLiveMeters: appData.meters.isEmpty == false, scanStartedAt: appData.bluetoothManager.scanStartedAt, now: now, noDevicesHelpDelay: noDevicesHelpDelay ) } private func toggleHelpSection() { withAnimation(.easeInOut(duration: 0.22)) { if shouldAutoExpandHelp { dismissedAutoHelpReason = activeHelpAutoReason isHelpExpanded = false } else { isHelpExpanded.toggle() } } } private func openSettings() { guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return } UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil) } }