| 1 |
// |
|
| 2 |
// SidebarView.swift |
|
| 3 |
// USB Meter |
|
| 4 |
// |
|
| 5 | ||
| 6 |
import SwiftUI |
|
| 7 |
import Combine |
|
| 8 | ||
| 9 |
struct SidebarView: View {
|
|
| 10 |
@EnvironmentObject private var appData: AppData |
|
| 11 |
@State private var isHelpExpanded = false |
|
| 12 |
@State private var dismissedAutoHelpReason: SidebarHelpReason? |
|
| 13 |
@State private var now = Date() |
|
| 14 |
private let helpRefreshTimer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() |
|
| 15 |
private let noDevicesHelpDelay: TimeInterval = 12 |
|
| 16 | ||
| 17 |
var body: some View {
|
|
| 18 |
SidebarListView(backgroundTint: appData.bluetoothManager.managerState.color) {
|
|
| 19 |
usbMetersSection |
|
| 20 |
} helpSection: {
|
|
| 21 |
helpSection |
|
| 22 |
} debugSection: {
|
|
| 23 |
debugSection |
|
| 24 |
} |
|
| 25 |
.onAppear {
|
|
| 26 |
appData.bluetoothManager.start() |
|
| 27 |
now = Date() |
|
| 28 |
} |
|
| 29 |
.onReceive(helpRefreshTimer) { currentDate in
|
|
| 30 |
now = currentDate |
|
| 31 |
} |
|
| 32 |
.onChange(of: activeHelpAutoReason) { newReason in
|
|
| 33 |
if newReason == nil {
|
|
| 34 |
dismissedAutoHelpReason = nil |
|
| 35 |
} |
|
| 36 |
} |
|
| 37 |
} |
|
| 38 | ||
| 39 |
private var usbMetersSection: some View {
|
|
| 40 |
SidebarUSBMetersSectionView( |
|
| 41 |
meters: appData.meterSummaries, |
|
| 42 |
managerState: appData.bluetoothManager.managerState, |
|
| 43 |
hasLiveMeters: appData.meters.isEmpty == false, |
|
| 44 |
scanStartedAt: appData.bluetoothManager.scanStartedAt, |
|
| 45 |
now: now, |
|
| 46 |
noDevicesHelpDelay: noDevicesHelpDelay |
|
| 47 |
) |
|
| 48 |
} |
|
| 49 | ||
| 50 |
private var helpSection: some View {
|
|
| 51 |
SidebarHelpSectionView( |
|
| 52 |
activeReason: activeHelpAutoReason, |
|
| 53 |
isExpanded: helpIsExpanded, |
|
| 54 |
bluetoothStatusTint: appData.bluetoothManager.managerState.color, |
|
| 55 |
bluetoothStatusText: bluetoothStatusText, |
|
| 56 |
cloudSyncHelpTitle: appData.cloudAvailability.helpTitle, |
|
| 57 |
cloudSyncHelpMessage: appData.cloudAvailability.helpMessage, |
|
| 58 |
onToggle: toggleHelpSection, |
|
| 59 |
onOpenSettings: openSettings |
|
| 60 |
) {
|
|
| 61 |
appData.bluetoothManager.managerState.helpView |
|
| 62 |
} deviceHelpDestination: {
|
|
| 63 |
DeviceHelpView() |
|
| 64 |
} |
|
| 65 |
} |
|
| 66 | ||
| 67 |
private var debugSection: some View {
|
|
| 68 |
SidebarDebugSectionView() |
|
| 69 |
} |
|
| 70 | ||
| 71 |
private var bluetoothStatusText: String {
|
|
| 72 |
switch appData.bluetoothManager.managerState {
|
|
| 73 |
case .poweredOff: |
|
| 74 |
return "Off" |
|
| 75 |
case .poweredOn: |
|
| 76 |
return "On" |
|
| 77 |
case .resetting: |
|
| 78 |
return "Resetting" |
|
| 79 |
case .unauthorized: |
|
| 80 |
return "Unauthorized" |
|
| 81 |
case .unknown: |
|
| 82 |
return "Unknown" |
|
| 83 |
case .unsupported: |
|
| 84 |
return "Unsupported" |
|
| 85 |
@unknown default: |
|
| 86 |
return "Other" |
|
| 87 |
} |
|
| 88 |
} |
|
| 89 | ||
| 90 |
private var helpIsExpanded: Bool {
|
|
| 91 |
isHelpExpanded || shouldAutoExpandHelp |
|
| 92 |
} |
|
| 93 | ||
| 94 |
private var shouldAutoExpandHelp: Bool {
|
|
| 95 |
guard let activeHelpAutoReason else {
|
|
| 96 |
return false |
|
| 97 |
} |
|
| 98 |
return dismissedAutoHelpReason != activeHelpAutoReason |
|
| 99 |
} |
|
| 100 | ||
| 101 |
private var activeHelpAutoReason: SidebarHelpReason? {
|
|
| 102 |
SidebarAutoHelpResolver.activeReason( |
|
| 103 |
managerState: appData.bluetoothManager.managerState, |
|
| 104 |
cloudAvailability: appData.cloudAvailability, |
|
| 105 |
hasLiveMeters: appData.meters.isEmpty == false, |
|
| 106 |
scanStartedAt: appData.bluetoothManager.scanStartedAt, |
|
| 107 |
now: now, |
|
| 108 |
noDevicesHelpDelay: noDevicesHelpDelay |
|
| 109 |
) |
|
| 110 |
} |
|
| 111 | ||
| 112 |
private func toggleHelpSection() {
|
|
| 113 |
withAnimation(.easeInOut(duration: 0.22)) {
|
|
| 114 |
if shouldAutoExpandHelp {
|
|
| 115 |
dismissedAutoHelpReason = activeHelpAutoReason |
|
| 116 |
isHelpExpanded = false |
|
| 117 |
} else {
|
|
| 118 |
isHelpExpanded.toggle() |
|
| 119 |
} |
|
| 120 |
} |
|
| 121 |
} |
|
| 122 | ||
| 123 |
private func openSettings() {
|
|
| 124 |
guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else {
|
|
| 125 |
return |
|
| 126 |
} |
|
| 127 |
UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil) |
|
| 128 |
} |
|
| 129 |
} |