1 contributor
129 lines | 4.033kb
//
//  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)
    }
}