-
Notifications
You must be signed in to change notification settings - Fork 16
/
SettingsView.swift
197 lines (159 loc) · 7.63 KB
/
SettingsView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import CioTracking
import SampleAppsCommon
import SwiftUI
import UIKit
struct SettingsView: View {
var siteId: String?
var apiKey: String?
var trackingUrl: String?
var done: () -> Void
@StateObject private var viewModel = ViewModel()
@State private var alertMessage: String?
@EnvironmentObject var userManager: UserManager
@State private var siteIdBeforeEditingSettings: String = ""
var body: some View {
ZStack {
BackButton {
done()
}
VStack(spacing: 5) {
HStack {
Text("Device token: ")
OneLineText(viewModel.pushToken)
Button(action: {
UIPasteboard.general.string = viewModel.pushToken
}) {
Image(systemName: "list.clipboard.fill").font(.system(size: 24))
}
}
Group {
LabeledStringTextField(title: "Tracking URL:", appiumId: "Track URL Input", value: $viewModel.settings.trackUrl)
.autocapitalization(.none)
LabeledStringTextField(title: "Site id:", appiumId: "Site ID Input", value: $viewModel.settings.siteId)
LabeledStringTextField(title: "API key:", appiumId: "API Key Input", value: $viewModel.settings.apiKey)
LabeledTimeIntervalTextField(title: "BQ seconds delay:", appiumId: nil, value: $viewModel.settings.bqSecondsDelay)
LabeledIntTextField(title: "BQ min number tasks:", appiumId: nil, value: $viewModel.settings.bqMinNumberTasks)
SettingsToggle(title: "Track screens", appiumId: "Track Screens Toggle", isOn: $viewModel.settings.trackScreens)
SettingsToggle(title: "Track device attributes", appiumId: "Track Device Attributes Toggle", isOn: $viewModel.settings.trackDeviceAttributes)
SettingsToggle(title: "Debug mode", appiumId: "Debug Mode Toggle", isOn: $viewModel.settings.debugSdkMode)
}
ColorButton("Save") {
hideKeyboard() // makes all textfields lose focus so that @State variables are up-to-date with the textfield values.
guard viewModel.settings.bqSecondsDelay > 0 else {
alertMessage = "BQ seconds delay must be > 0"
return
}
guard viewModel.settings.bqMinNumberTasks > 0 else {
alertMessage = "BQ min number tasks must be > 0"
return
}
guard verifyTrackUrl() else {
return
}
viewModel.saveSettings()
// Re-initialize the SDK to make the config changes go into place immediately
CustomerIO.initialize(siteId: viewModel.settings.siteId, apiKey: viewModel.settings.apiKey, region: .US) { config in
viewModel.settings.configureCioSdk(config: &config)
}
let didChangeSiteId = siteIdBeforeEditingSettings != viewModel.settings.siteId
if didChangeSiteId { // if siteid changed, we need to re-identify for the Customer.io SDK to get into a working state.
userManager.logout()
}
done()
}.setAppiumId("Save Settings Button")
Button("Restore default settings") {
viewModel.restoreDefaultSettings()
}.setAppiumId("Restore Default Settings Button")
}
.padding([.leading, .trailing], 10)
.onAppear {
siteIdBeforeEditingSettings = CustomerIO.shared.siteId!
// If parameters were passed into this View's constructor, updating the VM now will update the UI.
if let siteId = siteId {
viewModel.settings.siteId = siteId
}
if let apiKey = apiKey {
viewModel.settings.apiKey = apiKey
}
if let trackingUrl = trackingUrl {
viewModel.settings.trackUrl = trackingUrl
}
// Automatic screen view tracking in the Customer.io SDK does not work with SwiftUI apps (only UIKit apps).
// Therefore, this is how we can perform manual screen view tracking.
CustomerIO.shared.screen(name: "Settings")
}
.alert(isPresented: .notNil(alertMessage)) {
Alert(
title: Text("Error"),
message: Text(alertMessage!),
dismissButton: .default(Text("OK")) {
alertMessage = nil
}
)
}
}
}
private func verifyTrackUrl() -> Bool {
let enteredUrl = viewModel.settings.trackUrl
guard !enteredUrl.isEmpty else {
alertMessage = "Tracking URL is empty. Therefore, I cannot save the settings."
return false
}
guard let url = URL(string: enteredUrl) else {
alertMessage = "Tracking URL, \(enteredUrl), is not a valid URL. Therefore, I cannot save the settings."
return false
}
guard url.scheme != nil, url.scheme == "https" || url.scheme == "http" else {
alertMessage = "Tracking URL, \(enteredUrl), does not start with https or http. Therefore, I cannot save the settings."
return false
}
guard url.host != nil, !url.host!.isEmpty else {
alertMessage = "Tracking URL, \(enteredUrl), does not contain a domain name. Therefore, I cannot save the settings."
return false
}
// Auto-fix this instead of making the user fix it.
let urlEndsWithTrailingSlash = url.absoluteString.hasSuffix("/")
if !urlEndsWithTrailingSlash {
viewModel.settings.trackUrl += "/"
}
return true
}
class ViewModel: ObservableObject {
@Published var settings: CioSettings
@Published var pushToken: String
private let settingsManager: CioSettingsManager
private let keyValueStorage: KeyValueStore
init() {
self.settingsManager = CioSettingsManager()
self.keyValueStorage = KeyValueStore()
self.pushToken = CustomerIO.shared.registeredDeviceToken ?? "(none)"
self.settings = settingsManager.appSetSettings ?? CioSettings.getFromCioSdk()
}
func saveSettings() {
settingsManager.appSetSettings = settings
}
func restoreDefaultSettings() {
settingsManager.appSetSettings = nil // remove app overriden settings from device memory
// restore the siteid and apikey used at compile-time as defaults.
// Do this before reading the app settings from the SDK so that the correct siteid and apikey are read.
CustomerIO.initialize(siteId: BuildEnvironment.CustomerIO.siteId, apiKey: BuildEnvironment.CustomerIO.apiKey, region: .US) { _ in }
settings = CioSettings.getFromCioSdk() // Now that the SDK has default configuration back, refresh UI
}
}
}
struct SettingsToggle: View {
let title: String
let appiumId: String?
@Binding var isOn: Bool
var body: some View {
HStack {
Text(title)
Toggle("", isOn: $isOn).setAppiumId(appiumId)
}
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView {}
}
}