Newer Older
185 lines | 5.924kb
Bogdan Timofte authored 2 months ago
1
//
2
//  SidebarView.swift
3
//  USB Meter
4
//
5

            
6
import SwiftUI
7
import Combine
8

            
Bogdan Timofte authored a month ago
9
private enum SidebarCreationSheet: Identifiable {
10
    case meter
11
    case device
12
    case charger
13

            
14
    var id: String {
15
        switch self {
16
        case .meter:
17
            return "meter"
18
        case .device:
19
            return "device"
20
        case .charger:
21
            return "charger"
22
        }
23
    }
24
}
25

            
Bogdan Timofte authored 2 months ago
26
struct SidebarView: View {
27
    @EnvironmentObject private var appData: AppData
28
    @State private var isHelpExpanded = false
29
    @State private var dismissedAutoHelpReason: SidebarHelpReason?
30
    @State private var now = Date()
Bogdan Timofte authored a month ago
31
    @State private var creationSheet: SidebarCreationSheet?
Bogdan Timofte authored 2 months ago
32
    private let helpRefreshTimer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
33
    private let noDevicesHelpDelay: TimeInterval = 12
34

            
35
    var body: some View {
36
        SidebarListView(backgroundTint: appData.bluetoothManager.managerState.color) {
37
            usbMetersSection
38
        } helpSection: {
39
            helpSection
40
        } debugSection: {
41
            debugSection
42
        }
43
        .onAppear {
44
            appData.bluetoothManager.start()
45
            now = Date()
46
        }
47
        .onReceive(helpRefreshTimer) { currentDate in
48
            now = currentDate
49
        }
50
        .onChange(of: activeHelpAutoReason) { newReason in
51
            if newReason == nil {
52
                dismissedAutoHelpReason = nil
53
            }
54
        }
Bogdan Timofte authored a month ago
55
        .sheet(item: $creationSheet) { sheet in
56
            switch sheet {
57
            case .meter:
58
                MeterEditorSheetView()
59
                    .environmentObject(appData)
60
            case .device:
61
                ChargedDeviceEditorSheetView(
62
                    meterMACAddress: nil,
Bogdan Timofte authored a month ago
63
                    kind: .device
Bogdan Timofte authored a month ago
64
                )
65
                .environmentObject(appData)
66
            case .charger:
67
                ChargedDeviceEditorSheetView(
68
                    meterMACAddress: nil,
Bogdan Timofte authored a month ago
69
                    kind: .charger
Bogdan Timofte authored a month ago
70
                )
71
                .environmentObject(appData)
72
            }
73
        }
Bogdan Timofte authored 2 months ago
74
    }
75

            
76
    private var usbMetersSection: some View {
Bogdan Timofte authored a month ago
77
        Group {
78
            SidebarUSBMetersSectionView(
79
                meters: appData.meterSummaries,
80
                managerState: appData.bluetoothManager.managerState,
81
                hasLiveMeters: appData.meters.isEmpty == false,
82
                scanStartedAt: appData.bluetoothManager.scanStartedAt,
83
                now: now,
84
                noDevicesHelpDelay: noDevicesHelpDelay,
85
                onAddMeter: { creationSheet = .meter }
86
            )
87

            
88
            SidebarChargedDevicesSectionView(
89
                title: "Devices",
90
                chargedDevices: appData.deviceSummaries,
91
                emptyStateText: "No devices yet. Open Charge Record on a live meter or use the add button here to create one and start learning capacity.",
92
                tint: .orange,
93
                onAdd: { creationSheet = .device }
94
            )
95

            
96
            SidebarChargedDevicesSectionView(
97
                title: "Chargers",
98
                chargedDevices: appData.chargerSummaries,
99
                emptyStateText: "No chargers yet. Add one here so wireless sessions can track both the charged device and the charger being used.",
100
                tint: .pink,
101
                onAdd: { creationSheet = .charger }
102
            )
103
        }
Bogdan Timofte authored 2 months ago
104
    }
105

            
106
    private var helpSection: some View {
107
        SidebarHelpSectionView(
108
            activeReason: activeHelpAutoReason,
109
            isExpanded: helpIsExpanded,
110
            bluetoothStatusTint: appData.bluetoothManager.managerState.color,
111
            bluetoothStatusText: bluetoothStatusText,
112
            cloudSyncHelpTitle: appData.cloudAvailability.helpTitle,
113
            cloudSyncHelpMessage: appData.cloudAvailability.helpMessage,
114
            onToggle: toggleHelpSection,
115
            onOpenSettings: openSettings
116
        ) {
117
            appData.bluetoothManager.managerState.helpView
118
        } deviceHelpDestination: {
119
            DeviceHelpView()
120
        }
121
    }
122

            
123
    private var debugSection: some View {
124
        SidebarDebugSectionView()
125
    }
126

            
127
    private var bluetoothStatusText: String {
128
        switch appData.bluetoothManager.managerState {
129
        case .poweredOff:
130
            return "Off"
131
        case .poweredOn:
132
            return "On"
133
        case .resetting:
134
            return "Resetting"
135
        case .unauthorized:
136
            return "Unauthorized"
137
        case .unknown:
138
            return "Unknown"
139
        case .unsupported:
140
            return "Unsupported"
141
        @unknown default:
142
            return "Other"
143
        }
144
    }
145

            
146
    private var helpIsExpanded: Bool {
147
        isHelpExpanded || shouldAutoExpandHelp
148
    }
149

            
150
    private var shouldAutoExpandHelp: Bool {
151
        guard let activeHelpAutoReason else {
152
            return false
153
        }
154
        return dismissedAutoHelpReason != activeHelpAutoReason
155
    }
156

            
157
    private var activeHelpAutoReason: SidebarHelpReason? {
158
        SidebarAutoHelpResolver.activeReason(
159
            managerState: appData.bluetoothManager.managerState,
160
            cloudAvailability: appData.cloudAvailability,
161
            hasLiveMeters: appData.meters.isEmpty == false,
162
            scanStartedAt: appData.bluetoothManager.scanStartedAt,
163
            now: now,
164
            noDevicesHelpDelay: noDevicesHelpDelay
165
        )
166
    }
167

            
168
    private func toggleHelpSection() {
169
        withAnimation(.easeInOut(duration: 0.22)) {
170
            if shouldAutoExpandHelp {
171
                dismissedAutoHelpReason = activeHelpAutoReason
172
                isHelpExpanded = false
173
            } else {
174
                isHelpExpanded.toggle()
175
            }
176
        }
177
    }
178

            
179
    private func openSettings() {
180
        guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else {
181
            return
182
        }
183
        UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
184
    }
185
}