Merge lp:~dude-from-by/openlp/my-ios-remote into lp:~danielborges93/openlp/ios-remote
- my-ios-remote
- Merge into ios-remote
Proposed by
andrei
Status: | Superseded |
---|---|
Proposed branch: | lp:~dude-from-by/openlp/my-ios-remote |
Merge into: | lp:~danielborges93/openlp/ios-remote |
Diff against target: |
588 lines (+295/-48) 10 files modified
OLP RemoteTests/SettingsViewModelTests.swift (+77/-0) Podfile (+1/-0) Podfile.lock (+4/-1) Remote.xcodeproj/project.pbxproj (+14/-0) Remote/AppDelegate.swift (+11/-1) Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift (+2/-4) Remote/Classes/Controller/Settings/SettingsViewController.swift (+24/-40) Remote/Classes/Controller/Settings/SettingsViewModel.swift (+73/-0) Remote/Classes/Network/Service.swift (+4/-2) Remote/Classes/Util/CountlyClientSideUserPaths.swift (+85/-0) |
To merge this branch: | bzr merge lp:~dude-from-by/openlp/my-ios-remote |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Borges | Pending | ||
Review via email: mp+324113@code.launchpad.net |
This proposal has been superseded by a proposal from 2017-05-18.
Commit message
Description of the change
Moved SettingsViewCon
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'OLP RemoteTests/SettingsViewModelTests.swift' |
2 | --- OLP RemoteTests/SettingsViewModelTests.swift 1970-01-01 00:00:00 +0000 |
3 | +++ OLP RemoteTests/SettingsViewModelTests.swift 2017-05-18 14:03:54 +0000 |
4 | @@ -0,0 +1,77 @@ |
5 | +// |
6 | +// SettingsViewModelTests.swift |
7 | +// Remote |
8 | +// |
9 | +// Created by andrei shender on 5/16/17. |
10 | +// Copyright © 2017 OpenLP. All rights reserved. |
11 | +// |
12 | + |
13 | +import XCTest |
14 | +import InAppSettingsKit |
15 | + |
16 | +class SettingsViewModelTests: XCTestCase { |
17 | + |
18 | + func createModel() -> (defs: UserDefaults, sett: UserSettings, mod: SettingsViewModel) { |
19 | + let userDefaults = UserDefaults() |
20 | + let userSettings = UserSettings(defaults: userDefaults) |
21 | + let settingsViewModel = SettingsViewModel(settings: userSettings) |
22 | + return (userDefaults, userSettings, settingsViewModel) |
23 | + } |
24 | + |
25 | + func testNoAuth() { |
26 | + let (_, _, settingsViewModel) = createModel() |
27 | + XCTAssert(settingsViewModel.needAuth.value == false) |
28 | + } |
29 | + |
30 | + func testNoCrashNotificationWithoutUserInfo() { |
31 | + let (_, _, _) = createModel() |
32 | + NotificationCenter.default.post(Notification(name: NSNotification.Name(rawValue: kIASKAppSettingChanged), object: nil, userInfo: [:])) |
33 | + NotificationCenter.default.post(Notification(name: NSNotification.Name(rawValue: kIASKAppSettingChanged), object: nil, userInfo: nil)) |
34 | + } |
35 | + |
36 | + func testSettingNeedAuth() { |
37 | + let (_, _, settingsViewModel) = createModel() |
38 | + let userInfo = ["auth.needsAuth" : true] |
39 | + NotificationCenter.default.post(Notification(name: NSNotification.Name(rawValue: kIASKAppSettingChanged), object: nil, userInfo: userInfo)) |
40 | + XCTAssert(settingsViewModel.needAuth.value) |
41 | + } |
42 | + |
43 | + func testDismissWithEmptyServerIP() { |
44 | + let (userDefaults, _, settingsViewModel) = createModel() |
45 | + userDefaults.set("", forKey: "server.ip") |
46 | + settingsViewModel.dismiss() |
47 | + XCTAssert(settingsViewModel.alert.value.message == Localizable.Error.validIP) |
48 | + } |
49 | + |
50 | + func testDismissWithInvalidServerIP() { |
51 | + let (userDefaults, _, settingsViewModel) = createModel() |
52 | + userDefaults.set("±±±±", forKey: "server.ip") |
53 | + settingsViewModel.dismiss() |
54 | + XCTAssert(settingsViewModel.alert.value.message == Localizable.Error.validIP) |
55 | + } |
56 | + |
57 | + func testDismissWithNoServerPort() { |
58 | + let (userDefaults, _, settingsViewModel) = createModel() |
59 | + userDefaults.set("1", forKey: "server.ip") |
60 | + userDefaults.set("", forKey: "server.port") |
61 | + settingsViewModel.dismiss() |
62 | + XCTAssert(settingsViewModel.alert.value.message == Localizable.Error.validPort) |
63 | + } |
64 | + |
65 | + func testDismissWithInvalidServerPort() { |
66 | + let (userDefaults, _, settingsViewModel) = createModel() |
67 | + userDefaults.set("1", forKey: "server.ip") |
68 | + userDefaults.set("invalid", forKey: "server.port") |
69 | + settingsViewModel.dismiss() |
70 | + XCTAssert(settingsViewModel.alert.value.message == Localizable.Error.validPort) |
71 | + } |
72 | + |
73 | + func testDismiss() { |
74 | + let (userDefaults, _, settingsViewModel) = createModel() |
75 | + userDefaults.set("1", forKey: "server.ip") |
76 | + userDefaults.set("2", forKey: "server.port") |
77 | + settingsViewModel.dismiss() |
78 | + XCTAssert(settingsViewModel.alert.value.message == "") |
79 | + XCTAssert(settingsViewModel.dismissController.value) |
80 | + } |
81 | + } |
82 | |
83 | === modified file 'Podfile' |
84 | --- Podfile 2017-03-02 07:16:31 +0000 |
85 | +++ Podfile 2017-05-18 14:03:54 +0000 |
86 | @@ -12,6 +12,7 @@ |
87 | pod 'BlockLooper', :git=>'https://github.com/ashender/BlockLooper.git' |
88 | pod 'CWStatusBarNotification' |
89 | pod 'ReactiveCocoa' |
90 | + pod 'Countly' |
91 | end |
92 | |
93 | target 'OLP RemoteTests' do |
94 | |
95 | === modified file 'Podfile.lock' |
96 | --- Podfile.lock 2017-03-02 07:16:31 +0000 |
97 | +++ Podfile.lock 2017-05-18 14:03:54 +0000 |
98 | @@ -4,6 +4,7 @@ |
99 | - Alamofire (~> 4.1) |
100 | - ObjectMapper (~> 2.0) |
101 | - BlockLooper (0.0.3) |
102 | + - Countly (16.12) |
103 | - CWStatusBarNotification (2.3.5) |
104 | - InAppSettingsKit (2.8.1) |
105 | - Nimble (5.1.1) |
106 | @@ -35,6 +36,7 @@ |
107 | - Alamofire |
108 | - AlamofireObjectMapper |
109 | - BlockLooper (from `https://github.com/ashender/BlockLooper.git`) |
110 | + - Countly |
111 | - CWStatusBarNotification |
112 | - InAppSettingsKit |
113 | - Nimble |
114 | @@ -57,6 +59,7 @@ |
115 | Alamofire: 856a113053a7bc9cbe5d6367a555d773fc5cfef7 |
116 | AlamofireObjectMapper: 842d2eed43a4d0593ff0110d54ac86a170c4519c |
117 | BlockLooper: 8bba05fef76734e8e52e39412a0212ac3474776c |
118 | + Countly: 517a5c221463b29854e214b2193620690b5edb1a |
119 | CWStatusBarNotification: 3d2738b25c3207f60cc50201388d3c96182545ff |
120 | InAppSettingsKit: 94d2fba3ccd700fc4e32c6d09fabcc0af2426744 |
121 | Nimble: 415e3aa3267e7bc2c96b05fa814ddea7bb686a29 |
122 | @@ -68,6 +71,6 @@ |
123 | TPKeyboardAvoiding: 0d6af20e95e2850f4c621841225b59ec7d8dd852 |
124 | UITextView+Placeholder: 77680995fcdd07c3f52ec92fe1150874a2ac89ff |
125 | |
126 | -PODFILE CHECKSUM: 8bcb0a7a00d7e61acff50967f2778c47912a0880 |
127 | +PODFILE CHECKSUM: 315619d4b8576ea53bb0e33054782ee9669fb788 |
128 | |
129 | COCOAPODS: 1.1.1 |
130 | |
131 | === modified file 'Remote.xcodeproj/project.pbxproj' |
132 | --- Remote.xcodeproj/project.pbxproj 2017-04-05 15:55:26 +0000 |
133 | +++ Remote.xcodeproj/project.pbxproj 2017-05-18 14:03:54 +0000 |
134 | @@ -83,6 +83,10 @@ |
135 | 759464A51CEB8493001A56BF /* SettingsControllerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 759464A41CEB8493001A56BF /* SettingsControllerPresenter.swift */; }; |
136 | 759778AE1CF83AC400C2E4B4 /* APITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 759778AD1CF83AC400C2E4B4 /* APITest.swift */; }; |
137 | 75AF930F1E9297220051EB82 /* SearchResultsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755B3FE11E8CFEE000DA570C /* SearchResultsViewModel.swift */; }; |
138 | + 75BC63271ECDCAB500A21BF2 /* CountlyClientSideUserPaths.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75BC63261ECDCAB500A21BF2 /* CountlyClientSideUserPaths.swift */; }; |
139 | + 75C1BF671ECA1D9C00939F73 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75C1BF661ECA1D9C00939F73 /* SettingsViewModel.swift */; }; |
140 | + 75D100C61ECB2D0B00818402 /* SettingsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D100C51ECB2D0B00818402 /* SettingsViewModelTests.swift */; }; |
141 | + 75D100C71ECB2E0000818402 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75C1BF661ECA1D9C00939F73 /* SettingsViewModel.swift */; }; |
142 | 863574EB78CF355A8463055D /* Pods_Remote.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3194E32378DD6BB8E273BB47 /* Pods_Remote.framework */; }; |
143 | /* End PBXBuildFile section */ |
144 | |
145 | @@ -147,6 +151,9 @@ |
146 | 759778A31CF839C200C2E4B4 /* OLP RemoteTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "OLP RemoteTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; |
147 | 759778A71CF839C200C2E4B4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; |
148 | 759778AD1CF83AC400C2E4B4 /* APITest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APITest.swift; sourceTree = "<group>"; }; |
149 | + 75BC63261ECDCAB500A21BF2 /* CountlyClientSideUserPaths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CountlyClientSideUserPaths.swift; sourceTree = "<group>"; }; |
150 | + 75C1BF661ECA1D9C00939F73 /* SettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; }; |
151 | + 75D100C51ECB2D0B00818402 /* SettingsViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewModelTests.swift; sourceTree = "<group>"; }; |
152 | BF194B8FEA335C68D241C125 /* Pods-OLP RemoteTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OLP RemoteTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-OLP RemoteTests/Pods-OLP RemoteTests.release.xcconfig"; sourceTree = "<group>"; }; |
153 | /* End PBXFileReference section */ |
154 | |
155 | @@ -217,6 +224,7 @@ |
156 | children = ( |
157 | 759464A41CEB8493001A56BF /* SettingsControllerPresenter.swift */, |
158 | 462395801BE505EC00B90146 /* SettingsViewController.swift */, |
159 | + 75C1BF661ECA1D9C00939F73 /* SettingsViewModel.swift */, |
160 | ); |
161 | path = Settings; |
162 | sourceTree = "<group>"; |
163 | @@ -278,6 +286,7 @@ |
164 | 46A612301C78E75D00B61DC8 /* ColorUtil.swift */, |
165 | 46FD378E1C79867C00DED423 /* ErrorUtil.swift */, |
166 | 46753A9A1E593EAC007872C0 /* LocalizationUtil.swift */, |
167 | + 75BC63261ECDCAB500A21BF2 /* CountlyClientSideUserPaths.swift */, |
168 | ); |
169 | path = Util; |
170 | sourceTree = "<group>"; |
171 | @@ -367,6 +376,7 @@ |
172 | 750831BA1CFF594400CA9299 /* service_response.json */, |
173 | 750831BC1CFF597D00CA9299 /* slides_response.json */, |
174 | 757326FF1E8C06B7001E618B /* SearchViewModelTests.swift */, |
175 | + 75D100C51ECB2D0B00818402 /* SettingsViewModelTests.swift */, |
176 | ); |
177 | path = "OLP RemoteTests"; |
178 | sourceTree = "<group>"; |
179 | @@ -595,10 +605,12 @@ |
180 | 4623B6971C07BC2E007FFE2B /* SlidesViewController.swift in Sources */, |
181 | 46A9EED81BFD89DF00E8D520 /* ServiceAPI.swift in Sources */, |
182 | 46FD37871C7959EF00DED423 /* SearchAPI.swift in Sources */, |
183 | + 75C1BF671ECA1D9C00939F73 /* SettingsViewModel.swift in Sources */, |
184 | 4623B69C1C07C569007FFE2B /* ControllerAPI.swift in Sources */, |
185 | 463A91851C092E6B00D572E6 /* DictionaryUtil.swift in Sources */, |
186 | 462395831BE50C5A00B90146 /* ViewControllerUtil.swift in Sources */, |
187 | 46CC0CED1BE6972300423EB4 /* UserSettings.swift in Sources */, |
188 | + 75BC63271ECDCAB500A21BF2 /* CountlyClientSideUserPaths.swift in Sources */, |
189 | 46FD37891C796C9B00DED423 /* SearchResultViewController.swift in Sources */, |
190 | 463A918D1C093DD500D572E6 /* AlertsViewController.swift in Sources */, |
191 | 755B3FE21E8CFEE000DA570C /* SearchResultsViewModel.swift in Sources */, |
192 | @@ -636,6 +648,7 @@ |
193 | 75667B561CFEE949008FDFE0 /* ItemModel.swift in Sources */, |
194 | 75667B591CFEE949008FDFE0 /* LiveModel.swift in Sources */, |
195 | 75667B521CFEE938008FDFE0 /* AddAPI.swift in Sources */, |
196 | + 75D100C61ECB2D0B00818402 /* SettingsViewModelTests.swift in Sources */, |
197 | 75667B5C1CFEFF7E008FDFE0 /* DictionaryUtil.swift in Sources */, |
198 | 757327001E8C06B7001E618B /* SearchViewModelTests.swift in Sources */, |
199 | 75667B5E1CFEFF86008FDFE0 /* ErrorUtil.swift in Sources */, |
200 | @@ -648,6 +661,7 @@ |
201 | 757326FE1E8C060F001E618B /* LocalizationUtil.swift in Sources */, |
202 | 75667B5F1CFEFFA7008FDFE0 /* DisplayAPI.swift in Sources */, |
203 | 75667B4E1CFEE930008FDFE0 /* PollAPI.swift in Sources */, |
204 | + 75D100C71ECB2E0000818402 /* SettingsViewModel.swift in Sources */, |
205 | 75667B541CFEE93D008FDFE0 /* AlertAPI.swift in Sources */, |
206 | 75667B531CFEE938008FDFE0 /* Service.swift in Sources */, |
207 | 75667B291CFCA8C9008FDFE0 /* UserSettings.swift in Sources */, |
208 | |
209 | === modified file 'Remote/AppDelegate.swift' |
210 | --- Remote/AppDelegate.swift 2017-04-05 15:55:26 +0000 |
211 | +++ Remote/AppDelegate.swift 2017-05-18 14:03:54 +0000 |
212 | @@ -24,6 +24,7 @@ |
213 | |
214 | import UIKit |
215 | import BlockLooper |
216 | +import Countly |
217 | |
218 | @UIApplicationMain |
219 | class AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate, ServiceViewControllerDelegate { |
220 | @@ -42,9 +43,10 @@ |
221 | } |
222 | |
223 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { |
224 | - |
225 | + startAnalytics() |
226 | settings = UserSettings(defaults: UserDefaults.standard) |
227 | settings.registerDefaults() |
228 | + Countly.sharedInstance().applicationStartWithSettings(settings) |
229 | service = Service(settings: settings) |
230 | |
231 | var rootViewControllers = [UINavigationController]() |
232 | @@ -94,6 +96,14 @@ |
233 | useAnimator = false |
234 | } |
235 | |
236 | + func startAnalytics() { |
237 | + let config = CountlyConfig() |
238 | + config.appKey = "f057136e457a5d2da05c3b569a48caaee9a8644b" |
239 | + config.host = "https://stats.openlp.io" |
240 | + config.features = [CLYCrashReporting] |
241 | + Countly.sharedInstance().start(with: config) |
242 | + } |
243 | + |
244 | |
245 | // MARK: - ServiceViewControllerDelegate |
246 | func serviceViewControllerDidSelectItem(_ item: ItemModel) { |
247 | |
248 | === modified file 'Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift' |
249 | --- Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift 2017-02-05 02:25:57 +0000 |
250 | +++ Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift 2017-05-18 14:03:54 +0000 |
251 | @@ -26,13 +26,10 @@ |
252 | import UIKit |
253 | |
254 | class SettingsControllerPresenter: NSObject { |
255 | - |
256 | - let pollAPI: PollAPI |
257 | let settings: UserSettings |
258 | var fromController: UIViewController? |
259 | |
260 | init(settings: UserSettings, pollAPI: PollAPI) { |
261 | - self.pollAPI = pollAPI |
262 | self.settings = settings |
263 | super.init() |
264 | } |
265 | @@ -46,7 +43,8 @@ |
266 | |
267 | |
268 | func presentSettingViewController() { |
269 | - let settingsController = SettingsViewController(settings:settings, pollAPI: pollAPI) |
270 | + let settingsViewModel = SettingsViewModel(settings: settings) |
271 | + let settingsController = SettingsViewController(viewModel: settingsViewModel) |
272 | let navigationController = UINavigationController(rootViewController: settingsController) |
273 | guard let fromController = self.fromController else { return } |
274 | if #available(iOS 9.0, *) { |
275 | |
276 | === modified file 'Remote/Classes/Controller/Settings/SettingsViewController.swift' |
277 | --- Remote/Classes/Controller/Settings/SettingsViewController.swift 2017-02-19 05:21:00 +0000 |
278 | +++ Remote/Classes/Controller/Settings/SettingsViewController.swift 2017-05-18 14:03:54 +0000 |
279 | @@ -24,24 +24,37 @@ |
280 | |
281 | import UIKit |
282 | import InAppSettingsKit |
283 | +import Countly |
284 | |
285 | class SettingsViewController: IASKAppSettingsViewController { |
286 | |
287 | fileprivate let hiddenSettingsKeys = ["auth.userID" as NSObject, "auth.password" as NSObject] as Set<NSObject> |
288 | - fileprivate let pollAPI: PollAPI! |
289 | - fileprivate let settings: UserSettings! |
290 | + fileprivate let viewModel: SettingsViewModel? |
291 | |
292 | - init(settings: UserSettings, pollAPI: PollAPI) { |
293 | - self.pollAPI = pollAPI |
294 | - self.settings = settings |
295 | + init(viewModel: SettingsViewModel) { |
296 | + self.viewModel = viewModel |
297 | super.init(nibName:nil, bundle:nil) |
298 | + viewModel.needAuth.producer.startWithValues { (needAuth) in |
299 | + self.setHiddenKeys(needAuth ? [] : self.hiddenSettingsKeys, animated: true) |
300 | + self.synchronizeSettings() |
301 | + } |
302 | + |
303 | + viewModel.alert.producer.skip(first: 1).startWithValues { (alert) in |
304 | + UIAlertView(title: alert.title, message: alert.message, delegate: nil, cancelButtonTitle: "OK") |
305 | + .show() |
306 | + } |
307 | + |
308 | + viewModel.dismissController.producer.skip(first: 1).startWithValues { (shouldDismiss) in |
309 | + self.synchronizeSettings() |
310 | + self.dismiss(animated: true, completion: nil) |
311 | + } |
312 | + |
313 | self.setupSettingViewController() |
314 | self.setupNavigationBar() |
315 | } |
316 | |
317 | required init?(coder aDecoder: NSCoder) { |
318 | - self.pollAPI = nil |
319 | - self.settings = nil |
320 | + viewModel = nil |
321 | super.init(coder: aDecoder) |
322 | } |
323 | |
324 | @@ -53,55 +66,26 @@ |
325 | self.tableView.delegate = self |
326 | self.tableView.dataSource = self |
327 | } |
328 | - |
329 | + |
330 | // MARK: My methods |
331 | |
332 | fileprivate func setupSettingViewController() { |
333 | self.showDoneButton = false |
334 | self.showCreditsFooter = false |
335 | self.delegate = self |
336 | - |
337 | - let needsAuth = settings.needsAuth |
338 | - self.hiddenKeys = needsAuth ? [] : self.hiddenSettingsKeys |
339 | - |
340 | - NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.settingsDidChange(_:)), name: NSNotification.Name(rawValue: kIASKAppSettingChanged), object: nil) |
341 | - } |
342 | - |
343 | - @objc fileprivate func settingsDidChange(_ notification: Notification) { |
344 | - if let object = notification.userInfo { |
345 | - if object["auth.needsAuth"] != nil { |
346 | - let enabled = settings.needsAuth |
347 | - let hiddenKeys = enabled ? [] : self.hiddenSettingsKeys |
348 | - self.setHiddenKeys(hiddenKeys, animated: true) |
349 | - } |
350 | - } |
351 | + |
352 | } |
353 | |
354 | fileprivate func setupNavigationBar() { |
355 | self.navigationItem.title = Localizable.settings |
356 | - |
357 | let strSave = Localizable.ok |
358 | let btSave = UIBarButtonItem(title: strSave, style: .done, target: self, action: #selector(SettingsViewController.dismissViewController)) |
359 | self.navigationItem.rightBarButtonItem = btSave |
360 | } |
361 | - |
362 | + |
363 | @objc fileprivate func dismissViewController() { |
364 | - if !settings.validateServerIP() { |
365 | - let title = Localizable.error |
366 | - let message = Localizable.Error.validIP |
367 | - UIAlertView(title: title, message: message, delegate: nil, cancelButtonTitle: "OK") |
368 | - .show() |
369 | - } else if !settings.validateServerPort() { |
370 | - let title = Localizable.error |
371 | - let message = Localizable.Error.validPort |
372 | - UIAlertView(title: title, message: message, delegate: nil, cancelButtonTitle: "OK") |
373 | - .show() |
374 | - } else { |
375 | - self.synchronizeSettings() |
376 | - self.dismiss(animated: true, completion: nil) |
377 | - } |
378 | + viewModel?.dismiss() |
379 | } |
380 | - |
381 | } |
382 | |
383 | // MARK: - IASKSettingsDelegate |
384 | |
385 | === added file 'Remote/Classes/Controller/Settings/SettingsViewModel.swift' |
386 | --- Remote/Classes/Controller/Settings/SettingsViewModel.swift 1970-01-01 00:00:00 +0000 |
387 | +++ Remote/Classes/Controller/Settings/SettingsViewModel.swift 2017-05-18 14:03:54 +0000 |
388 | @@ -0,0 +1,73 @@ |
389 | +/****************************************************************************** |
390 | + * OpenLP iOS Remote * |
391 | + * --------------------------------------------------------------------------- * |
392 | + * Copyright (c) 2008-2016 OpenLP Developers * |
393 | + * --------------------------------------------------------------------------- * |
394 | + * Permission is hereby granted, free of charge, to any person obtaining a * |
395 | + * copy of this software and associated documentation files (the "Software"), * |
396 | + * to deal in the Software without restriction, including without limitation * |
397 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * |
398 | + * and/or sell copies of the Software, and to permit persons to whom the * |
399 | + * Software is furnished to do so, subject to the following conditions: * |
400 | + * * |
401 | + * The above copyright notice and this permission notice shall be included in * |
402 | + * all copies or substantial portions of the Software. * |
403 | + * * |
404 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * |
405 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * |
406 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * |
407 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * |
408 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * |
409 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * |
410 | + * DEALINGS IN THE SOFTWARE. * |
411 | + ******************************************************************************/ |
412 | + |
413 | + |
414 | +import UIKit |
415 | +import ReactiveCocoa |
416 | +import ReactiveSwift |
417 | +import InAppSettingsKit |
418 | +import Countly |
419 | + |
420 | +struct Alert { |
421 | + let title: String |
422 | + let message: String |
423 | +} |
424 | + |
425 | +class SettingsViewModel: NSObject { |
426 | + let needAuth: MutableProperty<Bool> |
427 | + let settings: UserSettings |
428 | + let alert: MutableProperty<Alert> = MutableProperty<Alert>(Alert(title: "", message: "")) |
429 | + let dismissController = MutableProperty<Bool>(false) |
430 | + |
431 | + init(settings: UserSettings) { |
432 | + self.needAuth = MutableProperty<Bool>(settings.needsAuth) |
433 | + self.settings = settings |
434 | + super.init() |
435 | + NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewModel.settingsDidChange(_:)), name: NSNotification.Name(rawValue: kIASKAppSettingChanged), object: nil) |
436 | + Countly.sharedInstance().settingsScreenOpenedWithUserSettings(settings) |
437 | + } |
438 | + |
439 | + @objc fileprivate func settingsDidChange(_ notification: Notification) { |
440 | + if let object = notification.userInfo, let needAuth = object["auth.needsAuth"] as? Bool { |
441 | + self.needAuth.value = needAuth |
442 | + } |
443 | + } |
444 | + |
445 | + func dismiss() { |
446 | + if !settings.validateServerIP() { |
447 | + let title = Localizable.error |
448 | + let message = Localizable.Error.validIP |
449 | + alert.value = Alert(title: title, message: message) |
450 | + } else if !settings.validateServerPort() { |
451 | + let title = Localizable.error |
452 | + let message = Localizable.Error.validPort |
453 | + alert.value = Alert(title: title, message: message) |
454 | + } else { |
455 | + dismissController.value = true |
456 | + if self.settings.serverIP.characters.count != 0 { |
457 | + Countly.sharedInstance().settingsScreenClosedWithUserSettings(settings) |
458 | + } |
459 | + } |
460 | + } |
461 | +} |
462 | |
463 | === modified file 'Remote/Classes/Network/Service.swift' |
464 | --- Remote/Classes/Network/Service.swift 2017-04-05 15:55:26 +0000 |
465 | +++ Remote/Classes/Network/Service.swift 2017-05-18 14:03:54 +0000 |
466 | @@ -27,6 +27,7 @@ |
467 | import Result |
468 | import ReactiveCocoa |
469 | import BlockLooper |
470 | +import Countly |
471 | |
472 | |
473 | protocol PollAPIServiceDelegate { |
474 | @@ -109,14 +110,14 @@ |
475 | |
476 | |
477 | pollSignal |
478 | - .filter({ (result) -> Bool in |
479 | + .filter() { (result) -> Bool in |
480 | switch result { |
481 | case .success: |
482 | return true |
483 | default: |
484 | return false |
485 | } |
486 | - }) |
487 | + } |
488 | .observe { (event) in |
489 | self.handlePollResponse((event.value?.value)!) |
490 | } |
491 | @@ -157,6 +158,7 @@ |
492 | |
493 | fileprivate func handlePollResponse(_ poll: PollModel?) { |
494 | if let poll = poll { |
495 | + Countly.sharedInstance().serverSentNonEmptyResponse() |
496 | if self.poll.service != poll.service { |
497 | self.updateService({ |
498 | self.serviceDelegate?.updateSelectedItem(itemId: poll.item) |
499 | |
500 | === added file 'Remote/Classes/Util/CountlyClientSideUserPaths.swift' |
501 | --- Remote/Classes/Util/CountlyClientSideUserPaths.swift 1970-01-01 00:00:00 +0000 |
502 | +++ Remote/Classes/Util/CountlyClientSideUserPaths.swift 2017-05-18 14:03:54 +0000 |
503 | @@ -0,0 +1,85 @@ |
504 | +/****************************************************************************** |
505 | + * OpenLP iOS Remote * |
506 | + * --------------------------------------------------------------------------- * |
507 | + * Copyright (c) 2008-2016 OpenLP Developers * |
508 | + * --------------------------------------------------------------------------- * |
509 | + * Permission is hereby granted, free of charge, to any person obtaining a * |
510 | + * copy of this software and associated documentation files (the "Software"), * |
511 | + * to deal in the Software without restriction, including without limitation * |
512 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * |
513 | + * and/or sell copies of the Software, and to permit persons to whom the * |
514 | + * Software is furnished to do so, subject to the following conditions: * |
515 | + * * |
516 | + * The above copyright notice and this permission notice shall be included in * |
517 | + * all copies or substantial portions of the Software. * |
518 | + * * |
519 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * |
520 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * |
521 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * |
522 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * |
523 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * |
524 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * |
525 | + * DEALINGS IN THE SOFTWARE. * |
526 | + ******************************************************************************/ |
527 | + |
528 | +import UIKit |
529 | +import Countly |
530 | + |
531 | +extension Countly { |
532 | + |
533 | + enum UserPathFirstExperienceState : String { |
534 | + case Started = "started" |
535 | + case SettingsOpenedWithEmptyServerAddress = "SettingsOpenedWithEmptyServerAddress" |
536 | + case SettingsClosedWithFilledServerAddress = "SettingsClosedWithFilledServerAddress" |
537 | + case GotNonEmptyResponseFromServer = "GotNonEmptyResponseFromServer" |
538 | + } |
539 | + |
540 | + static let firstExperiencePathStartedKey = "userPath_firstExperienceState" |
541 | + |
542 | + func applicationStartWithSettings(_ settings: UserSettings) { |
543 | + if firstExperiencePathState() == .none, settings.serverIP.characters.count == 0 { |
544 | + startFirstExperienceUserPath() |
545 | + type(of: self).sharedInstance().recordEvent("first app launch start with no server ip") |
546 | + } |
547 | + } |
548 | + |
549 | + func settingsScreenOpenedWithUserSettings(_ settings: UserSettings) { |
550 | + if let state = firstExperiencePathState(), state == .Started, settings.serverIP.characters.count == 0 { |
551 | + updateFirstExperiencePathState(newState: .SettingsOpenedWithEmptyServerAddress) |
552 | + type(of: self).sharedInstance().recordEvent("settings screen was opened without server ip filled") |
553 | + } |
554 | + } |
555 | + |
556 | + func settingsScreenClosedWithUserSettings(_ settings: UserSettings) { |
557 | + if let state = firstExperiencePathState(), state == .SettingsOpenedWithEmptyServerAddress, settings.serverIP.characters.count != 0 { |
558 | + updateFirstExperiencePathState(newState: .SettingsClosedWithFilledServerAddress) |
559 | + type(of: self).sharedInstance().recordEvent("settings screen was closed with server ip filled") |
560 | + } |
561 | + } |
562 | + |
563 | + func serverSentNonEmptyResponse() { |
564 | + if let state = firstExperiencePathState(), state == .SettingsClosedWithFilledServerAddress { |
565 | + updateFirstExperiencePathState(newState: .GotNonEmptyResponseFromServer) |
566 | + type(of: self).sharedInstance().recordEvent("received server response - setup complete") |
567 | + } |
568 | + } |
569 | + |
570 | + // MARK: private |
571 | + |
572 | + fileprivate func startFirstExperienceUserPath() { |
573 | + updateFirstExperiencePathState(newState: .Started) |
574 | + } |
575 | + |
576 | + fileprivate func firstExperiencePathState() -> UserPathFirstExperienceState? { |
577 | + if let state = UserDefaults.standard.object(forKey: type(of: self).firstExperiencePathStartedKey) as? String { |
578 | + return UserPathFirstExperienceState(rawValue:state) |
579 | + } |
580 | + else { |
581 | + return Optional.none |
582 | + } |
583 | + } |
584 | + |
585 | + fileprivate func updateFirstExperiencePathState(newState: UserPathFirstExperienceState) { |
586 | + UserDefaults.standard.set(newState.rawValue, forKey: type(of: self).firstExperiencePathStartedKey) |
587 | + } |
588 | +} |