USB-Meter / USB Meter / Views / Meter / MeterSettingsView.swift
Newer Older
264 lines | 8.889kb
Bogdan Timofte authored 2 weeks ago
1
//
2
//  SettingsView.swift
3
//  USB Meter
4
//
5
//  Created by Bogdan Timofte on 14/03/2020.
6
//  Copyright © 2020 Bogdan Timofte. All rights reserved.
7
//
8

            
9
import SwiftUI
10

            
11
struct MeterSettingsView: View {
12

            
13
    @EnvironmentObject private var meter: Meter
Bogdan Timofte authored 2 weeks ago
14
    @Environment(\.dismiss) private var dismiss
15

            
16
    private static let isMacIPadApp: Bool = ProcessInfo.processInfo.isiOSAppOnMac
Bogdan Timofte authored a week ago
17
    private static let isCatalyst: Bool = {
18
        #if targetEnvironment(macCatalyst)
19
        return true
20
        #else
21
        return false
22
        #endif
23
    }()
Bogdan Timofte authored 2 weeks ago
24

            
Bogdan Timofte authored 2 weeks ago
25
    @State private var editingName = false
26
    @State private var editingScreenTimeout = false
27
    @State private var editingScreenBrightness = false
28

            
29
    var body: some View {
Bogdan Timofte authored 2 weeks ago
30
        VStack(spacing: 0) {
31
            if Self.isMacIPadApp {
32
                macSettingsHeader
33
            }
34
            ScrollView {
Bogdan Timofte authored 2 weeks ago
35
            VStack (spacing: 14) {
36
                settingsCard(title: "Name", tint: meter.color) {
Bogdan Timofte authored 2 weeks ago
37
                    HStack {
38
                        Spacer()
39
                        if !editingName {
40
                            Text(meter.name)
Bogdan Timofte authored 2 weeks ago
41
                                .foregroundColor(.secondary)
Bogdan Timofte authored 2 weeks ago
42
                        }
Bogdan Timofte authored 2 weeks ago
43
                        ChevronView(rotate: $editingName)
Bogdan Timofte authored 2 weeks ago
44
                    }
45
                    if editingName {
46
                        EditNameView(editingName: $editingName, newName: meter.name)
47
                    }
48
                }
Bogdan Timofte authored 2 weeks ago
49

            
Bogdan Timofte authored 2 weeks ago
50
                if meter.operationalState == .dataIsAvailable && meter.supportsManualTemperatureUnitSelection {
Bogdan Timofte authored 2 weeks ago
51
                    settingsCard(title: "Meter Temperature Unit", tint: .orange) {
52
                        Text("TC66 temperature is shown as degrees without assuming Celsius or Fahrenheit. Keep this matched to the unit configured on the device so you can interpret the reading correctly.")
Bogdan Timofte authored 2 weeks ago
53
                            .font(.footnote)
54
                            .foregroundColor(.secondary)
55
                        Picker("", selection: $meter.tc66TemperatureUnitPreference) {
56
                            ForEach(TemperatureUnitPreference.allCases) { unit in
57
                                Text(unit.title).tag(unit)
58
                            }
59
                        }
60
                        .pickerStyle(SegmentedPickerStyle())
61
                    }
Bogdan Timofte authored 2 weeks ago
62
                }
Bogdan Timofte authored 2 weeks ago
63

            
Bogdan Timofte authored 2 weeks ago
64
                if meter.operationalState == .dataIsAvailable {
65
                    settingsCard(
66
                        title: meter.reportsCurrentScreenIndex ? "Screen Controls" : "Page Controls",
67
                        tint: .indigo
68
                    ) {
69
                        if meter.reportsCurrentScreenIndex {
70
                            Text("Use these controls when you want to change the screen shown on the device without crowding the main meter view.")
71
                                .font(.footnote)
72
                                .foregroundColor(.secondary)
73
                        } else {
74
                            Text("Use these controls when you want to switch device pages without crowding the main meter view.")
75
                                .font(.footnote)
76
                                .foregroundColor(.secondary)
77
                        }
78

            
79
                        ControlView(showsHeader: false)
80
                    }
81
                }
82

            
Bogdan Timofte authored 2 weeks ago
83
                if meter.operationalState == .dataIsAvailable && meter.supportsUMSettings {
Bogdan Timofte authored 2 weeks ago
84
                    settingsCard(title: "Screen Timeout", tint: .purple) {
Bogdan Timofte authored 2 weeks ago
85
                        HStack {
86
                            Spacer()
87
                            if !editingScreenTimeout {
Bogdan Timofte authored 2 weeks ago
88
                                Text(meter.screenTimeout != 0 ? "\(meter.screenTimeout) Minutes" : "Off")
89
                                    .foregroundColor(.secondary)
Bogdan Timofte authored 2 weeks ago
90
                            }
Bogdan Timofte authored 2 weeks ago
91
                            ChevronView(rotate: $editingScreenTimeout)
Bogdan Timofte authored 2 weeks ago
92
                        }
93
                        if editingScreenTimeout {
94
                            EditScreenTimeoutView()
95
                        }
96
                    }
Bogdan Timofte authored 2 weeks ago
97

            
98
                    settingsCard(title: "Screen Brightness", tint: .yellow) {
Bogdan Timofte authored 2 weeks ago
99
                        HStack {
100
                            Spacer()
101
                            if !editingScreenBrightness {
Bogdan Timofte authored 2 weeks ago
102
                                Text("\(meter.screenBrightness)")
103
                                    .foregroundColor(.secondary)
Bogdan Timofte authored 2 weeks ago
104
                            }
Bogdan Timofte authored 2 weeks ago
105
                            ChevronView(rotate: $editingScreenBrightness)
Bogdan Timofte authored 2 weeks ago
106
                        }
107
                        if editingScreenBrightness {
108
                            EditScreenBrightnessView()
109
                        }
110
                    }
111
                }
112
            }
Bogdan Timofte authored 2 weeks ago
113
            .padding()
Bogdan Timofte authored 2 weeks ago
114
        }
Bogdan Timofte authored 2 weeks ago
115
        .background(
116
            LinearGradient(
117
                colors: [meter.color.opacity(0.14), Color.clear],
118
                startPoint: .topLeading,
119
                endPoint: .bottomTrailing
120
            )
121
            .ignoresSafeArea()
122
        )
Bogdan Timofte authored 2 weeks ago
123
        }
124
        .modifier(IOSOnlySettingsNavBar(
Bogdan Timofte authored a week ago
125
            apply: !Self.isMacIPadApp && !Self.isCatalyst,
Bogdan Timofte authored 2 weeks ago
126
            rssi: meter.btSerial.averageRSSI
127
        ))
128
    }
129

            
130
    // MARK: - Custom navigation header for Designed-for-iPad on Mac
131

            
132
    private var macSettingsHeader: some View {
133
        HStack(spacing: 12) {
134
            Button {
135
                dismiss()
136
            } label: {
137
                HStack(spacing: 4) {
138
                    Image(systemName: "chevron.left")
139
                        .font(.body.weight(.semibold))
140
                    Text("Back")
141
                }
142
                .foregroundColor(.accentColor)
143
            }
144
            .buttonStyle(.plain)
145

            
146
            Text("Meter Settings")
147
                .font(.headline)
148
                .lineLimit(1)
149

            
150
            Spacer()
151

            
Bogdan Timofte authored a week ago
152
            if meter.operationalState >= .peripheralNotConnected {
Bogdan Timofte authored 2 weeks ago
153
                RSSIView(RSSI: meter.btSerial.averageRSSI)
154
                    .frame(width: 18, height: 18)
155
            }
156
        }
157
        .padding(.horizontal, 16)
158
        .padding(.vertical, 10)
159
        .background(
160
            Rectangle()
161
                .fill(.ultraThinMaterial)
162
                .ignoresSafeArea(edges: .top)
163
        )
164
        .overlay(alignment: .bottom) {
165
            Rectangle()
166
                .fill(Color.secondary.opacity(0.12))
167
                .frame(height: 1)
168
        }
Bogdan Timofte authored 2 weeks ago
169
    }
Bogdan Timofte authored 2 weeks ago
170

            
171
    private func settingsCard<Content: View>(
172
        title: String,
173
        tint: Color,
174
        @ViewBuilder content: () -> Content
175
    ) -> some View {
176
        VStack(alignment: .leading, spacing: 12) {
177
            Text(title)
178
                .font(.headline)
179
            content()
180
        }
181
        .padding(18)
182
        .meterCard(tint: tint, fillOpacity: 0.18, strokeOpacity: 0.24)
183
    }
Bogdan Timofte authored 2 weeks ago
184
}
185

            
186
struct EditNameView: View {
187

            
188
    @EnvironmentObject private var meter: Meter
189

            
190
    @Binding var editingName: Bool
191
    @State var newName: String
192

            
193
    var body: some View {
194
        TextField("Name", text: self.$newName, onCommit: {
195
            self.meter.name = self.newName
196
            self.editingName = false
197
        })
198
            .textFieldStyle(RoundedBorderTextFieldStyle())
199
            .lineLimit(1)
200
            .disableAutocorrection(true)
201
            .multilineTextAlignment(.center)
202
    }
203
}
204

            
205
struct EditScreenTimeoutView: View {
206

            
207
    @EnvironmentObject private var meter: Meter
208

            
209
    var body: some View {
210
        Picker("", selection: self.$meter.screenTimeout ) {
211
            Text("1").tag(1)
212
            Text("2").tag(2)
213
            Text("3").tag(3)
214
            Text("4").tag(4)
215
            Text("5").tag(5)
216
            Text("6").tag(6)
217
            Text("7").tag(7)
218
            Text("8").tag(8)
219
            Text("9").tag(9)
220
            Text("Off").tag(0)
221
        }
222
        .pickerStyle( SegmentedPickerStyle() )
223
    }
224
}
225

            
226
struct EditScreenBrightnessView: View {
227

            
228
    @EnvironmentObject private var meter: Meter
229

            
230
    var body: some View {
231
        Picker("", selection: self.$meter.screenBrightness ) {
232
            Text("0").tag(0)
233
            Text("1").tag(1)
234
            Text("2").tag(2)
235
            Text("3").tag(3)
236
            Text("4").tag(4)
237
            Text("5").tag(5)
238
        }
239
        .pickerStyle( SegmentedPickerStyle() )
240
    }
241
}
Bogdan Timofte authored 2 weeks ago
242

            
243
// MARK: - Conditional navigation bar modifier (skipped on Designed-for-iPad / Mac)
244

            
245
private struct IOSOnlySettingsNavBar: ViewModifier {
246
    let apply: Bool
247
    let rssi: Int
248

            
249
    @ViewBuilder
250
    func body(content: Content) -> some View {
251
        if apply {
252
            content
253
                .navigationBarTitle("Meter Settings")
254
                .toolbar {
255
                    ToolbarItem(placement: .navigationBarTrailing) {
256
                        RSSIView(RSSI: rssi).frame(width: 18, height: 18)
257
                    }
258
                }
259
        } else {
260
            content
261
                .navigationBarHidden(true)
262
        }
263
    }
264
}