USB-Meter / USB Meter / Views / Meter / MeterSettingsView.swift
Newer Older
257 lines | 8.691kb
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
17

            
Bogdan Timofte authored 2 weeks ago
18
    @State private var editingName = false
19
    @State private var editingScreenTimeout = false
20
    @State private var editingScreenBrightness = false
21

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

            
Bogdan Timofte authored 2 weeks ago
43
                if meter.operationalState == .dataIsAvailable && meter.supportsManualTemperatureUnitSelection {
Bogdan Timofte authored 2 weeks ago
44
                    settingsCard(title: "Meter Temperature Unit", tint: .orange) {
45
                        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
46
                            .font(.footnote)
47
                            .foregroundColor(.secondary)
48
                        Picker("", selection: $meter.tc66TemperatureUnitPreference) {
49
                            ForEach(TemperatureUnitPreference.allCases) { unit in
50
                                Text(unit.title).tag(unit)
51
                            }
52
                        }
53
                        .pickerStyle(SegmentedPickerStyle())
54
                    }
Bogdan Timofte authored 2 weeks ago
55
                }
Bogdan Timofte authored 2 weeks ago
56

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

            
72
                        ControlView(showsHeader: false)
73
                    }
74
                }
75

            
Bogdan Timofte authored 2 weeks ago
76
                if meter.operationalState == .dataIsAvailable && meter.supportsUMSettings {
Bogdan Timofte authored 2 weeks ago
77
                    settingsCard(title: "Screen Timeout", tint: .purple) {
Bogdan Timofte authored 2 weeks ago
78
                        HStack {
79
                            Spacer()
80
                            if !editingScreenTimeout {
Bogdan Timofte authored 2 weeks ago
81
                                Text(meter.screenTimeout != 0 ? "\(meter.screenTimeout) Minutes" : "Off")
82
                                    .foregroundColor(.secondary)
Bogdan Timofte authored 2 weeks ago
83
                            }
Bogdan Timofte authored 2 weeks ago
84
                            ChevronView(rotate: $editingScreenTimeout)
Bogdan Timofte authored 2 weeks ago
85
                        }
86
                        if editingScreenTimeout {
87
                            EditScreenTimeoutView()
88
                        }
89
                    }
Bogdan Timofte authored 2 weeks ago
90

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

            
123
    // MARK: - Custom navigation header for Designed-for-iPad on Mac
124

            
125
    private var macSettingsHeader: some View {
126
        HStack(spacing: 12) {
127
            Button {
128
                dismiss()
129
            } label: {
130
                HStack(spacing: 4) {
131
                    Image(systemName: "chevron.left")
132
                        .font(.body.weight(.semibold))
133
                    Text("Back")
134
                }
135
                .foregroundColor(.accentColor)
136
            }
137
            .buttonStyle(.plain)
138

            
139
            Text("Meter Settings")
140
                .font(.headline)
141
                .lineLimit(1)
142

            
143
            Spacer()
144

            
145
            if meter.operationalState > .notPresent {
146
                RSSIView(RSSI: meter.btSerial.averageRSSI)
147
                    .frame(width: 18, height: 18)
148
            }
149
        }
150
        .padding(.horizontal, 16)
151
        .padding(.vertical, 10)
152
        .background(
153
            Rectangle()
154
                .fill(.ultraThinMaterial)
155
                .ignoresSafeArea(edges: .top)
156
        )
157
        .overlay(alignment: .bottom) {
158
            Rectangle()
159
                .fill(Color.secondary.opacity(0.12))
160
                .frame(height: 1)
161
        }
Bogdan Timofte authored 2 weeks ago
162
    }
Bogdan Timofte authored 2 weeks ago
163

            
164
    private func settingsCard<Content: View>(
165
        title: String,
166
        tint: Color,
167
        @ViewBuilder content: () -> Content
168
    ) -> some View {
169
        VStack(alignment: .leading, spacing: 12) {
170
            Text(title)
171
                .font(.headline)
172
            content()
173
        }
174
        .padding(18)
175
        .meterCard(tint: tint, fillOpacity: 0.18, strokeOpacity: 0.24)
176
    }
Bogdan Timofte authored 2 weeks ago
177
}
178

            
179
struct EditNameView: View {
180

            
181
    @EnvironmentObject private var meter: Meter
182

            
183
    @Binding var editingName: Bool
184
    @State var newName: String
185

            
186
    var body: some View {
187
        TextField("Name", text: self.$newName, onCommit: {
188
            self.meter.name = self.newName
189
            self.editingName = false
190
        })
191
            .textFieldStyle(RoundedBorderTextFieldStyle())
192
            .lineLimit(1)
193
            .disableAutocorrection(true)
194
            .multilineTextAlignment(.center)
195
    }
196
}
197

            
198
struct EditScreenTimeoutView: View {
199

            
200
    @EnvironmentObject private var meter: Meter
201

            
202
    var body: some View {
203
        Picker("", selection: self.$meter.screenTimeout ) {
204
            Text("1").tag(1)
205
            Text("2").tag(2)
206
            Text("3").tag(3)
207
            Text("4").tag(4)
208
            Text("5").tag(5)
209
            Text("6").tag(6)
210
            Text("7").tag(7)
211
            Text("8").tag(8)
212
            Text("9").tag(9)
213
            Text("Off").tag(0)
214
        }
215
        .pickerStyle( SegmentedPickerStyle() )
216
    }
217
}
218

            
219
struct EditScreenBrightnessView: View {
220

            
221
    @EnvironmentObject private var meter: Meter
222

            
223
    var body: some View {
224
        Picker("", selection: self.$meter.screenBrightness ) {
225
            Text("0").tag(0)
226
            Text("1").tag(1)
227
            Text("2").tag(2)
228
            Text("3").tag(3)
229
            Text("4").tag(4)
230
            Text("5").tag(5)
231
        }
232
        .pickerStyle( SegmentedPickerStyle() )
233
    }
234
}
Bogdan Timofte authored 2 weeks ago
235

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

            
238
private struct IOSOnlySettingsNavBar: ViewModifier {
239
    let apply: Bool
240
    let rssi: Int
241

            
242
    @ViewBuilder
243
    func body(content: Content) -> some View {
244
        if apply {
245
            content
246
                .navigationBarTitle("Meter Settings")
247
                .toolbar {
248
                    ToolbarItem(placement: .navigationBarTrailing) {
249
                        RSSIView(RSSI: rssi).frame(width: 18, height: 18)
250
                    }
251
                }
252
        } else {
253
            content
254
                .navigationBarHidden(true)
255
        }
256
    }
257
}