Merge lp:~dude-from-by/openlp/my-ios-remote into lp:~danielborges93/openlp/ios-remote

Proposed by andrei
Status: Merged
Approved by: Daniel Borges
Approved revision: no longer in the source branch.
Merged at revision: 55
Proposed branch: lp:~dude-from-by/openlp/my-ios-remote
Merge into: lp:~danielborges93/openlp/ios-remote
Diff against target: 2700 lines (+749/-489)
42 files modified
OLP RemoteTests/APITest.swift (+1/-1)
OLP RemoteTests/PollAPITests.swift (+12/-12)
OLP RemoteTests/TestUtils.swift (+3/-3)
Podfile (+6/-2)
Podfile.lock (+44/-35)
Remote.xcodeproj/project.pbxproj (+24/-21)
Remote/AppDelegate.swift (+44/-11)
Remote/Classes/Controller/Alerts/AlertsViewController.swift (+36/-36)
Remote/Classes/Controller/Search/SearchResultViewController.swift (+26/-26)
Remote/Classes/Controller/Search/SearchViewController.swift (+33/-33)
Remote/Classes/Controller/Service/ServiceViewController.swift (+40/-35)
Remote/Classes/Controller/Service/ServiceViewController.xib (+13/-9)
Remote/Classes/Controller/Service/ServiceViewControllerDelegate.swift (+29/-0)
Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift (+3/-3)
Remote/Classes/Controller/Settings/SettingsViewController.swift (+14/-24)
Remote/Classes/Controller/Slides/SlidesViewController.swift (+54/-44)
Remote/Classes/Controller/Slides/SlidesViewController.xib (+12/-8)
Remote/Classes/Model/ItemModel.swift (+1/-1)
Remote/Classes/Model/LiveModel.swift (+1/-1)
Remote/Classes/Model/PollModel.swift (+36/-49)
Remote/Classes/Model/ServiceListModel.swift (+2/-2)
Remote/Classes/Model/SlideModel.swift (+1/-1)
Remote/Classes/Model/SuccessModel.swift (+1/-1)
Remote/Classes/Model/UserSettings.swift (+19/-14)
Remote/Classes/Network/API.swift (+2/-2)
Remote/Classes/Network/AddAPI.swift (+12/-9)
Remote/Classes/Network/AlertAPI.swift (+6/-6)
Remote/Classes/Network/ControllerAPI.swift (+16/-16)
Remote/Classes/Network/DisplayAPI.swift (+4/-4)
Remote/Classes/Network/LiveAPI.swift (+12/-9)
Remote/Classes/Network/PollAPI.swift (+17/-30)
Remote/Classes/Network/SearchAPI.swift (+8/-8)
Remote/Classes/Network/Service.swift (+2/-0)
Remote/Classes/Network/ServiceAPI.swift (+20/-19)
Remote/Classes/Util/ColorUtil.swift (+1/-1)
Remote/Classes/Util/DictionaryUtil.swift (+3/-3)
Remote/Classes/Util/ErrorUtil.swift (+5/-4)
Remote/Classes/Util/TabSwitchingToRightAnimationController.swift (+66/-0)
Remote/Classes/Util/ViewControllerUtil.swift (+42/-6)
Remote/Classes/View/SlideCell.swift (+44/-0)
Remote/Resources/Settings.bundle/Root.inApp.plist (+16/-0)
Remote/Resources/Settings.bundle/Root.plist (+18/-0)
To merge this branch: bzr merge lp:~dude-from-by/openlp/my-ios-remote
Reviewer Review Type Date Requested Status
Daniel Borges Approve
Review via email: mp+315893@code.launchpad.net

This proposal supersedes a proposal from 2017-01-25.

Description of the change

migrated to swift 3

To post a comment you must log in.
Revision history for this message
Daniel Borges (danielborges93) wrote : Posted in a previous version of this proposal

Follows some observations:

1) The link of the pod BlockLooper is incorrect. I think you only have access to the current :git link. Replacing to "https://github.com/ashender/BlockLooper.git" works well for me;
2) The arrow to next and previous slide (in SlidesViewController) are breaking the app;
- There is a log message when I select a slide (in SlideViewController): "slide selection error: nil", please remove it;
- In SettingViewController when I (dis)able Needs Auth the fields do not hide or show;
- "Use precise slides scroll" is in embedded setting, but not in root settings (in Setting.app). As is possible to add to toggle in root setting, add to PSToggleSwitchSpecifier into Root.plist;
- The tests here are quite crazy. I had to add the AlamofireObjectMapper pod into test target, but I'm getting errors about swift version. It is only with me?

If possible, add a footer text after "Use precise slides scroll" explaining what is it. For this, add the key "FooterText" as a String in the dictionary of its GroupSpecifier.

review: Needs Fixing
Revision history for this message
Daniel Borges (danielborges93) wrote : Posted in a previous version of this proposal

> - "Use precise slides scroll" is in embedded setting, but not in root settings
> (in Setting.app). As is possible to add to toggle in root setting, add to
> PSToggleSwitchSpecifier into Root.plist;
And add the String "Use precise slides scroll" in Resources/Settings.bundle/en.lproj/Root.strings. We have to do this to all changes in Settings (for future translations).

Revision history for this message
andrei (dude-from-by) wrote : Posted in a previous version of this proposal

Fixed issues

Revision history for this message
Daniel Borges (danielborges93) wrote : Posted in a previous version of this proposal

Now the only thing is that the .string file is missing the character ; at the end os the last 2 lines. The file is not loading because this.

review: Needs Fixing
Revision history for this message
andrei (dude-from-by) wrote :

updated

Revision history for this message
Daniel Borges (danielborges93) :
review: Approve
55. By andrei <email address hidden>

Migrated to swift3. Add activity indicator on slide selection, increased polling interval from 0.5 to 2 seconds. And more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'OLP RemoteTests/APITest.swift'
2--- OLP RemoteTests/APITest.swift 2016-07-03 18:04:32 +0000
3+++ OLP RemoteTests/APITest.swift 2017-01-30 12:52:52 +0000
4@@ -40,7 +40,7 @@
5
6 func test_api_base_withHTTPS() {
7 let defaults = TestUtils.defaults()
8- defaults.setBool(true, forKey:"server.useHTTPS")
9+ defaults.set(true, forKey:"server.useHTTPS")
10 let settings = UserSettings(defaults: defaults)
11 let api = API(settings: settings)
12 XCTAssert(api.base.hasPrefix("https"))
13
14=== modified file 'OLP RemoteTests/PollAPITests.swift'
15--- OLP RemoteTests/PollAPITests.swift 2016-07-03 18:04:32 +0000
16+++ OLP RemoteTests/PollAPITests.swift 2017-01-30 12:52:52 +0000
17@@ -33,8 +33,8 @@
18 override func setUp() {
19 super.setUp()
20
21- stub(isPath("/api/poll")) { _ in
22- guard let path = OHPathForFile("poll_response.json", self.dynamicType) else {
23+ stub(condition: isPath("/api/poll")) { _ in
24+ guard let path = OHPathForFile("poll_response.json", type(of: self)) else {
25 preconditionFailure("Could not find expected file in test bundle")
26 }
27
28@@ -44,8 +44,8 @@
29 headers: [ "ContentType": "application/json" ]
30 )
31 }
32- stub(isPath("/api/service/list")) { _ in
33- guard let path = OHPathForFile("service_response.json", self.dynamicType) else {
34+ stub(condition: isPath("/api/service/list")) { _ in
35+ guard let path = OHPathForFile("service_response.json", type(of: self)) else {
36 preconditionFailure("Could not find expected file in test bundle")
37 }
38
39@@ -68,7 +68,7 @@
40 var selectedItem : String?
41 var projectionState: ProjectionState?
42
43- func updateServiceList(items: [ItemModel]) {
44+ func updateServiceList(_ items: [ItemModel]) {
45 serviceList = items
46 }
47
48@@ -76,7 +76,7 @@
49 selectedItem = id
50 }
51
52- func updateProjectionState(state: ProjectionState) {
53+ func updateProjectionState(_ state: ProjectionState) {
54 projectionState = state
55 }
56 }
57@@ -87,22 +87,22 @@
58 var selectedSlide: Int?
59 var projectionState: ProjectionState?
60
61- func updateSlides(slides: [SlideModel]) {
62+ func updateSlides(_ slides: [SlideModel]) {
63 model = slides
64 }
65
66- func updateSelectedSlide(row: Int) {
67+ func updateSelectedSlide(_ row: Int) {
68 selectedSlide = row
69 }
70
71- func updateProjectionState(state: ProjectionState) {
72+ func updateProjectionState(_ state: ProjectionState) {
73 projectionState = state
74 }
75 }
76
77- func getPollAPI(serviceDelegate: PollAPIServiceDelegate, slidesDelegate: PollAPISlidesDelegate) -> PollAPI {
78+ func getPollAPI(_ serviceDelegate: PollAPIServiceDelegate, slidesDelegate: PollAPISlidesDelegate) -> PollAPI {
79 let defaults = TestUtils.defaults()
80- defaults.setBool(true, forKey:"server.useHTTPS")
81+ defaults.set(true, forKey:"server.useHTTPS")
82 let settings = UserSettings(defaults: defaults)
83 let controllerAPI = ControllerAPI(settings: settings)
84 let serviceAPI = ServiceAPI(settings: settings)
85@@ -116,7 +116,7 @@
86 let serviceDelegate: PollAPIServiceDelegateMock = PollAPIServiceDelegateMock()
87 let slidesDelegate: PollAPISlidesDelegateMock = PollAPISlidesDelegateMock()
88 getPollAPI(serviceDelegate, slidesDelegate: slidesDelegate).poll()
89- expect(serviceDelegate.projectionState).toEventually(equal(ProjectionState.Desktop))
90+ expect(serviceDelegate.projectionState).toEventually(equal(ProjectionState.desktop))
91 }
92
93 func test_pollSelectedItem() {
94
95=== modified file 'OLP RemoteTests/TestUtils.swift'
96--- OLP RemoteTests/TestUtils.swift 2016-07-03 18:04:32 +0000
97+++ OLP RemoteTests/TestUtils.swift 2017-01-30 12:52:52 +0000
98@@ -26,11 +26,11 @@
99
100 class TestUtils {
101
102- static func defaults() -> NSUserDefaults {
103- let defaults = NSUserDefaults(suiteName:NSUUID().UUIDString)!
104+ static func defaults() -> UserDefaults {
105+ let defaults = UserDefaults(suiteName:UUID().uuidString)!
106 defaults.setValue("123", forKey: "server.port")
107 defaults.setValue("100.200.200.200", forKey:"server.ip")
108 return defaults
109 }
110
111-}
112\ No newline at end of file
113+}
114
115=== modified file 'Podfile'
116--- Podfile 2016-07-03 18:04:32 +0000
117+++ Podfile 2017-01-30 12:52:52 +0000
118@@ -8,16 +8,20 @@
119 pod 'AlamofireObjectMapper'
120 pod 'TPKeyboardAvoiding'
121 pod 'InAppSettingsKit'
122- pod 'BlockLooper'
123 pod 'UITextView+Placeholder'
124+ pod 'BlockLooper', :git=>'https://github.com/ashender/BlockLooper.git'
125 pod 'CWStatusBarNotification'
126 end
127
128 target 'OLP RemoteTests' do
129 pod 'Alamofire'
130- pod 'AlamofireObjectMapper'
131+ pod 'InAppSettingsKit'
132+ pod 'BlockLooper', :git=>'https://github.com/ashender/BlockLooper.git'
133+ pod 'UITextView+Placeholder'
134+ pod 'CWStatusBarNotification'
135 pod 'OHHTTPStubs'
136 pod 'Nimble'
137+ pod 'AlamofireObjectMapper'
138 pod 'OHHTTPStubs/Swift'
139 end
140
141
142=== modified file 'Podfile.lock'
143--- Podfile.lock 2016-07-03 18:11:13 +0000
144+++ Podfile.lock 2017-01-30 12:52:52 +0000
145@@ -1,35 +1,35 @@
146 PODS:
147- - Alamofire (3.1.3)
148- - AlamofireObjectMapper (2.1.0):
149- - Alamofire (~> 3.1.0)
150- - ObjectMapper (~> 1.0)
151+ - Alamofire (4.3.0)
152+ - AlamofireObjectMapper (4.0.1):
153+ - Alamofire (~> 4.1)
154+ - ObjectMapper (~> 2.0)
155 - BlockLooper (0.0.3)
156- - CWStatusBarNotification (2.3.3)
157- - InAppSettingsKit (2.6)
158- - Nimble (4.1.0)
159- - ObjectMapper (1.0.1)
160- - OHHTTPStubs (5.1.0):
161- - OHHTTPStubs/Default (= 5.1.0)
162- - OHHTTPStubs/Core (5.1.0)
163- - OHHTTPStubs/Default (5.1.0):
164+ - CWStatusBarNotification (2.3.5)
165+ - InAppSettingsKit (2.8.1)
166+ - Nimble (5.1.1)
167+ - ObjectMapper (2.2.2)
168+ - OHHTTPStubs (5.2.3):
169+ - OHHTTPStubs/Default (= 5.2.3)
170+ - OHHTTPStubs/Core (5.2.3)
171+ - OHHTTPStubs/Default (5.2.3):
172 - OHHTTPStubs/Core
173 - OHHTTPStubs/JSON
174 - OHHTTPStubs/NSURLSession
175 - OHHTTPStubs/OHPathHelpers
176- - OHHTTPStubs/JSON (5.1.0):
177- - OHHTTPStubs/Core
178- - OHHTTPStubs/NSURLSession (5.1.0):
179- - OHHTTPStubs/Core
180- - OHHTTPStubs/OHPathHelpers (5.1.0)
181- - OHHTTPStubs/Swift (5.1.0):
182- - OHHTTPStubs/Core
183- - TPKeyboardAvoiding (1.2.11)
184- - UITextView+Placeholder (1.1.0)
185+ - OHHTTPStubs/JSON (5.2.3):
186+ - OHHTTPStubs/Core
187+ - OHHTTPStubs/NSURLSession (5.2.3):
188+ - OHHTTPStubs/Core
189+ - OHHTTPStubs/OHPathHelpers (5.2.3)
190+ - OHHTTPStubs/Swift (5.2.3):
191+ - OHHTTPStubs/Core
192+ - TPKeyboardAvoiding (1.3.1)
193+ - UITextView+Placeholder (1.2.0)
194
195 DEPENDENCIES:
196 - Alamofire
197 - AlamofireObjectMapper
198- - BlockLooper
199+ - BlockLooper (from `https://github.com/ashender/BlockLooper.git`)
200 - CWStatusBarNotification
201 - InAppSettingsKit
202 - Nimble
203@@ -38,18 +38,27 @@
204 - TPKeyboardAvoiding
205 - UITextView+Placeholder
206
207+EXTERNAL SOURCES:
208+ BlockLooper:
209+ :git: https://github.com/ashender/BlockLooper.git
210+
211+CHECKOUT OPTIONS:
212+ BlockLooper:
213+ :commit: 47b90418b5ee460e3e41013a43d9b9bbd90e0577
214+ :git: https://github.com/ashender/BlockLooper.git
215+
216 SPEC CHECKSUMS:
217- Alamofire: 9f93b56389e48def9220dd57d1f44b1927229a5a
218- AlamofireObjectMapper: 24097576202064f8b0a583452dd934064f78dc0e
219+ Alamofire: 856a113053a7bc9cbe5d6367a555d773fc5cfef7
220+ AlamofireObjectMapper: 842d2eed43a4d0593ff0110d54ac86a170c4519c
221 BlockLooper: 8bba05fef76734e8e52e39412a0212ac3474776c
222- CWStatusBarNotification: 2349142e97c9f16fb8247ed3c00308cd355d334b
223- InAppSettingsKit: cc56d3ec45f11352a16d5b210da8a3fa1b9d05ed
224- Nimble: 97a0a4cae5124c117115634b2d055d8c97d0af19
225- ObjectMapper: 98524bac0dca46c6b3d5ee02cd410fc700ec6ce2
226- OHHTTPStubs: 592f74439d2d72615115cf99a954237a3fbe26e5
227- TPKeyboardAvoiding: e5ce146b313de063957bfa75a13f1e9b0ff18ab7
228- UITextView+Placeholder: 672ce543356b5b5787f354415bc3b132d47f0362
229-
230-PODFILE CHECKSUM: b264ee57cf5b5b7fa8f69ff62c6becc3b32d65f4
231-
232-COCOAPODS: 1.0.1
233+ CWStatusBarNotification: 3d2738b25c3207f60cc50201388d3c96182545ff
234+ InAppSettingsKit: 94d2fba3ccd700fc4e32c6d09fabcc0af2426744
235+ Nimble: 415e3aa3267e7bc2c96b05fa814ddea7bb686a29
236+ ObjectMapper: 9e385c2295bcc4e16eabbcfc85db801442bba545
237+ OHHTTPStubs: e238cd5b66d8efa51c861db45895de8fe079f4a7
238+ TPKeyboardAvoiding: 0d6af20e95e2850f4c621841225b59ec7d8dd852
239+ UITextView+Placeholder: 77680995fcdd07c3f52ec92fe1150874a2ac89ff
240+
241+PODFILE CHECKSUM: 33c246100fdb079469ba0c7b05499d31b72d3722
242+
243+COCOAPODS: 1.1.1
244
245=== modified file 'Remote.xcodeproj/project.pbxproj'
246--- Remote.xcodeproj/project.pbxproj 2016-07-03 18:11:13 +0000
247+++ Remote.xcodeproj/project.pbxproj 2017-01-30 12:52:52 +0000
248@@ -48,6 +48,8 @@
249 750831B91CFF44FC00CA9299 /* poll_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 750831B81CFF44FC00CA9299 /* poll_response.json */; };
250 750831BB1CFF594400CA9299 /* service_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 750831BA1CFF594400CA9299 /* service_response.json */; };
251 750831BD1CFF597D00CA9299 /* slides_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 750831BC1CFF597D00CA9299 /* slides_response.json */; };
252+ 75219D021E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75219D011E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift */; };
253+ 755A61C91E04878F00D035D4 /* ServiceViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A61C81E04878F00D035D4 /* ServiceViewControllerDelegate.swift */; };
254 755C78CE1CCE9080001CF70D /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755C78CD1CCE9080001CF70D /* Service.swift */; };
255 75667B281CFCA8B1008FDFE0 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4640F2901BE4274A00E2AA61 /* API.swift */; };
256 75667B291CFCA8C9008FDFE0 /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CC0CEC1BE6972300423EB4 /* UserSettings.swift */; };
257@@ -72,21 +74,12 @@
258 75667B5D1CFEFF83008FDFE0 /* ColorUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A612301C78E75D00B61DC8 /* ColorUtil.swift */; };
259 75667B5E1CFEFF86008FDFE0 /* ErrorUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD378E1C79867C00DED423 /* ErrorUtil.swift */; };
260 75667B5F1CFEFFA7008FDFE0 /* DisplayAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4623B6921C078F70007FFE2B /* DisplayAPI.swift */; };
261+ 756FA0FD1E28FF060011AE6F /* SlideCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756FA0FC1E28FF060011AE6F /* SlideCell.swift */; };
262 759464A51CEB8493001A56BF /* SettingsControllerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 759464A41CEB8493001A56BF /* SettingsControllerPresenter.swift */; };
263 759778AE1CF83AC400C2E4B4 /* APITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 759778AD1CF83AC400C2E4B4 /* APITest.swift */; };
264 863574EB78CF355A8463055D /* Pods_Remote.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3194E32378DD6BB8E273BB47 /* Pods_Remote.framework */; };
265 /* End PBXBuildFile section */
266
267-/* Begin PBXContainerItemProxy section */
268- 759778A81CF839C200C2E4B4 /* PBXContainerItemProxy */ = {
269- isa = PBXContainerItemProxy;
270- containerPortal = 462258C11BE29EF300A509C8 /* Project object */;
271- proxyType = 1;
272- remoteGlobalIDString = 462258C81BE29EF300A509C8;
273- remoteInfo = Remote;
274- };
275-/* End PBXContainerItemProxy section */
276-
277 /* Begin PBXFileReference section */
278 0BAC8A693E937F5B9F7CF9A6 /* Pods_OLP_RemoteTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OLP_RemoteTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
279 20B750141C8B3B45881386FA /* Pods-Remote.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Remote.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Remote/Pods-Remote.debug.xcconfig"; sourceTree = "<group>"; };
280@@ -135,9 +128,12 @@
281 750831B81CFF44FC00CA9299 /* poll_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = poll_response.json; sourceTree = "<group>"; };
282 750831BA1CFF594400CA9299 /* service_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = service_response.json; sourceTree = "<group>"; };
283 750831BC1CFF597D00CA9299 /* slides_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = slides_response.json; sourceTree = "<group>"; };
284+ 75219D011E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabSwitchingToRightAnimationController.swift; sourceTree = "<group>"; };
285+ 755A61C81E04878F00D035D4 /* ServiceViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceViewControllerDelegate.swift; sourceTree = "<group>"; };
286 755C78CD1CCE9080001CF70D /* Service.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = "<group>"; };
287 75667B2A1CFCAE44008FDFE0 /* PollAPITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PollAPITests.swift; sourceTree = "<group>"; };
288 75667B4B1CFEE85A008FDFE0 /* TestUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = "<group>"; };
289+ 756FA0FC1E28FF060011AE6F /* SlideCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SlideCell.swift; sourceTree = "<group>"; };
290 759464A41CEB8493001A56BF /* SettingsControllerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsControllerPresenter.swift; sourceTree = "<group>"; };
291 759778A31CF839C200C2E4B4 /* OLP RemoteTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "OLP RemoteTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
292 759778A71CF839C200C2E4B4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
293@@ -267,6 +263,7 @@
294 4623BF8E1BE418A2003A04FB /* Util */ = {
295 isa = PBXGroup;
296 children = (
297+ 75219D011E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift */,
298 462395821BE50C5A00B90146 /* ViewControllerUtil.swift */,
299 463A91841C092E6B00D572E6 /* DictionaryUtil.swift */,
300 46A612301C78E75D00B61DC8 /* ColorUtil.swift */,
301@@ -278,6 +275,7 @@
302 4623BF8F1BE418A2003A04FB /* View */ = {
303 isa = PBXGroup;
304 children = (
305+ 756FA0FC1E28FF060011AE6F /* SlideCell.swift */,
306 );
307 path = View;
308 sourceTree = "<group>";
309@@ -304,6 +302,7 @@
310 4623BF981BE419B6003A04FB /* Service */ = {
311 isa = PBXGroup;
312 children = (
313+ 755A61C81E04878F00D035D4 /* ServiceViewControllerDelegate.swift */,
314 4623BF991BE419FE003A04FB /* ServiceViewController.swift */,
315 4623BF9A1BE419FE003A04FB /* ServiceViewController.xib */,
316 );
317@@ -408,7 +407,6 @@
318 buildRules = (
319 );
320 dependencies = (
321- 759778A91CF839C200C2E4B4 /* PBXTargetDependency */,
322 );
323 name = "OLP RemoteTests";
324 productName = "OLP RemoteTests";
325@@ -428,9 +426,11 @@
326 TargetAttributes = {
327 462258C81BE29EF300A509C8 = {
328 CreatedOnToolsVersion = 7.1;
329+ LastSwiftMigration = 0810;
330 };
331 759778A21CF839C200C2E4B4 = {
332 CreatedOnToolsVersion = 7.3.1;
333+ LastSwiftMigration = 0810;
334 };
335 };
336 };
337@@ -538,7 +538,7 @@
338 );
339 runOnlyForDeploymentPostprocessing = 0;
340 shellPath = /bin/sh;
341- shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
342+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
343 showEnvVarsInLog = 0;
344 };
345 BCF6BCAAAC1529152D882FC6 /* [CP] Check Pods Manifest.lock */ = {
346@@ -553,7 +553,7 @@
347 );
348 runOnlyForDeploymentPostprocessing = 0;
349 shellPath = /bin/sh;
350- shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
351+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
352 showEnvVarsInLog = 0;
353 };
354 F0EA71C50D6F72431C9A5B4E /* [CP] Embed Pods Frameworks */ = {
355@@ -589,10 +589,12 @@
356 46FD37891C796C9B00DED423 /* SearchResultViewController.swift in Sources */,
357 463A918D1C093DD500D572E6 /* AlertsViewController.swift in Sources */,
358 4640F2951BE42B6E00E2AA61 /* PollModel.swift in Sources */,
359+ 75219D021E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift in Sources */,
360 46A9EED61BFD85FF00E8D520 /* ItemModel.swift in Sources */,
361 755C78CE1CCE9080001CF70D /* Service.swift in Sources */,
362 46A9EEDC1BFD8FEE00E8D520 /* SuccessModel.swift in Sources */,
363 4640F2911BE4274A00E2AA61 /* API.swift in Sources */,
364+ 756FA0FD1E28FF060011AE6F /* SlideCell.swift in Sources */,
365 4623BF9B1BE419FE003A04FB /* ServiceViewController.swift in Sources */,
366 463A91891C093AE100D572E6 /* ServiceListModel.swift in Sources */,
367 463A91871C093A2300D572E6 /* LiveModel.swift in Sources */,
368@@ -608,6 +610,7 @@
369 46FD378F1C79867C00DED423 /* ErrorUtil.swift in Sources */,
370 46A612351C79572600B61DC8 /* PluginModel.swift in Sources */,
371 759464A51CEB8493001A56BF /* SettingsControllerPresenter.swift in Sources */,
372+ 755A61C91E04878F00D035D4 /* ServiceViewControllerDelegate.swift in Sources */,
373 );
374 runOnlyForDeploymentPostprocessing = 0;
375 };
376@@ -644,14 +647,6 @@
377 };
378 /* End PBXSourcesBuildPhase section */
379
380-/* Begin PBXTargetDependency section */
381- 759778A91CF839C200C2E4B4 /* PBXTargetDependency */ = {
382- isa = PBXTargetDependency;
383- target = 462258C81BE29EF300A509C8 /* Remote */;
384- targetProxy = 759778A81CF839C200C2E4B4 /* PBXContainerItemProxy */;
385- };
386-/* End PBXTargetDependency section */
387-
388 /* Begin PBXVariantGroup section */
389 4623BFA11BE42390003A04FB /* Localizable.strings */ = {
390 isa = PBXVariantGroup;
391@@ -705,6 +700,7 @@
392 ONLY_ACTIVE_ARCH = YES;
393 SDKROOT = iphoneos;
394 SWIFT_OPTIMIZATION_LEVEL = "-Onone";
395+ SWIFT_VERSION = "";
396 };
397 name = Debug;
398 };
399@@ -741,6 +737,7 @@
400 IPHONEOS_DEPLOYMENT_TARGET = 8.0;
401 MTL_ENABLE_DEBUG_INFO = NO;
402 SDKROOT = iphoneos;
403+ SWIFT_VERSION = "";
404 VALIDATE_PRODUCT = YES;
405 };
406 name = Release;
407@@ -753,11 +750,13 @@
408 ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
409 CODE_SIGN_IDENTITY = "iPhone Developer";
410 DEFINES_MODULE = NO;
411+ DEVELOPMENT_TEAM = "";
412 INFOPLIST_FILE = "Remote/Supporting files/Info.plist";
413 IPHONEOS_DEPLOYMENT_TARGET = 8.0;
414 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
415 PRODUCT_BUNDLE_IDENTIFIER = org.openlp.Remote;
416 PRODUCT_NAME = "$(TARGET_NAME)";
417+ SWIFT_VERSION = 3.0;
418 };
419 name = Debug;
420 };
421@@ -769,11 +768,13 @@
422 ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
423 CODE_SIGN_IDENTITY = "iPhone Developer";
424 DEFINES_MODULE = NO;
425+ DEVELOPMENT_TEAM = "";
426 INFOPLIST_FILE = "Remote/Supporting files/Info.plist";
427 IPHONEOS_DEPLOYMENT_TARGET = 8.0;
428 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
429 PRODUCT_BUNDLE_IDENTIFIER = org.openlp.Remote;
430 PRODUCT_NAME = "$(TARGET_NAME)";
431+ SWIFT_VERSION = 3.0;
432 };
433 name = Release;
434 };
435@@ -787,6 +788,7 @@
436 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
437 PRODUCT_BUNDLE_IDENTIFIER = "com.openlp.OLP-RemoteTests";
438 PRODUCT_NAME = "$(TARGET_NAME)";
439+ SWIFT_VERSION = 3.0;
440 };
441 name = Debug;
442 };
443@@ -800,6 +802,7 @@
444 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
445 PRODUCT_BUNDLE_IDENTIFIER = "com.openlp.OLP-RemoteTests";
446 PRODUCT_NAME = "$(TARGET_NAME)";
447+ SWIFT_VERSION = 3.0;
448 };
449 name = Release;
450 };
451
452=== modified file 'Remote/AppDelegate.swift'
453--- Remote/AppDelegate.swift 2016-07-03 18:04:32 +0000
454+++ Remote/AppDelegate.swift 2017-01-30 12:52:52 +0000
455@@ -26,23 +26,31 @@
456 import BlockLooper
457
458 @UIApplicationMain
459-class AppDelegate: UIResponder, UIApplicationDelegate {
460+class AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate, ServiceViewControllerDelegate {
461
462 var window: UIWindow?
463 var service: Service!
464 var settings: UserSettings!
465-
466-
467- func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
468-
469- settings = UserSettings(defaults: NSUserDefaults.standardUserDefaults())
470+ var tabBarController: UITabBarController!
471+ var useAnimator: Bool = false
472+
473+ enum OpenLPTab: Int {
474+ case serviceTab
475+ case slidesTab
476+ case alertsTab
477+ case searchTab
478+ }
479+
480+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
481+
482+ settings = UserSettings(defaults: UserDefaults.standard)
483 settings.registerDefaults()
484 service = Service(settings: settings)
485
486 var rootViewControllers = [UINavigationController]()
487 var navigationController: UINavigationController
488
489- let serviceViewController = ServiceViewController(settings: settings, service: service)
490+ let serviceViewController = ServiceViewController(settings: settings, service: service, delegate: self)
491 navigationController = UINavigationController(rootViewController: serviceViewController)
492 rootViewControllers.append(navigationController)
493
494@@ -63,22 +71,47 @@
495
496 let tabBarController = UITabBarController()
497 tabBarController.viewControllers = rootViewControllers
498+
499+ self.tabBarController = tabBarController
500+ tabBarController.delegate = self
501
502- self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
503+ self.window = UIWindow(frame: UIScreen.main.bounds)
504 self.window?.rootViewController = tabBarController
505 self.window?.makeKeyAndVisible()
506
507 settings.resetDefaultsIfNeeded()
508
509- BlockLooper.executeBlockWithRate(0.5) {
510+ BlockLooper.executeBlockWithRate(2.0) {
511 if self.settings.validateURL() {
512- self.service.pollAPI.poll()
513+ if self.service.pauseLoopPolling == false {
514+ self.service.pollAPI.poll()
515+ }
516 }
517 return false
518 }
519
520 return true
521 }
522-
523+
524+
525+ func withAnimator(_ block:()-> Void) -> Void {
526+ useAnimator = true
527+ block()
528+ useAnimator = false
529+ }
530+
531+
532+ // MARK: - ServiceViewControllerDelegate
533+ func serviceViewControllerDidSelectItem(_ item: ItemModel) {
534+ withAnimator {
535+ self.tabBarController.selectedIndex = OpenLPTab.slidesTab.rawValue
536+ }
537+ }
538+
539+
540+ // MARK: - TabBarControllerDelegate
541+ func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
542+ return useAnimator ? TabSwitchingToRightAnimationController(tabBarController: self.tabBarController) : nil
543+ }
544 }
545
546
547=== modified file 'Remote/Classes/Controller/Alerts/AlertsViewController.swift'
548--- Remote/Classes/Controller/Alerts/AlertsViewController.swift 2016-07-03 18:04:32 +0000
549+++ Remote/Classes/Controller/Alerts/AlertsViewController.swift 2017-01-30 12:52:52 +0000
550@@ -33,9 +33,9 @@
551 @IBOutlet weak var btShow: UIButton!
552 @IBOutlet weak var btShowBottomConstraint: NSLayoutConstraint!
553
554- private var btCancel: UIBarButtonItem!
555- private let service: Service!
556- private let settingsPresenter: SettingsControllerPresenter!
557+ fileprivate var btCancel: UIBarButtonItem!
558+ fileprivate let service: Service!
559+ fileprivate let settingsPresenter: SettingsControllerPresenter!
560
561 // MARK: Init
562
563@@ -62,57 +62,57 @@
564
565 // MARK: Setup
566
567- private func setupNavigationBar() {
568+ fileprivate func setupNavigationBar() {
569 self.navigationItem.leftBarButtonItem = settingsPresenter.settingsBarButton(self)
570
571 self.navigationItem.title = NSLocalizedString("Alerts", comment: "")
572
573 let strCancel = NSLocalizedString("Cancel", comment: "")
574- self.btCancel = UIBarButtonItem(title: strCancel, style: .Plain, target: self, action: #selector(AlertsViewController.clear))
575- self.btCancel.enabled = false
576+ self.btCancel = UIBarButtonItem(title: strCancel, style: .plain, target: self, action: #selector(AlertsViewController.clear))
577+ self.btCancel.isEnabled = false
578 self.navigationItem.rightBarButtonItem = self.btCancel
579 }
580
581- private func setupAlertTextView() {
582+ fileprivate func setupAlertTextView() {
583 self.textAlert.placeholder = NSLocalizedString("Type here...", comment: "")
584 }
585
586- private func setupShowButton() {
587+ fileprivate func setupShowButton() {
588 let strShow = NSLocalizedString("Show", comment: "")
589- self.btShow.setTitle(strShow, forState: .Normal)
590- self.btShow.enabled = false
591+ self.btShow.setTitle(strShow, for: UIControlState())
592+ self.btShow.isEnabled = false
593 }
594
595- private func setupTabBar() {
596+ fileprivate func setupTabBar() {
597 self.tabBarItem.title = NSLocalizedString("Alerts", comment: "")
598 self.tabBarItem.image = UIImage(named: "ic_alerts")
599 }
600
601- private func setupObservers() {
602- NSNotificationCenter.defaultCenter().addObserver(self,
603+ fileprivate func setupObservers() {
604+ NotificationCenter.default.addObserver(self,
605 selector: #selector(AlertsViewController.keyboardWillAppear(_:)),
606- name: UIKeyboardWillShowNotification,
607+ name: NSNotification.Name.UIKeyboardWillShow,
608 object: nil)
609- NSNotificationCenter.defaultCenter().addObserver(self,
610+ NotificationCenter.default.addObserver(self,
611 selector: #selector(AlertsViewController.keyboardWillDisappear(_:)),
612- name: UIKeyboardWillHideNotification,
613+ name: NSNotification.Name.UIKeyboardWillHide,
614 object: nil)
615 }
616
617 // MARK: My methods
618
619- @objc private func clear() {
620+ @objc fileprivate func clear() {
621 self.textAlert.resignFirstResponder()
622 self.textAlert.text = ""
623 }
624
625 @IBAction func showAlert() {
626 self.service.alertAPI.alert(self.textAlert.text) { success, error in
627- if let error = error, message = verifyError(error) {
628- self.displayNotification(message: message, isError: true)
629+ if let error = error, let message = verifyError(error as NSError) {
630+ self.displayNotification(message, isError: true)
631 } else {
632 let strNotification = NSLocalizedString("Alert showed!", comment: "")
633- self.displayNotification(message: strNotification)
634+ self.displayNotification(strNotification)
635 self.clear()
636 }
637 }
638@@ -120,25 +120,25 @@
639
640 // MARK: Keyboard
641
642- @objc func keyboardWillAppear(notification: NSNotification) {
643- self.btCancel.enabled = true
644+ @objc func keyboardWillAppear(_ notification: Notification) {
645+ self.btCancel.isEnabled = true
646
647- let keyboardRect = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
648+ let keyboardRect = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
649 let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
650 self.btShowBottomConstraint.constant = keyboardRect.size.height + 8
651- UIView.animateWithDuration(animationDuration) {
652+ UIView.animate(withDuration: animationDuration, animations: {
653 self.view.layoutIfNeeded()
654- }
655+ })
656 }
657
658- @objc func keyboardWillDisappear(notification: NSNotification) {
659- self.btCancel.enabled = false
660+ @objc func keyboardWillDisappear(_ notification: Notification) {
661+ self.btCancel.isEnabled = false
662
663 let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
664 self.btShowBottomConstraint.constant = 57
665- UIView.animateWithDuration(animationDuration) {
666+ UIView.animate(withDuration: animationDuration, animations: {
667 self.view.layoutIfNeeded()
668- }
669+ })
670 }
671
672 }
673@@ -147,19 +147,19 @@
674
675 extension AlertsViewController: UITextViewDelegate {
676
677- func textViewDidChange(textView: UITextView) {
678+ func textViewDidChange(_ textView: UITextView) {
679 if textView.text == "" {
680- self.btShow.enabled = false
681+ self.btShow.isEnabled = false
682 } else {
683- self.btShow.enabled = true
684+ self.btShow.isEnabled = true
685 }
686 }
687
688- func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
689+ func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
690
691- if text.containsString("\n") {
692- let newText = text.stringByReplacingOccurrencesOfString("\n", withString: " ")
693- let fullText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: newText)
694+ if text.contains("\n") {
695+ let newText = text.replacingOccurrences(of: "\n", with: " ")
696+ let fullText = (textView.text as NSString).replacingCharacters(in: range, with: newText)
697 textView.text = fullText
698 return false
699 }
700
701=== modified file 'Remote/Classes/Controller/Search/SearchResultViewController.swift'
702--- Remote/Classes/Controller/Search/SearchResultViewController.swift 2016-07-03 18:04:32 +0000
703+++ Remote/Classes/Controller/Search/SearchResultViewController.swift 2017-01-30 12:52:52 +0000
704@@ -26,13 +26,13 @@
705
706 class SearchResultViewController: UITableViewController {
707
708- private var items: [ItemModel]!
709- private let service: Service!
710+ fileprivate var items: [ItemModel]!
711+ fileprivate let service: Service!
712
713 init(items: [ItemModel], service: Service) {
714 self.items = items
715 self.service = service
716- super.init(style: .Plain)
717+ super.init(style: .plain)
718 }
719
720 required init?(coder aDecoder: NSCoder) {
721@@ -48,25 +48,25 @@
722
723 // MARK: Setup
724
725- private func setupNavigationBar() {
726+ fileprivate func setupNavigationBar() {
727 self.navigationItem.title = NSLocalizedString("Results", comment: "")
728 }
729
730- private func setupTableView() {
731+ fileprivate func setupTableView() {
732 self.tableView.estimatedRowHeight = 44
733 self.tableView.rowHeight = UITableViewAutomaticDimension
734 }
735
736 // MARK: Table view data source
737
738- override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
739+ override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
740 return self.items.count
741 }
742
743- override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
744- var cell = tableView.dequeueReusableCellWithIdentifier("Cell")
745+ override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
746+ var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
747 if cell == nil {
748- cell = UITableViewCell(style: .Default, reuseIdentifier: "Cell")
749+ cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
750 cell!.textLabel?.numberOfLines = 0
751 }
752 let item = self.items[indexPath.row]
753@@ -76,60 +76,60 @@
754
755 // MARK: Table view delegate
756
757- override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
758- func showErrorNotification(error: NSError) {
759+ override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
760+ func showErrorNotification(_ error: NSError) {
761 if let message = verifyError(error) {
762- self.displayNotification(message: message, isError: true)
763+ self.displayNotification(message, isError: true)
764 }
765 }
766 func itemAddedNotification() {
767 let message = NSLocalizedString("Item added.", comment: "")
768- self.displayNotification(message: message)
769+ self.displayNotification(message)
770 }
771 let item = self.items[indexPath.row]
772- let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
773+ let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
774 let goLiveStr = NSLocalizedString("Go Live", comment: "")
775- let goLiveAction = UIAlertAction(title: goLiveStr, style: .Default) { _ in
776- tableView.deselectRowAtIndexPath(indexPath, animated: true)
777+ let goLiveAction = UIAlertAction(title: goLiveStr, style: .default) { _ in
778+ tableView.deselectRow(at: indexPath, animated: true)
779 self.service.liveAPI.goItemToLive(item, plugin: Plugin(rawValue: item.plugin!)!) { error in
780 if let error = error {
781- showErrorNotification(error)
782+ showErrorNotification(error as NSError)
783 return
784 }
785 self.tabBarController?.selectedIndex = 1
786 }
787 }
788 let addStr = NSLocalizedString("Add to Service", comment: "")
789- let addAction = UIAlertAction(title: addStr, style: .Default) { _ in
790- tableView.deselectRowAtIndexPath(indexPath, animated: true)
791+ let addAction = UIAlertAction(title: addStr, style: .default) { _ in
792+ tableView.deselectRow(at: indexPath, animated: true)
793 self.service.addAPI.addItem(item, plugin: Plugin(rawValue: item.plugin!)!) { error in
794 if let error = error {
795- showErrorNotification(error)
796+ showErrorNotification(error as NSError)
797 } else {
798 itemAddedNotification()
799 }
800 }
801 }
802 let addAndGoStr = NSLocalizedString("Add & Go to Service", comment: "")
803- let addAndGoAction = UIAlertAction(title: addAndGoStr, style: .Default) { _ in
804- tableView.deselectRowAtIndexPath(indexPath, animated: true)
805+ let addAndGoAction = UIAlertAction(title: addAndGoStr, style: .default) { _ in
806+ tableView.deselectRow(at: indexPath, animated: true)
807 self.service.addAPI.addItem(item, plugin: Plugin(rawValue: item.plugin!)!) { error in
808 if let error = error {
809- showErrorNotification(error)
810+ showErrorNotification(error as NSError)
811 return
812 }
813 self.tabBarController?.selectedIndex = 0
814 }
815 }
816 let cancelStr = NSLocalizedString("Cancel", comment: "")
817- let cancelAction = UIAlertAction(title: cancelStr, style: .Cancel) { _ in
818- tableView.deselectRowAtIndexPath(indexPath, animated: true)
819+ let cancelAction = UIAlertAction(title: cancelStr, style: .cancel) { _ in
820+ tableView.deselectRow(at: indexPath, animated: true)
821 }
822 alertController.addAction(goLiveAction)
823 alertController.addAction(addAction)
824 alertController.addAction(addAndGoAction)
825 alertController.addAction(cancelAction)
826- self.presentViewController(alertController, animated: true, completion: nil)
827+ self.present(alertController, animated: true, completion: nil)
828 }
829
830 }
831
832=== modified file 'Remote/Classes/Controller/Search/SearchViewController.swift'
833--- Remote/Classes/Controller/Search/SearchViewController.swift 2016-07-03 18:04:32 +0000
834+++ Remote/Classes/Controller/Search/SearchViewController.swift 2017-01-30 12:52:52 +0000
835@@ -32,11 +32,11 @@
836 @IBOutlet weak var lbTitle: UILabel!
837 @IBOutlet weak var pickerView: UIPickerView!
838
839- private var notifications: CWStatusBarNotification!
840- private var textField: UITextField!
841- private var plugins: [Plugin]!
842- private let service: Service!
843- private var settingsPresenter: SettingsControllerPresenter!
844+ fileprivate var notifications: CWStatusBarNotification!
845+ fileprivate var textField: UITextField!
846+ fileprivate var plugins: [Plugin]!
847+ fileprivate let service: Service!
848+ fileprivate var settingsPresenter: SettingsControllerPresenter!
849
850 // MARK: Init
851
852@@ -64,32 +64,32 @@
853
854 // MARK: Setup
855
856- private func setupNavigationBar() {
857+ fileprivate func setupNavigationBar() {
858 self.navigationItem.leftBarButtonItem = settingsPresenter.settingsBarButton(self)
859
860 self.textField = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 30))
861- self.textField.backgroundColor = UIColor.whiteColor()
862- self.textField.textAlignment = .Center
863- self.textField.clearButtonMode = .WhileEditing
864+ self.textField.backgroundColor = UIColor.white
865+ self.textField.textAlignment = .center
866+ self.textField.clearButtonMode = .whileEditing
867 self.textField.placeholder = NSLocalizedString("Type here...", comment: "")
868 self.textField.layer.borderWidth = 0.7
869- self.textField.layer.borderColor = kGreyColor.CGColor
870+ self.textField.layer.borderColor = kGreyColor.cgColor
871 self.textField.layer.cornerRadius = 5
872- self.textField.returnKeyType = .Search
873+ self.textField.returnKeyType = .search
874 self.textField.delegate = self
875 self.navigationItem.titleView = self.textField
876
877- let btSearch = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: #selector(SearchViewController.search))
878+ let btSearch = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(SearchViewController.search))
879 self.navigationItem.rightBarButtonItem = btSearch
880 }
881
882- private func setupPickerView() {
883+ fileprivate func setupPickerView() {
884 self.lbTitle.text = NSLocalizedString("Search for", comment: "")
885- self.pickerView.layer.borderColor = kGreyColor.CGColor
886+ self.pickerView.layer.borderColor = kGreyColor.cgColor
887 self.pickerView.layer.borderWidth = 0.7
888 }
889
890- private func setupOptions() {
891+ fileprivate func setupOptions() {
892 self.plugins = [
893 .Songs,
894 .Bibles,
895@@ -100,7 +100,7 @@
896 ]
897 }
898
899- private func setupGestures() {
900+ fileprivate func setupGestures() {
901 var gesture: UIGestureRecognizer
902 gesture = UITapGestureRecognizer(target: self, action: #selector(SearchViewController.dismissKeyboard))
903 gesture.delegate = self
904@@ -109,35 +109,35 @@
905 self.pickerView.addGestureRecognizer(gesture)
906 }
907
908- private func setupTabBar() {
909- self.tabBarItem = UITabBarItem(tabBarSystemItem: .Search, tag: 0)
910+ fileprivate func setupTabBar() {
911+ self.tabBarItem = UITabBarItem(tabBarSystemItem: .search, tag: 0)
912 self.tabBarItem.title = NSLocalizedString("Search", comment: "")
913 }
914
915- private func setupNotifications() {
916+ fileprivate func setupNotifications() {
917 self.notifications = CWStatusBarNotification()
918- self.notifications.notificationLabelTextColor = UIColor.whiteColor()
919- self.notifications.notificationAnimationInStyle = .Top
920- self.notifications.notificationAnimationOutStyle = .Top
921+ self.notifications.notificationLabelTextColor = UIColor.white
922+ self.notifications.notificationAnimationInStyle = .top
923+ self.notifications.notificationAnimationOutStyle = .top
924 }
925
926 // MARK: My functions
927
928- @objc private func search() {
929+ @objc fileprivate func search() {
930 self.dismissKeyboard()
931- let plugin = self.plugins[self.pickerView.selectedRowInComponent(0)]
932+ let plugin = self.plugins[self.pickerView.selectedRow(inComponent: 0)]
933 let text = self.textField.text!
934 service.searchAPI.search(plugin: plugin, text: text) { items, error in
935 if let error = error {
936 let message = NSLocalizedString("An error occurred. Try again...", comment: "")
937 self.notifications.notificationLabelBackgroundColor = kRedColor
938- self.notifications.displayNotificationWithMessage(message, forDuration: 3)
939+ self.notifications.display(withMessage: message, forDuration: 3)
940 print(error)
941 return
942 } else if items?.count == 0 {
943 let message = NSLocalizedString("No results found", comment: "")
944 self.notifications.notificationLabelBackgroundColor = kBlueColor
945- self.notifications.displayNotificationWithMessage(message, forDuration: 3)
946+ self.notifications.display(withMessage: message, forDuration: 3)
947 return
948 }
949 let resultsViewController = SearchResultViewController(items: items!, service: self.service)
950@@ -145,7 +145,7 @@
951 }
952 }
953
954- @objc private func dismissKeyboard() {
955+ @objc fileprivate func dismissKeyboard() {
956 self.textField.resignFirstResponder()
957 }
958
959@@ -155,11 +155,11 @@
960
961 extension SearchViewController: UIPickerViewDataSource {
962
963- func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
964+ func numberOfComponents(in pickerView: UIPickerView) -> Int {
965 return 1
966 }
967
968- func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
969+ func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
970 return self.plugins.count
971 }
972
973@@ -169,7 +169,7 @@
974
975 extension SearchViewController: UIPickerViewDelegate {
976
977- func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
978+ func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
979 let option = self.plugins[row]
980 return option.name()
981 }
982@@ -180,8 +180,8 @@
983
984 extension SearchViewController: UIGestureRecognizerDelegate {
985
986- func gestureRecognizer(gestureRecognizer: UIGestureRecognizer,
987- shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
988+ func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
989+ shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
990 return true
991 }
992
993@@ -191,7 +191,7 @@
994
995 extension SearchViewController: UITextFieldDelegate {
996
997- func textFieldShouldReturn(textField: UITextField) -> Bool {
998+ func textFieldShouldReturn(_ textField: UITextField) -> Bool {
999 self.search()
1000 return true
1001 }
1002
1003=== modified file 'Remote/Classes/Controller/Service/ServiceViewController.swift'
1004--- Remote/Classes/Controller/Service/ServiceViewController.swift 2016-07-03 18:04:32 +0000
1005+++ Remote/Classes/Controller/Service/ServiceViewController.swift 2017-01-30 12:52:52 +0000
1006@@ -31,16 +31,18 @@
1007 @IBOutlet weak var tableView: UITableView!
1008 @IBOutlet weak var segProjectionState: UISegmentedControl!
1009
1010- private var items = [ItemModel]()
1011- private var dicItemRow = [String: Int]()
1012- private let service: Service!
1013- private var settingsPresenter: SettingsControllerPresenter!
1014+ fileprivate var items = [ItemModel]()
1015+ fileprivate var dicItemRow = [String: Int]()
1016+ fileprivate let service: Service!
1017+ fileprivate var settingsPresenter: SettingsControllerPresenter!
1018+ fileprivate let delegate: ServiceViewControllerDelegate!
1019
1020 // MARK: Init
1021
1022- init(settings: UserSettings, service: Service) {
1023+ init(settings: UserSettings, service: Service, delegate: ServiceViewControllerDelegate) {
1024 self.service = service
1025 self.settingsPresenter = SettingsControllerPresenter(settings: settings, pollAPI: service.pollAPI)
1026+ self.delegate = delegate
1027 super.init(nibName: "ServiceViewController", bundle: nil)
1028 self.setupNavigationBar()
1029 self.setupTabBar()
1030@@ -48,6 +50,7 @@
1031
1032 required init?(coder aDecoder: NSCoder) {
1033 self.service = nil
1034+ self.delegate = nil
1035 super.init(coder: aDecoder)
1036 }
1037
1038@@ -59,8 +62,8 @@
1039
1040 // MARK: Setup
1041
1042- private func setupNavigationBar() {
1043- let btAdd = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(ServiceViewController.goToSearchViewController))
1044+ fileprivate func setupNavigationBar() {
1045+ let btAdd = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(ServiceViewController.goToSearchViewController))
1046 self.navigationItem.leftBarButtonItems = [
1047 settingsPresenter.settingsBarButton(self),
1048 btAdd
1049@@ -69,58 +72,59 @@
1050 self.navigationItem.title = NSLocalizedString("Service", comment: "")
1051
1052 let imagePrevious = UIImage(named: "ic_arrow-up")
1053- let btPrevious = UIBarButtonItem(image: imagePrevious, style: .Plain, target: self, action: #selector(ServiceViewController.previousItem))
1054+ let btPrevious = UIBarButtonItem(image: imagePrevious, style: .plain, target: self, action: #selector(ServiceViewController.previousItem))
1055 let imageNext = UIImage(named: "ic_arrow-down")
1056- let btNext = UIBarButtonItem(image: imageNext, style: .Plain, target: self, action: #selector(ServiceViewController.nextItem))
1057+ let btNext = UIBarButtonItem(image: imageNext, style: .plain, target: self, action: #selector(ServiceViewController.nextItem))
1058 self.navigationItem.rightBarButtonItems = [
1059 btNext,
1060 btPrevious
1061 ]
1062 }
1063
1064- private func setupTabBar() {
1065+ fileprivate func setupTabBar() {
1066 self.tabBarItem.title = NSLocalizedString("Service", comment: "")
1067 self.tabBarItem.image = UIImage(named: "ic_service")
1068 }
1069
1070- private func setupTableView() {
1071+ fileprivate func setupTableView() {
1072 self.tableView.rowHeight = UITableViewAutomaticDimension
1073 self.tableView.estimatedRowHeight = 44
1074+ self.tableView?.decelerationRate = UIScrollViewDecelerationRateFast
1075 }
1076
1077- private func setupSegmentedControl() {
1078+ fileprivate func setupSegmentedControl() {
1079 self.segProjectionState.selectedSegmentIndex = -1
1080 }
1081
1082 // MARK: My methods
1083
1084- @IBAction func segmentedControlValueChanged() {
1085+ @IBAction func sementedControlValueChanged() {
1086 let index = self.segProjectionState.selectedSegmentIndex
1087 if let state = ProjectionState(rawValue: index) {
1088 self.service.displayAPI.projectionState(state) { _, error in
1089- if let error = error, message = verifyError(error) {
1090- self.displayNotification(message: message, isError: true)
1091+ if let error = error, let message = verifyError(error as NSError) {
1092+ self.displayNotification(message, isError: true)
1093 }
1094 }
1095 }
1096 }
1097
1098- @objc private func goToSearchViewController() {
1099+ @objc fileprivate func goToSearchViewController() {
1100 self.tabBarController?.selectedIndex = 3
1101 }
1102
1103- @objc private func previousItem() {
1104+ @objc fileprivate func previousItem() {
1105 self.service.serviceAPI.previous() { _, error in
1106- if let error = error, message = verifyError(error) {
1107- self.displayNotification(message: message, isError: true)
1108+ if let error = error, let message = verifyError(error as NSError) {
1109+ self.displayNotification(message, isError: true)
1110 }
1111 }
1112 }
1113
1114- @objc private func nextItem() {
1115+ @objc fileprivate func nextItem() {
1116 self.service.serviceAPI.next() { _, error in
1117- if let error = error, message = verifyError(error) {
1118- self.displayNotification(message: message, isError: true)
1119+ if let error = error, let message = verifyError(error as NSError) {
1120+ self.displayNotification(message, isError: true)
1121 }
1122 }
1123 }
1124@@ -131,15 +135,15 @@
1125
1126 extension ServiceViewController: UITableViewDataSource {
1127
1128- func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1129+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1130 return self.items.count
1131 }
1132
1133- func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
1134- var cell = tableView.dequeueReusableCellWithIdentifier("Cell")
1135+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
1136+ var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
1137
1138 if cell == nil {
1139- cell = UITableViewCell(style: .Default, reuseIdentifier: "Cell")
1140+ cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
1141 cell!.textLabel?.numberOfLines = 0
1142 }
1143
1144@@ -155,22 +159,23 @@
1145
1146 extension ServiceViewController: UITableViewDelegate {
1147
1148- func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
1149+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
1150 self.service.serviceAPI.set(row: indexPath.row) { success, error in
1151- if let error = error, message = verifyError(error) {
1152- self.displayNotification(message: message, isError: true)
1153- tableView.deselectRowAtIndexPath(indexPath, animated: true)
1154+ if let error = error, let message = verifyError(error as NSError) {
1155+ self.displayNotification(message, isError: true)
1156+ tableView.deselectRow(at: indexPath, animated: true)
1157+ } else if success {
1158+ self.delegate.serviceViewControllerDidSelectItem(self.items[indexPath.row])
1159 }
1160 }
1161 }
1162-
1163 }
1164
1165 // MARK: - PollAPIServiceDelegate
1166
1167 extension ServiceViewController: PollAPIServiceDelegate {
1168
1169- func updateServiceList(items: [ItemModel]) {
1170+ func updateServiceList(_ items: [ItemModel]) {
1171 self.items = items
1172 self.tableView.reloadData()
1173
1174@@ -185,13 +190,13 @@
1175 func updateSelectedItem(itemId id: String) {
1176 if let selectedRow = self.dicItemRow[id] {
1177 if selectedRow < self.items.count {
1178- let indexPath = NSIndexPath(forRow: selectedRow, inSection: 0)
1179- self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .None)
1180+ let indexPath = IndexPath(row: selectedRow, section: 0)
1181+ self.tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
1182 }
1183 }
1184 }
1185
1186- func updateProjectionState(state: ProjectionState) {
1187+ func updateProjectionState(_ state: ProjectionState) {
1188 self.segProjectionState.selectedSegmentIndex = state.rawValue
1189 }
1190
1191
1192=== modified file 'Remote/Classes/Controller/Service/ServiceViewController.xib'
1193--- Remote/Classes/Controller/Service/ServiceViewController.xib 2016-07-03 18:04:32 +0000
1194+++ Remote/Classes/Controller/Service/ServiceViewController.xib 2017-01-30 12:52:52 +0000
1195@@ -1,8 +1,12 @@
1196-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
1197-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9060" systemVersion="14F1021" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
1198+<?xml version="1.0" encoding="UTF-8"?>
1199+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11542" systemVersion="16D17a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
1200+ <device id="retina4_0" orientation="portrait">
1201+ <adaptation id="fullscreen"/>
1202+ </device>
1203 <dependencies>
1204 <deployment identifier="iOS"/>
1205- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
1206+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
1207+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
1208 </dependencies>
1209 <objects>
1210 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ServiceViewController" customModule="Remote" customModuleProvider="target">
1211@@ -14,18 +18,18 @@
1212 </placeholder>
1213 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
1214 <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
1215- <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
1216+ <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
1217 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
1218 <subviews>
1219- <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="A9d-va-PLe">
1220+ <tableView clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="A9d-va-PLe">
1221 <rect key="frame" x="0.0" y="0.0" width="600" height="556"/>
1222- <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
1223+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
1224 <connections>
1225 <outlet property="dataSource" destination="-1" id="5bH-k5-YRz"/>
1226 <outlet property="delegate" destination="-1" id="hnH-to-FEe"/>
1227 </connections>
1228 </tableView>
1229- <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bfe-Nb-Utk">
1230+ <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bfe-Nb-Utk">
1231 <rect key="frame" x="0.0" y="507" width="600" height="44"/>
1232 <constraints>
1233 <constraint firstAttribute="height" constant="44" id="IBR-6A-7Oo"/>
1234@@ -43,7 +47,7 @@
1235 <segment title="Show"/>
1236 </segments>
1237 <connections>
1238- <action selector="segmentedControlValueChanged" destination="-1" eventType="valueChanged" id="43O-Kb-ivs"/>
1239+ <action selector="sementedControlValueChanged" destination="-1" eventType="valueChanged" id="YOp-zI-OuN"/>
1240 </connections>
1241 </segmentedControl>
1242 </barButtonItem>
1243@@ -51,7 +55,7 @@
1244 </items>
1245 </toolbar>
1246 </subviews>
1247- <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
1248+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
1249 <constraints>
1250 <constraint firstItem="A9d-va-PLe" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="0X6-ik-XVD"/>
1251 <constraint firstAttribute="bottom" secondItem="A9d-va-PLe" secondAttribute="bottom" constant="44" id="OCH-8f-c0t"/>
1252
1253=== added file 'Remote/Classes/Controller/Service/ServiceViewControllerDelegate.swift'
1254--- Remote/Classes/Controller/Service/ServiceViewControllerDelegate.swift 1970-01-01 00:00:00 +0000
1255+++ Remote/Classes/Controller/Service/ServiceViewControllerDelegate.swift 2017-01-30 12:52:52 +0000
1256@@ -0,0 +1,29 @@
1257+/******************************************************************************
1258+ * OpenLP iOS Remote *
1259+ * --------------------------------------------------------------------------- *
1260+ * Copyright (c) 2008-2016 OpenLP Developers *
1261+ * --------------------------------------------------------------------------- *
1262+ * Permission is hereby granted, free of charge, to any person obtaining a *
1263+ * copy of this software and associated documentation files (the "Software"), *
1264+ * to deal in the Software without restriction, including without limitation *
1265+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
1266+ * and/or sell copies of the Software, and to permit persons to whom the *
1267+ * Software is furnished to do so, subject to the following conditions: *
1268+ * *
1269+ * The above copyright notice and this permission notice shall be included in *
1270+ * all copies or substantial portions of the Software. *
1271+ * *
1272+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
1273+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
1274+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
1275+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
1276+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
1277+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
1278+ * DEALINGS IN THE SOFTWARE. *
1279+ ******************************************************************************/
1280+
1281+import Foundation
1282+
1283+protocol ServiceViewControllerDelegate {
1284+ func serviceViewControllerDidSelectItem(_ item: ItemModel)
1285+}
1286
1287=== modified file 'Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift'
1288--- Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift 2016-07-03 18:04:32 +0000
1289+++ Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift 2017-01-30 12:52:52 +0000
1290@@ -37,10 +37,10 @@
1291 super.init()
1292 }
1293
1294- func settingsBarButton(fromController: UIViewController) -> UIBarButtonItem {
1295+ func settingsBarButton(_ fromController: UIViewController) -> UIBarButtonItem {
1296 self.fromController = fromController
1297 let imageSettings = UIImage(named: "ic_gear")
1298- let btSettings = UIBarButtonItem(image: imageSettings, style: .Plain, target: self, action: #selector(SettingsControllerPresenter.presentSettingViewController))
1299+ let btSettings = UIBarButtonItem(image: imageSettings, style: .plain, target: self, action: #selector(SettingsControllerPresenter.presentSettingViewController))
1300 return btSettings
1301 }
1302
1303@@ -48,6 +48,6 @@
1304 func presentSettingViewController() {
1305 let settingsController = SettingsViewController(settings:settings, pollAPI: pollAPI)
1306 let navigationController = UINavigationController(rootViewController: settingsController)
1307- fromController!.showViewController(navigationController, sender: nil)
1308+ fromController!.show(navigationController, sender: nil)
1309 }
1310 }
1311
1312=== modified file 'Remote/Classes/Controller/Settings/SettingsViewController.swift'
1313--- Remote/Classes/Controller/Settings/SettingsViewController.swift 2016-07-03 18:04:32 +0000
1314+++ Remote/Classes/Controller/Settings/SettingsViewController.swift 2017-01-30 12:52:52 +0000
1315@@ -27,14 +27,14 @@
1316
1317 class SettingsViewController: IASKAppSettingsViewController {
1318
1319- private let hiddenSettingsKeys = ["auth.userID", "auth.password"] as Set<NSObject>
1320- private let pollAPI: PollAPI!
1321- private let settings: UserSettings!
1322+ fileprivate let hiddenSettingsKeys = ["auth.userID" as NSObject, "auth.password" as NSObject] as Set<NSObject>
1323+ fileprivate let pollAPI: PollAPI!
1324+ fileprivate let settings: UserSettings!
1325
1326 init(settings: UserSettings, pollAPI: PollAPI) {
1327 self.pollAPI = pollAPI
1328 self.settings = settings
1329- super.init(style: .Grouped)
1330+ super.init(style: .grouped)
1331 self.setupSettingViewController()
1332 self.setupNavigationBar()
1333 }
1334@@ -47,7 +47,7 @@
1335
1336 // MARK: My methods
1337
1338- private func setupSettingViewController() {
1339+ fileprivate func setupSettingViewController() {
1340 self.showDoneButton = false
1341 self.showCreditsFooter = false
1342 self.delegate = self
1343@@ -55,12 +55,12 @@
1344 let needsAuth = settings.needsAuth
1345 self.hiddenKeys = needsAuth ? [] : self.hiddenSettingsKeys
1346
1347- NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(SettingsViewController.settingsDidChange(_:)), name: kIASKAppSettingChanged, object: nil)
1348+ NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.settingsDidChange(_:)), name: NSNotification.Name(rawValue: kIASKAppSettingChanged), object: nil)
1349 }
1350
1351- @objc private func settingsDidChange(notification: NSNotification) {
1352- if let object = notification.object {
1353- if object.isEqual("auth.needsAuth") {
1354+ @objc fileprivate func settingsDidChange(_ notification: Notification) {
1355+ if let object = notification.userInfo {
1356+ if object["auth.needsAuth"] != nil {
1357 let enabled = settings.needsAuth
1358 let hiddenKeys = enabled ? [] : self.hiddenSettingsKeys
1359 self.setHiddenKeys(hiddenKeys, animated: true)
1360@@ -68,15 +68,15 @@
1361 }
1362 }
1363
1364- private func setupNavigationBar() {
1365+ fileprivate func setupNavigationBar() {
1366 self.navigationItem.title = NSLocalizedString("Settings", comment: "")
1367
1368 let strSave = NSLocalizedString("OK", comment: "")
1369- let btSave = UIBarButtonItem(title: strSave, style: .Done, target: self, action: #selector(SettingsViewController.dismissViewController))
1370+ let btSave = UIBarButtonItem(title: strSave, style: .done, target: self, action: #selector(SettingsViewController.dismissViewController))
1371 self.navigationItem.rightBarButtonItem = btSave
1372 }
1373
1374- @objc private func dismissViewController() {
1375+ @objc fileprivate func dismissViewController() {
1376 if !settings.validateServerIP() {
1377 let title = NSLocalizedString("Error", comment: "")
1378 let message = NSLocalizedString("Please, verify if the server IP is valid.", comment: "")
1379@@ -89,7 +89,7 @@
1380 .show()
1381 } else {
1382 self.synchronizeSettings()
1383- self.dismissViewControllerAnimated(true, completion: nil)
1384+ self.dismiss(animated: true, completion: nil)
1385 }
1386 }
1387
1388@@ -99,17 +99,7 @@
1389
1390 extension SettingsViewController: IASKSettingsDelegate {
1391
1392- func settingsViewControllerDidEnd(sender: IASKAppSettingsViewController!) {
1393+ func settingsViewControllerDidEnd(_ sender: IASKAppSettingsViewController!) {
1394 // This is required...
1395 }
1396-
1397- func settingsViewController(sender: IASKAppSettingsViewController!, buttonTappedForSpecifier specifier: IASKSpecifier!) {
1398- if specifier.key() == "server.testConnection" {
1399- pollAPI.testConnection { success in
1400- print("Success: \(success)")
1401- }
1402- }
1403- self.synchronizeSettings()
1404- }
1405-
1406 }
1407
1408=== modified file 'Remote/Classes/Controller/Slides/SlidesViewController.swift'
1409--- Remote/Classes/Controller/Slides/SlidesViewController.swift 2016-07-03 18:04:32 +0000
1410+++ Remote/Classes/Controller/Slides/SlidesViewController.swift 2017-01-30 12:52:52 +0000
1411@@ -31,15 +31,19 @@
1412 @IBOutlet weak var tableView: UITableView?
1413 @IBOutlet weak var segProjectionState: UISegmentedControl?
1414
1415- private var slides = [SlideModel]()
1416- private let service: Service!
1417- private var settingsPresenter: SettingsControllerPresenter!
1418+ fileprivate var slides = [SlideModel]()
1419+ fileprivate let service: Service!
1420+ fileprivate var settingsPresenter: SettingsControllerPresenter!
1421+ fileprivate let settings: UserSettings!
1422+
1423+ fileprivate let cellIdentifier = "cell_id"
1424
1425 // MARK: Init
1426
1427 init(settings: UserSettings, service: Service) {
1428 self.service = service
1429 self.settingsPresenter = SettingsControllerPresenter(settings: settings, pollAPI: service.pollAPI)
1430+ self.settings = settings
1431 super.init(nibName: "SlidesViewController", bundle: nil)
1432 self.setupTabBar()
1433 self.setupNavigationBar()
1434@@ -48,43 +52,50 @@
1435 required init?(coder aDecoder: NSCoder) {
1436 self.service = nil
1437 self.settingsPresenter = nil
1438+ self.settings = nil
1439 super.init(coder: aDecoder)
1440 }
1441
1442 override func viewDidLoad() {
1443 super.viewDidLoad()
1444- self.setupTableView()
1445- self.setupSegmentedControl()
1446- }
1447-
1448+ setupTableView()
1449+ setupSegmentedControl()
1450+ }
1451+
1452+ override func viewWillAppear(_ animated: Bool) {
1453+ self.tableView?.decelerationRate = settings.preciseSlidesScroll ? UIScrollViewDecelerationRateFast : UIScrollViewDecelerationRateNormal
1454+ self.tableView?.bounces = !settings.preciseSlidesScroll
1455+ }
1456+
1457 // MARK: Setup
1458
1459- private func setupTabBar() {
1460+ fileprivate func setupTabBar() {
1461 self.tabBarItem.title = NSLocalizedString("Slides", comment: "")
1462 self.tabBarItem.image = UIImage(named: "ic_slides")
1463 }
1464
1465- private func setupNavigationBar() {
1466+ fileprivate func setupNavigationBar() {
1467 self.navigationItem.leftBarButtonItem = settingsPresenter.settingsBarButton(self)
1468
1469 self.navigationItem.title = NSLocalizedString("Slides", comment: "")
1470
1471 let imagePrevious = UIImage(named: "ic_arrow-up")
1472- let btPrevious = UIBarButtonItem(image: imagePrevious, style: .Plain, target: self, action: #selector(SlidesViewController.previousSlide))
1473+ let btPrevious = UIBarButtonItem(image: imagePrevious, style: .plain, target: self, action: #selector(SlidesViewController.previousSlide))
1474 let imageNext = UIImage(named: "ic_arrow-down")
1475- let btNext = UIBarButtonItem(image: imageNext, style: .Plain, target: self, action: #selector(SlidesViewController.nextSlide))
1476+ let btNext = UIBarButtonItem(image: imageNext, style: .plain, target: self, action: #selector(SlidesViewController.nextSlide))
1477 self.navigationItem.rightBarButtonItems = [
1478 btNext,
1479 btPrevious
1480 ]
1481 }
1482
1483- private func setupTableView() {
1484+ fileprivate func setupTableView() {
1485 self.tableView?.rowHeight = UITableViewAutomaticDimension
1486 self.tableView?.estimatedRowHeight = 44
1487+ self.tableView?.register(SlideCell.self, forCellReuseIdentifier: cellIdentifier)
1488 }
1489
1490- private func setupSegmentedControl() {
1491+ fileprivate func setupSegmentedControl() {
1492 self.segProjectionState?.selectedSegmentIndex = -1
1493 }
1494
1495@@ -94,25 +105,25 @@
1496 let index = self.segProjectionState?.selectedSegmentIndex
1497 if let state = ProjectionState(rawValue: index!) {
1498 self.service.displayAPI.projectionState(state) { _, error in
1499- if let error = error, message = verifyError(error) {
1500- self.displayNotification(message: message, isError: true)
1501+ if let error = error, let message = verifyError(error as NSError) {
1502+ self.displayNotification(message, isError: true)
1503 }
1504 }
1505 }
1506 }
1507
1508- @objc private func previousSlide() {
1509+ @objc fileprivate func previousSlide() {
1510 self.service.controllerAPI.livePrevious() { _, error in
1511- if let error = error, message = verifyError(error) {
1512- self.displayNotification(message: message, isError: true)
1513+ if let error = error, let message = verifyError(error) {
1514+ self.displayNotification(message, isError: true)
1515 }
1516 }
1517 }
1518
1519- @objc private func nextSlide() {
1520+ @objc fileprivate func nextSlide() {
1521 self.service.controllerAPI.liveNext() { _, error in
1522- if let error = error, message = verifyError(error) {
1523- self.displayNotification(message: message, isError: true)
1524+ if let error = error, let message = verifyError(error) {
1525+ self.displayNotification(message, isError: true)
1526 }
1527 }
1528 }
1529@@ -124,58 +135,57 @@
1530
1531 extension SlidesViewController: UITableViewDataSource {
1532
1533- func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1534+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1535 return self.slides.count
1536 }
1537
1538- func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
1539- var cell = tableView.dequeueReusableCellWithIdentifier("Cell")
1540-
1541- if cell == nil {
1542- cell = UITableViewCell(style: .Default, reuseIdentifier: "Cell")
1543- cell!.textLabel?.numberOfLines = 0
1544- }
1545-
1546+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
1547+ let cell: SlideCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as! SlideCell
1548 let slide = self.slides[indexPath.row]
1549- cell!.textLabel?.text = slide.text
1550-
1551- return cell!
1552+ cell.textLabel?.text = slide.text
1553+ return cell
1554 }
1555-
1556 }
1557
1558+
1559 // MARK: - UITableViewDelegate
1560
1561 extension SlidesViewController: UITableViewDelegate {
1562
1563- func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
1564+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
1565+ let cell = tableView.cellForRow(at: indexPath) as! SlideCell
1566+ cell.spinner.startAnimating()
1567+ service.pauseLoopPolling = true
1568 self.service.controllerAPI.liveSet(row: indexPath.row) { _, error in
1569- if let error = error, message = verifyError(error) {
1570- self.displayNotification(message: message, isError: true)
1571- tableView.deselectRowAtIndexPath(indexPath, animated: true)
1572+ self.service.pauseLoopPolling = false
1573+ cell.spinner.stopAnimating()
1574+ if let error = error, let message = verifyError(error as NSError) {
1575+ self.displayNotification(message, isError: true)
1576+ tableView.deselectRow(at: indexPath, animated: true)
1577 }
1578 }
1579 }
1580-
1581 }
1582
1583+
1584 // MARK: - PollAPISlidesDelegate
1585
1586 extension SlidesViewController: PollAPISlidesDelegate {
1587
1588- func updateSlides(slides: [SlideModel]) {
1589+ func updateSlides(_ slides: [SlideModel]) {
1590 self.slides = slides
1591 self.tableView?.reloadData()
1592+ self.tableView?.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: true)
1593 }
1594
1595- func updateSelectedSlide(row: Int) {
1596+ func updateSelectedSlide(_ row: Int) {
1597 if self.slides.count > 0 {
1598- let indexPath = NSIndexPath(forRow: row, inSection: 0)
1599- self.tableView?.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .None)
1600+ let indexPath = IndexPath(row: row, section: 0)
1601+ self.tableView?.selectRow(at: indexPath, animated: true, scrollPosition: .none)
1602 }
1603 }
1604
1605- func updateProjectionState(state: ProjectionState) {
1606+ func updateProjectionState(_ state: ProjectionState) {
1607 self.segProjectionState?.selectedSegmentIndex = state.rawValue
1608 }
1609
1610
1611=== modified file 'Remote/Classes/Controller/Slides/SlidesViewController.xib'
1612--- Remote/Classes/Controller/Slides/SlidesViewController.xib 2016-07-03 18:04:32 +0000
1613+++ Remote/Classes/Controller/Slides/SlidesViewController.xib 2017-01-30 12:52:52 +0000
1614@@ -1,8 +1,12 @@
1615-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
1616-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9060" systemVersion="14F1021" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
1617+<?xml version="1.0" encoding="UTF-8"?>
1618+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11542" systemVersion="16D17a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
1619+ <device id="retina4_0" orientation="portrait">
1620+ <adaptation id="fullscreen"/>
1621+ </device>
1622 <dependencies>
1623 <deployment identifier="iOS"/>
1624- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
1625+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
1626+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
1627 </dependencies>
1628 <objects>
1629 <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SlidesViewController" customModule="Remote" customModuleProvider="target">
1630@@ -14,18 +18,18 @@
1631 </placeholder>
1632 <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
1633 <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
1634- <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
1635+ <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
1636 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
1637 <subviews>
1638- <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="yep-A9-X97">
1639+ <tableView clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="yep-A9-X97">
1640 <rect key="frame" x="0.0" y="0.0" width="600" height="556"/>
1641- <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
1642+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
1643 <connections>
1644 <outlet property="dataSource" destination="-1" id="IUL-yU-aAA"/>
1645 <outlet property="delegate" destination="-1" id="yTW-CE-U9j"/>
1646 </connections>
1647 </tableView>
1648- <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bd2-0o-H00">
1649+ <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bd2-0o-H00">
1650 <rect key="frame" x="0.0" y="507" width="600" height="44"/>
1651 <constraints>
1652 <constraint firstAttribute="height" constant="44" id="nTo-A6-Fmk"/>
1653@@ -51,7 +55,7 @@
1654 </items>
1655 </toolbar>
1656 </subviews>
1657- <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
1658+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
1659 <constraints>
1660 <constraint firstItem="bd2-0o-H00" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="9Nx-QJ-WEy"/>
1661 <constraint firstAttribute="bottom" secondItem="yep-A9-X97" secondAttribute="bottom" constant="44" id="K91-G1-wno"/>
1662
1663=== modified file 'Remote/Classes/Model/ItemModel.swift'
1664--- Remote/Classes/Model/ItemModel.swift 2016-07-03 18:04:32 +0000
1665+++ Remote/Classes/Model/ItemModel.swift 2017-01-30 12:52:52 +0000
1666@@ -36,7 +36,7 @@
1667
1668 init() {}
1669
1670- required init?(_ map: Map) {}
1671+ required init?(map: Map) {}
1672
1673 func mapping(map: Map) {
1674 self.id <- map["id"]
1675
1676=== modified file 'Remote/Classes/Model/LiveModel.swift'
1677--- Remote/Classes/Model/LiveModel.swift 2016-07-03 18:04:32 +0000
1678+++ Remote/Classes/Model/LiveModel.swift 2017-01-30 12:52:52 +0000
1679@@ -30,7 +30,7 @@
1680 var item: String!
1681 var slides: [SlideModel]!
1682
1683- required init?(_ map: Map) {}
1684+ required init?(map: Map) {}
1685
1686 func mapping(map: Map) {
1687 self.item <- map["results.item"]
1688
1689=== modified file 'Remote/Classes/Model/PollModel.swift'
1690--- Remote/Classes/Model/PollModel.swift 2016-07-03 18:04:32 +0000
1691+++ Remote/Classes/Model/PollModel.swift 2017-01-30 12:52:52 +0000
1692@@ -26,20 +26,20 @@
1693 import ObjectMapper
1694
1695 enum ProjectionState: Int {
1696- case Blank = 0
1697- case Theme = 1
1698- case Desktop = 2
1699- case Show = 3
1700+ case blank = 0
1701+ case theme = 1
1702+ case desktop = 2
1703+ case show = 3
1704
1705 func string() -> String {
1706 switch self {
1707- case .Blank:
1708+ case .blank:
1709 return "blank"
1710- case .Theme:
1711+ case .theme:
1712 return "theme"
1713- case .Desktop:
1714+ case .desktop:
1715 return "desktop"
1716- case .Show:
1717+ case .show:
1718 return "show"
1719 }
1720 }
1721@@ -47,48 +47,39 @@
1722
1723 class PollModel: Mappable {
1724
1725- var item: String!
1726- var version: Int!
1727- var isSecure: Bool!
1728- var isAuthorised: Bool!
1729- private var blank: Bool!
1730- private var display: Bool!
1731- private var theme: Bool!
1732- var twelve: Bool!
1733- var slide: Int!
1734- var service: Int!
1735+ var item: String = ""
1736+ var version: Int = 0
1737+ var isSecure: Bool = false
1738+ var isAuthorised: Bool = false
1739+ fileprivate var blank: Bool = false
1740+ fileprivate var display: Bool = false
1741+ fileprivate var theme: Bool = false
1742+ var twelve: Bool = false
1743+ var slide: Int = 0
1744+ var service: Int = 0
1745 var projectionState: ProjectionState {
1746- if blank.boolValue || display.boolValue || theme.boolValue {
1747- if (blank.boolValue) {
1748- return .Blank
1749- }
1750- else if display.boolValue {
1751- return .Desktop
1752+ get {
1753+ if blank || display || theme {
1754+ if (blank) {
1755+ return .blank
1756+ }
1757+ else if display {
1758+ return .desktop
1759+ }
1760+ else {
1761+ return .theme
1762+ }
1763 }
1764 else {
1765- return .Theme
1766+ return .show
1767 }
1768 }
1769- else {
1770- return .Show
1771- }
1772- }
1773-
1774- init() {
1775- self.item = ""
1776- self.version = 0
1777- self.isSecure = false
1778- self.isAuthorised = false
1779- self.blank = false
1780- self.display = false
1781- self.theme = false
1782- self.twelve = false
1783- self.slide = 0
1784- self.service = 0
1785- }
1786-
1787- required init?(_ map: Map) {}
1788-
1789+ }
1790+
1791+ init() {}
1792+
1793+ required init?(map: Map) {}
1794+
1795 func mapping(map: Map) {
1796 self.item <- map["results.item"]
1797 self.version <- map["results.version"]
1798@@ -101,8 +92,4 @@
1799 self.slide <- map["results.slide"]
1800 self.service <- map["results.service"]
1801 }
1802-
1803-
1804-
1805-
1806 }
1807
1808=== modified file 'Remote/Classes/Model/ServiceListModel.swift'
1809--- Remote/Classes/Model/ServiceListModel.swift 2016-07-03 18:04:32 +0000
1810+++ Remote/Classes/Model/ServiceListModel.swift 2017-01-30 12:52:52 +0000
1811@@ -27,12 +27,12 @@
1812
1813 class ServiceListModel: Mappable {
1814
1815- private var intern: Dictionary<String, [ItemModel]>!
1816+ fileprivate var intern: Dictionary<String, [ItemModel]>!
1817 var results: [ItemModel] {
1818 return intern["items"]!
1819 }
1820
1821- required init?(_ map: Map) {}
1822+ required init?(map: Map) {}
1823
1824 func mapping(map: Map) {
1825 self.intern <- map["results"]
1826
1827=== modified file 'Remote/Classes/Model/SlideModel.swift'
1828--- Remote/Classes/Model/SlideModel.swift 2016-07-03 18:04:32 +0000
1829+++ Remote/Classes/Model/SlideModel.swift 2017-01-30 12:52:52 +0000
1830@@ -32,7 +32,7 @@
1831 var text: String!
1832 var selected: Bool!
1833
1834- required init?(_ map: Map) {}
1835+ required init?(map: Map) {}
1836
1837 func mapping(map: Map) {
1838 self.tag <- map["tag"]
1839
1840=== modified file 'Remote/Classes/Model/SuccessModel.swift'
1841--- Remote/Classes/Model/SuccessModel.swift 2016-07-03 18:04:32 +0000
1842+++ Remote/Classes/Model/SuccessModel.swift 2017-01-30 12:52:52 +0000
1843@@ -29,7 +29,7 @@
1844
1845 var success: Bool!
1846
1847- required init?(_ map: Map) {}
1848+ required init?(map: Map) {}
1849
1850 func mapping(map: Map) {
1851 self.success <- map["results.success"]
1852
1853=== modified file 'Remote/Classes/Model/UserSettings.swift'
1854--- Remote/Classes/Model/UserSettings.swift 2016-07-03 18:04:32 +0000
1855+++ Remote/Classes/Model/UserSettings.swift 2017-01-30 12:52:52 +0000
1856@@ -26,57 +26,62 @@
1857
1858 struct UserSettings {
1859
1860- private let userDefaults: NSUserDefaults
1861+ fileprivate let userDefaults: UserDefaults
1862
1863- init(defaults: NSUserDefaults) {
1864+ init(defaults: UserDefaults) {
1865 userDefaults = defaults
1866 }
1867
1868 var serverIP: String {
1869- return userDefaults.valueForKey("server.ip") as! String
1870+ return userDefaults.value(forKey: "server.ip") as! String
1871 }
1872
1873 var serverPort: String {
1874- return userDefaults.valueForKey("server.port") as! String
1875+ return userDefaults.value(forKey: "server.port") as! String
1876 }
1877
1878 var useHTTPS: Bool {
1879- return userDefaults.boolForKey("server.useHTTPS")
1880+ return userDefaults.bool(forKey: "server.useHTTPS")
1881 }
1882
1883 var needsAuth: Bool {
1884- return userDefaults.boolForKey("auth.needsAuth")
1885+ return userDefaults.bool(forKey: "auth.needsAuth")
1886 }
1887
1888 var userID: String {
1889- return userDefaults.valueForKey("auth.userID") as! String
1890+ return userDefaults.value(forKey: "auth.userID") as! String
1891 }
1892
1893 var password: String {
1894- return userDefaults.valueForKey("auth.password") as! String
1895+ return userDefaults.value(forKey: "auth.password") as! String
1896+ }
1897+
1898+ var preciseSlidesScroll: Bool {
1899+ return userDefaults.bool(forKey: "ui.preciseScroll")
1900 }
1901
1902 func registerDefaults() {
1903- userDefaults.registerDefaults([
1904+ userDefaults.register(defaults: [
1905 "server.ip": "",
1906 "server.port": "4316",
1907 "server.useHTTPS": false,
1908 "auth.needsAuth": false,
1909 "auth.userID": "",
1910- "auth.password": ""
1911+ "auth.password": "",
1912+ "ui.preciseScroll": false
1913 ])
1914 }
1915
1916 func resetDefaultsIfNeeded() {
1917- guard let _ = NSURL(string: serverIP + ":" + serverPort) else {
1918- userDefaults.removeObjectForKey("server.ip")
1919- userDefaults.removeObjectForKey("server.port")
1920+ guard let _ = URL(string: serverIP + ":" + serverPort) else {
1921+ userDefaults.removeObject(forKey: "server.ip")
1922+ userDefaults.removeObject(forKey: "server.port")
1923 return
1924 }
1925 }
1926
1927 func validateServerIP() -> Bool {
1928- guard let _ = NSURL(string: serverIP) else {
1929+ guard let _ = URL(string: serverIP) else {
1930 return false
1931 }
1932 return true
1933
1934=== modified file 'Remote/Classes/Network/API.swift'
1935--- Remote/Classes/Network/API.swift 2016-07-03 18:04:32 +0000
1936+++ Remote/Classes/Network/API.swift 2017-01-30 12:52:52 +0000
1937@@ -43,7 +43,7 @@
1938 scheme += "s"
1939 }
1940
1941- let components: NSURLComponents = NSURLComponents()
1942+ var components: URLComponents = URLComponents()
1943 components.scheme = scheme
1944 components.host = serverIP
1945 components.port = Int(serverPort)
1946@@ -51,4 +51,4 @@
1947
1948 return components.string!//strUrl
1949 }
1950-}
1951\ No newline at end of file
1952+}
1953
1954=== modified file 'Remote/Classes/Network/AddAPI.swift'
1955--- Remote/Classes/Network/AddAPI.swift 2016-07-03 18:04:32 +0000
1956+++ Remote/Classes/Network/AddAPI.swift 2017-01-30 12:52:52 +0000
1957@@ -27,22 +27,25 @@
1958
1959 class AddAPI: API {
1960
1961- func addItem(item: ItemModel, plugin: Plugin, completion: (NSError?) -> Void) {
1962+ func addItem(_ item: ItemModel, plugin: Plugin, completion: @escaping (Error?) -> Void) {
1963 let url = self.base + "/" + plugin.rawValue + "/add"
1964- var params: [String: AnyObject] = [
1965+ var params: [String: Any] = [
1966 "request": [
1967 "id": (item.id == nil ? String(item.idInt!) : item.id!)
1968 ]
1969 ]
1970 if let jsonString = jsonString(fromDictionary: params) {
1971- params = ["data": jsonString]
1972- let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
1973+ params = ["data": jsonString as Any]
1974+ let request = Alamofire.request(url, parameters: params).validate(statusCode: 200...200)
1975 if settings.needsAuth {
1976- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
1977- }
1978- request.response { _, _, _, error in
1979- completion(error)
1980- }
1981+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
1982+ }
1983+
1984+ let responseHandler: (Alamofire.DefaultDataResponse) -> Swift.Void = { response in
1985+ completion(response.error)
1986+ }
1987+
1988+ request.response(completionHandler: responseHandler)
1989 }
1990 }
1991
1992
1993=== modified file 'Remote/Classes/Network/AlertAPI.swift'
1994--- Remote/Classes/Network/AlertAPI.swift 2016-07-03 18:04:32 +0000
1995+++ Remote/Classes/Network/AlertAPI.swift 2017-01-30 12:52:52 +0000
1996@@ -28,21 +28,21 @@
1997
1998 class AlertAPI: API {
1999
2000- func alert(text: String, completion: ((Bool, NSError?) -> Void)? = nil) {
2001+ func alert(_ text: String, completion: ((Bool, Error?) -> Void)? = nil) {
2002 let url = self.base + "/alert"
2003- var params: [String: AnyObject] = [
2004+ var params: [String: Any] = [
2005 "request": [
2006 "text": text
2007 ]
2008 ]
2009
2010 if let jsonString = jsonString(fromDictionary: params) {
2011- params = ["data": jsonString]
2012- let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
2013+ params = ["data": jsonString as Any]
2014+ let request = Alamofire.request(url, parameters: params).validate(statusCode: 200...200)
2015 if settings.needsAuth {
2016- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2017+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2018 }
2019- request.responseObject { (response: Response<SuccessModel, NSError>) in
2020+ request.responseObject { (response: DataResponse<SuccessModel>) in
2021 let error = response.result.error
2022 var success = response.result.value?.success
2023 if success == nil {
2024
2025=== modified file 'Remote/Classes/Network/ControllerAPI.swift'
2026--- Remote/Classes/Network/ControllerAPI.swift 2016-07-03 18:04:32 +0000
2027+++ Remote/Classes/Network/ControllerAPI.swift 2017-01-30 12:52:52 +0000
2028@@ -28,26 +28,26 @@
2029
2030 class ControllerAPI: API {
2031
2032- func liveText(completion: ([SlideModel]?, NSError?) -> Void) {
2033+ func liveText(_ completion: @escaping ([SlideModel]?, Error?) -> Void) {
2034 let url = self.base + "/controller/live/text"
2035- let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
2036+ let request = Alamofire.request(url).validate(statusCode: 200...200)
2037 if settings.needsAuth {
2038- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2039+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2040 }
2041- request.responseObject { (response: Response<LiveModel, NSError>) -> Void in
2042+ request.responseObject { (response: DataResponse<LiveModel>) -> Void in
2043 let error = response.result.error
2044 let slides = response.result.value?.slides
2045 completion(slides, error)
2046 }
2047 }
2048
2049- private func action(action: String, completion: ((Bool, NSError?) -> Void)?) {
2050+ fileprivate func action(_ action: String, completion: ((Bool, Error?) -> Void)?) {
2051 let url = self.base + "/controller/live/" + action
2052- let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
2053+ let request = Alamofire.request(url).validate(statusCode: 200...200)
2054 if settings.needsAuth {
2055- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2056+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2057 }
2058- request.responseObject { (response: Response<SuccessModel, NSError>) -> Void in
2059+ request.responseObject { (response: DataResponse<SuccessModel>) -> Void in
2060 let error = response.result.error
2061 var success = response.result.value?.success
2062 if success == nil {
2063@@ -60,29 +60,29 @@
2064 }
2065 }
2066
2067- func livePrevious(completion: ((Bool, NSError?) -> Void)? = nil) {
2068+ func livePrevious(_ completion: ((Bool, Error?) -> Void)? = nil) {
2069 self.action("previous", completion: completion)
2070 }
2071
2072- func liveNext(completion: ((Bool, NSError?) -> Void)? = nil) {
2073+ func liveNext(_ completion: ((Bool, Error?) -> Void)? = nil) {
2074 self.action("next", completion: completion)
2075 }
2076
2077- func liveSet(row row: Int, completion: ((Bool, NSError?) -> Void)? = nil) {
2078+ func liveSet(row: Int, completion: ((Bool, Error?) -> Void)? = nil) {
2079 let url = self.base + "/controller/live/set"
2080- var params: [String: AnyObject] = [
2081+ var params: [String: Any] = [
2082 "request": [
2083 "id": "+\(row)"
2084 ]
2085 ]
2086
2087 if let jsonString = jsonString(fromDictionary: params) {
2088- params = ["data": jsonString]
2089- let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
2090+ params = ["data": jsonString as Any]
2091+ let request = Alamofire.request(url, parameters: params).validate(statusCode: 200...200)
2092 if settings.needsAuth {
2093- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2094+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2095 }
2096- request.responseObject { (response: Response<SuccessModel, NSError>) in
2097+ request.responseObject { (response: DataResponse<SuccessModel>) in
2098 let error = response.result.error
2099 var success = response.result.value?.success
2100 if success == nil {
2101
2102=== modified file 'Remote/Classes/Network/DisplayAPI.swift'
2103--- Remote/Classes/Network/DisplayAPI.swift 2016-07-03 18:04:32 +0000
2104+++ Remote/Classes/Network/DisplayAPI.swift 2017-01-30 12:52:52 +0000
2105@@ -28,13 +28,13 @@
2106
2107 class DisplayAPI: API {
2108
2109- func projectionState(state: ProjectionState, completion: ((Bool, NSError?) -> Void)? = nil) {
2110+ func projectionState(_ state: ProjectionState, completion: ((Bool, Error?) -> Void)? = nil) {
2111 let url = self.base + "/display/" + state.string()
2112- let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
2113+ let request = Alamofire.request(url).validate(statusCode: 200...200)
2114 if settings.needsAuth {
2115- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2116+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2117 }
2118- request.responseObject { (response: Response<SuccessModel, NSError>) in
2119+ request.responseObject { (response: DataResponse<SuccessModel>) in
2120 let error = response.result.error
2121 var success = response.result.value?.success
2122 if success == nil {
2123
2124=== modified file 'Remote/Classes/Network/LiveAPI.swift'
2125--- Remote/Classes/Network/LiveAPI.swift 2016-07-03 18:04:32 +0000
2126+++ Remote/Classes/Network/LiveAPI.swift 2017-01-30 12:52:52 +0000
2127@@ -27,22 +27,25 @@
2128
2129 class LiveAPI: API {
2130
2131- func goItemToLive(item: ItemModel, plugin: Plugin, completion: (NSError?) -> Void) {
2132+ func goItemToLive(_ item: ItemModel, plugin: Plugin, completion: @escaping (Error?) -> Void) {
2133 let url = self.base + "/" + plugin.rawValue + "/live"
2134- var params: [String: AnyObject] = [
2135+ var params: [String: Any] = [
2136 "request": [
2137 "id": (item.id == nil ? String(item.idInt!) : item.id!)
2138 ]
2139 ]
2140 if let jsonString = jsonString(fromDictionary: params) {
2141- params = ["data": jsonString]
2142- let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
2143+ params = ["data": jsonString as Any]
2144+ let request = Alamofire.request(url, parameters: params).validate(statusCode: 200...200)
2145 if settings.needsAuth {
2146- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2147- }
2148- request.response { _, _, _, error in
2149- completion(error)
2150- }
2151+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2152+ }
2153+
2154+ let responseHandler: (Alamofire.DefaultDataResponse) -> Swift.Void = { response in
2155+ completion(response.error)
2156+ }
2157+
2158+ request.response(completionHandler: responseHandler)
2159 }
2160 }
2161
2162
2163=== modified file 'Remote/Classes/Network/PollAPI.swift'
2164--- Remote/Classes/Network/PollAPI.swift 2016-07-03 18:04:32 +0000
2165+++ Remote/Classes/Network/PollAPI.swift 2017-01-30 12:52:52 +0000
2166@@ -27,24 +27,24 @@
2167 import AlamofireObjectMapper
2168
2169 protocol PollAPIServiceDelegate {
2170- func updateServiceList(items: [ItemModel])
2171+ func updateServiceList(_ items: [ItemModel])
2172 func updateSelectedItem(itemId id: String)
2173- func updateProjectionState(state: ProjectionState)
2174+ func updateProjectionState(_ state: ProjectionState)
2175 }
2176
2177 protocol PollAPISlidesDelegate {
2178- func updateSlides(slides: [SlideModel])
2179- func updateSelectedSlide(row: Int)
2180- func updateProjectionState(state: ProjectionState)
2181+ func updateSlides(_ slides: [SlideModel])
2182+ func updateSelectedSlide(_ row: Int)
2183+ func updateProjectionState(_ state: ProjectionState)
2184 }
2185
2186 class PollAPI: API {
2187
2188- private var poll: PollModel = PollModel()
2189+ fileprivate var poll: PollModel = PollModel()
2190 var serviceDelegate: PollAPIServiceDelegate?
2191 var slidesDelegate: PollAPISlidesDelegate?
2192- private let controllerAPI: ControllerAPI
2193- private let serviceAPI: ServiceAPI
2194+ fileprivate let controllerAPI: ControllerAPI
2195+ fileprivate let serviceAPI: ServiceAPI
2196
2197 init(settings: UserSettings, controllerAPI: ControllerAPI, serviceAPI: ServiceAPI) {
2198 self.controllerAPI = controllerAPI
2199@@ -52,13 +52,13 @@
2200 super.init(settings: settings)
2201 }
2202
2203- func poll(completion: ((PollModel?, NSError?) -> Void)? = nil) {
2204+ func poll(_ completion: ((PollModel?, Error?) -> Void)? = nil) {
2205 let url = self.base + "/poll"
2206- let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
2207+ let request = Alamofire.request(url).validate(statusCode: 200...200)
2208 if settings.needsAuth {
2209- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2210+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2211 }
2212- request.responseObject { (response: Response<PollModel, NSError>) in
2213+ request.responseObject { (response: DataResponse<PollModel>) in
2214 let error = response.result.error
2215 let poll = response.result.value
2216
2217@@ -71,7 +71,7 @@
2218 }
2219
2220
2221- private func updateService(completion: ((Void) -> Void)? = nil) {
2222+ fileprivate func updateService(_ completion: ((Void) -> Void)? = nil) {
2223 self.serviceAPI.list { items, error in
2224 if let items = items {
2225 self.serviceDelegate?.updateServiceList(items)
2226@@ -84,7 +84,7 @@
2227 }
2228
2229
2230- private func updateSlides(completion: ((Void) -> Void)? = nil) {
2231+ fileprivate func updateSlides(_ completion: ((Void) -> Void)? = nil) {
2232 self.controllerAPI.liveText { slides, error in
2233 if let slides = slides {
2234 self.slidesDelegate?.updateSlides(slides)
2235@@ -97,13 +97,13 @@
2236 }
2237
2238
2239- private func updateProjectionState(projectionState: ProjectionState) {
2240+ fileprivate func updateProjectionState(_ projectionState: ProjectionState) {
2241 self.serviceDelegate?.updateProjectionState(projectionState)
2242 self.slidesDelegate?.updateProjectionState(projectionState)
2243 }
2244
2245
2246- private func handlePollResponse(poll: PollModel?) {
2247+ fileprivate func handlePollResponse(_ poll: PollModel?) {
2248 if let poll = poll {
2249 if self.poll.service != poll.service {
2250 self.updateService({
2251@@ -129,17 +129,4 @@
2252 }
2253 }
2254
2255-
2256- func testConnection(completion: (Bool) -> Void) {
2257- self.poll { poll, error in
2258- if let _ = error {
2259- completion(false)
2260- } else if let _ = poll {
2261- completion(true)
2262- } else {
2263- completion(false)
2264- }
2265- }
2266- }
2267-
2268-}
2269\ No newline at end of file
2270+}
2271
2272=== modified file 'Remote/Classes/Network/SearchAPI.swift'
2273--- Remote/Classes/Network/SearchAPI.swift 2016-07-03 18:04:32 +0000
2274+++ Remote/Classes/Network/SearchAPI.swift 2017-01-30 12:52:52 +0000
2275@@ -27,24 +27,24 @@
2276
2277 class SearchAPI: API {
2278
2279- func search(plugin plugin: Plugin, text: String, completion: ([ItemModel]?, NSError?) -> Void) {
2280+ func search(plugin: Plugin, text: String, completion: @escaping ([ItemModel]?, Error?) -> Void) {
2281 let url = self.base + "/" + plugin.rawValue + "/search"
2282- var params: [String: AnyObject] = [
2283+ var params: [String: Any] = [
2284 "request": [
2285 "text": text
2286 ]
2287 ]
2288 if let jsonString = jsonString(fromDictionary: params) {
2289- params = ["data": jsonString]
2290- let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
2291+ params = ["data": jsonString as Any]
2292+ let request = Alamofire.request(url, parameters: params).validate(statusCode: 200...200)
2293 if settings.needsAuth {
2294- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2295+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2296 }
2297- request.responseJSON { (response: Response<AnyObject, NSError>) in
2298+ request.responseJSON { (response: DataResponse<Any>) in
2299 var result = [ItemModel]()
2300 if let value = response.result.value as? NSDictionary,
2301- results = value["results"] as? NSDictionary,
2302- items = results["items"] as? NSArray {
2303+ let results = value["results"] as? NSDictionary,
2304+ let items = results["items"] as? NSArray {
2305 for item in items {
2306 let item = item as! NSArray
2307 let i = ItemModel()
2308
2309=== modified file 'Remote/Classes/Network/Service.swift'
2310--- Remote/Classes/Network/Service.swift 2016-07-03 18:04:32 +0000
2311+++ Remote/Classes/Network/Service.swift 2017-01-30 12:52:52 +0000
2312@@ -33,6 +33,8 @@
2313 let searchAPI: SearchAPI
2314 let liveAPI: LiveAPI
2315 let addAPI: AddAPI
2316+ var pauseLoopPolling = false
2317+
2318 init(settings: UserSettings) {
2319 serviceAPI = ServiceAPI(settings: settings)
2320 controllerAPI = ControllerAPI(settings :settings)
2321
2322=== modified file 'Remote/Classes/Network/ServiceAPI.swift'
2323--- Remote/Classes/Network/ServiceAPI.swift 2016-07-03 18:04:32 +0000
2324+++ Remote/Classes/Network/ServiceAPI.swift 2017-01-30 12:52:52 +0000
2325@@ -28,34 +28,35 @@
2326
2327 class ServiceAPI: API {
2328
2329- func list(completion: ([ItemModel]?, NSError?) -> Void) {
2330+ func list(_ completion: @escaping ([ItemModel]?, Error?) -> Void) {
2331 let url = self.base + "/service/list"
2332- let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
2333+ let request = Alamofire.request(url).validate(statusCode: 200...200)
2334 if settings.needsAuth {
2335- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2336+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2337 }
2338- request.responseObject { (response: Response<ServiceListModel, NSError>) in
2339+ request.responseObject { (response: DataResponse<ServiceListModel>) in
2340 let error = response.result.error
2341 let items = response.result.value?.results
2342 completion(items, error)
2343 }
2344 }
2345
2346- func set(row row: Int, completion: ((Bool, NSError?) -> Void)? = nil) {
2347+ func set(row: Int, completion: ((Bool, Error?) -> Void)? = nil) {
2348 let url = self.base + "/service/set"
2349- var params: [String: AnyObject] = [
2350- "request": [
2351- "id": "+\(row)"
2352- ]
2353+ let literal: [String: Any] = [
2354+ "id": "+\(row)"
2355+ ]
2356+ var params: [String: Any] = [
2357+ "request": literal
2358 ]
2359
2360 if let jsonString = jsonString(fromDictionary: params) {
2361- params = ["data": jsonString]
2362- let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
2363+ params = ["data": jsonString as AnyObject]
2364+ let request = Alamofire.request(url, parameters: params).validate(statusCode: 200...200)
2365 if settings.needsAuth {
2366- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2367+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2368 }
2369- request.responseObject { (response: Response<SuccessModel, NSError>) in
2370+ request.responseObject { (response: DataResponse<SuccessModel>) in
2371 let error = response.result.error
2372 var success = response.result.value?.success
2373 if success == nil {
2374@@ -71,13 +72,13 @@
2375 }
2376 }
2377
2378- private func nextPrevious(action: String, completion: ((Bool, NSError?) -> Void)? = nil) {
2379+ fileprivate func nextPrevious(_ action: String, completion: ((Bool, Error?) -> Void)? = nil) {
2380 let url = self.base + "/service/" + action
2381- let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
2382+ let request = Alamofire.request(url).validate(statusCode: 200...200)
2383 if settings.needsAuth {
2384- request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
2385+ request.authenticate(user: settings.userID, password: settings.password, persistence: .none)
2386 }
2387- request.responseObject { (response: Response<SuccessModel, NSError>) in
2388+ request.responseObject { (response: DataResponse<SuccessModel>) in
2389 let error = response.result.error
2390 var success = response.result.value?.success
2391 if success == nil {
2392@@ -90,11 +91,11 @@
2393 }
2394 }
2395
2396- func previous(completion: ((Bool, NSError?) -> Void)? = nil) {
2397+ func previous(_ completion: ((Bool, Error?) -> Void)? = nil) {
2398 self.nextPrevious("previous", completion: completion)
2399 }
2400
2401- func next(completion: ((Bool, NSError?) -> Void)? = nil) {
2402+ func next(_ completion: ((Bool, Error?) -> Void)? = nil) {
2403 self.nextPrevious("next", completion: completion)
2404 }
2405
2406
2407=== modified file 'Remote/Classes/Util/ColorUtil.swift'
2408--- Remote/Classes/Util/ColorUtil.swift 2016-07-03 18:04:32 +0000
2409+++ Remote/Classes/Util/ColorUtil.swift 2017-01-30 12:52:52 +0000
2410@@ -26,4 +26,4 @@
2411
2412 let kGreyColor = UIColor(red: 207/255, green: 207/255, blue: 207/255, alpha: 1)
2413 let kBlueColor = UIColor(red: 0, green: 122/255, blue: 255/255, alpha: 1)
2414-let kRedColor = UIColor.redColor()
2415+let kRedColor = UIColor.red
2416
2417=== modified file 'Remote/Classes/Util/DictionaryUtil.swift'
2418--- Remote/Classes/Util/DictionaryUtil.swift 2016-07-03 18:04:32 +0000
2419+++ Remote/Classes/Util/DictionaryUtil.swift 2017-01-30 12:52:52 +0000
2420@@ -24,10 +24,10 @@
2421
2422 import Foundation
2423
2424-func jsonString(fromDictionary dictionary: [String: AnyObject]) -> String? {
2425+func jsonString(fromDictionary dictionary: [String: Any]) -> String? {
2426 do {
2427- let jsonData = try NSJSONSerialization.dataWithJSONObject(dictionary, options: NSJSONWritingOptions(rawValue: 0))
2428- let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding)!
2429+ let jsonData = try JSONSerialization.data(withJSONObject: dictionary, options: JSONSerialization.WritingOptions(rawValue: 0))
2430+ let jsonString = String(data: jsonData, encoding: String.Encoding.utf8)!
2431 return jsonString
2432 } catch {
2433 return nil
2434
2435=== modified file 'Remote/Classes/Util/ErrorUtil.swift'
2436--- Remote/Classes/Util/ErrorUtil.swift 2016-07-03 18:04:32 +0000
2437+++ Remote/Classes/Util/ErrorUtil.swift 2017-01-30 12:52:52 +0000
2438@@ -24,12 +24,13 @@
2439
2440 import UIKit
2441
2442-func verifyError(error: NSError) -> String? {
2443- if error.code == -6003 {
2444+func verifyError(_ error: Error) -> String? {
2445+ let castedError = error as NSError
2446+ if castedError.code == -6003 {
2447 return NSLocalizedString("User not authenticated.", comment: "")
2448- } else if error.code == -999 {
2449+ } else if castedError.code == -999 {
2450 return NSLocalizedString("Verify your credentials of authentication.", comment: "")
2451- } else if error.code == -6004 {
2452+ } else if castedError.code == -6004 {
2453 return nil
2454 }
2455 return NSLocalizedString("An error occurred. Try again...", comment: "")
2456
2457=== added file 'Remote/Classes/Util/TabSwitchingToRightAnimationController.swift'
2458--- Remote/Classes/Util/TabSwitchingToRightAnimationController.swift 1970-01-01 00:00:00 +0000
2459+++ Remote/Classes/Util/TabSwitchingToRightAnimationController.swift 2017-01-30 12:52:52 +0000
2460@@ -0,0 +1,66 @@
2461+/******************************************************************************
2462+ * OpenLP iOS Remote *
2463+ * --------------------------------------------------------------------------- *
2464+ * Copyright (c) 2008-2016 OpenLP Developers *
2465+ * --------------------------------------------------------------------------- *
2466+ * Permission is hereby granted, free of charge, to any person obtaining a *
2467+ * copy of this software and associated documentation files (the "Software"), *
2468+ * to deal in the Software without restriction, including without limitation *
2469+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
2470+ * and/or sell copies of the Software, and to permit persons to whom the *
2471+ * Software is furnished to do so, subject to the following conditions: *
2472+ * *
2473+ * The above copyright notice and this permission notice shall be included in *
2474+ * all copies or substantial portions of the Software. *
2475+ * *
2476+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
2477+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
2478+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
2479+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
2480+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
2481+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
2482+ * DEALINGS IN THE SOFTWARE. *
2483+ ******************************************************************************/
2484+
2485+import UIKit
2486+
2487+class TabSwitchingToRightAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
2488+ let tabBarController: UITabBarController
2489+
2490+ init(tabBarController: UITabBarController) {
2491+ self.tabBarController = tabBarController
2492+ }
2493+
2494+ func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
2495+ return 0.5
2496+ }
2497+
2498+ func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
2499+ if let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
2500+ let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) {
2501+ let fromView = fromVC.view
2502+ let toView: UIView = toVC.view
2503+
2504+ let containerView = transitionContext.containerView
2505+ containerView.addSubview(toView)
2506+
2507+ var fromViewEndFrame = fromView?.frame
2508+ fromViewEndFrame?.origin.x -= containerView.frame.width
2509+
2510+ let toViewEndFrame = transitionContext.finalFrame(for: toVC)
2511+ let toViewStartFrame = CGRect(x: toViewEndFrame.origin.x + toViewEndFrame.size.width, y: toViewEndFrame.origin.y, width: toViewEndFrame.size.width, height: toViewEndFrame.size.height)
2512+
2513+ toView.frame = toViewStartFrame
2514+
2515+ containerView.backgroundColor = UIColor.white
2516+
2517+ UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: UIViewAnimationOptions(), animations: { () -> Void in
2518+ toView.frame = toViewEndFrame
2519+ fromView?.frame = fromViewEndFrame!
2520+
2521+ }, completion: { (completed) -> Void in
2522+ transitionContext.completeTransition(completed)
2523+ })
2524+ }
2525+ }
2526+}
2527
2528=== modified file 'Remote/Classes/Util/ViewControllerUtil.swift'
2529--- Remote/Classes/Util/ViewControllerUtil.swift 2016-07-03 18:04:32 +0000
2530+++ Remote/Classes/Util/ViewControllerUtil.swift 2017-01-30 12:52:52 +0000
2531@@ -27,19 +27,55 @@
2532
2533
2534 extension UIViewController {
2535- func wrapedInNavigationController(controller: UIViewController) -> UINavigationController {
2536+ func wrapedInNavigationController(_ controller: UIViewController) -> UINavigationController {
2537 let navigationController = UINavigationController(rootViewController: controller)
2538 return navigationController
2539 }
2540
2541
2542- func displayNotification(message message: String, isError: Bool = false) {
2543+ func displayNotification(_ message: String, isError: Bool = false) {
2544 let notifications = CWStatusBarNotification()
2545- notifications.notificationLabelTextColor = UIColor.whiteColor()
2546+ notifications.notificationLabelTextColor = UIColor.white
2547 notifications.notificationLabelBackgroundColor = isError ? kRedColor : kBlueColor
2548- notifications.notificationAnimationInStyle = .Top
2549- notifications.notificationAnimationOutStyle = .Top
2550- notifications.displayNotificationWithMessage(message, forDuration: 3)
2551+ notifications.notificationAnimationInStyle = .top
2552+ notifications.notificationAnimationOutStyle = .top
2553+ notifications.display(withMessage: message, forDuration: 3)
2554+ }
2555+
2556+
2557+ func animateRightBetweenTabViews(_ fromViewController: UIViewController, toViewController: UIViewController, completion:@escaping ()->Void) {
2558+
2559+ let toView = toViewController.view
2560+ let fromView = fromViewController.view
2561+
2562+
2563+
2564+ // Add the toView to the tab bar view
2565+ fromView?.superview!.addSubview(toView!)
2566+
2567+
2568+ // Position toView off screen (to the left/right of fromView)
2569+ let screenWidth = UIScreen.main.bounds.size.width;
2570+
2571+ let offset = screenWidth;
2572+ toView?.center = CGPoint(x: (fromView?.center.x)! + offset, y: (toView?.center.y)!)
2573+
2574+ // Disable interaction during animation
2575+ view.isUserInteractionEnabled = false
2576+
2577+ UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {
2578+
2579+ // Slide the views by -offset
2580+ fromView?.center = CGPoint(x: (fromView?.center.x)! - offset, y: (fromView?.center.y)!);
2581+ toView?.center = CGPoint(x: (toView?.center.x)! - offset, y: (toView?.center.y)!);
2582+
2583+ }, completion: { finished in
2584+
2585+ // Remove the old view from the tabbar view.
2586+ fromView?.removeFromSuperview()
2587+ self.view.isUserInteractionEnabled = true
2588+ completion()
2589+ })
2590 }
2591
2592 }
2593
2594=== added file 'Remote/Classes/View/SlideCell.swift'
2595--- Remote/Classes/View/SlideCell.swift 1970-01-01 00:00:00 +0000
2596+++ Remote/Classes/View/SlideCell.swift 2017-01-30 12:52:52 +0000
2597@@ -0,0 +1,44 @@
2598+/******************************************************************************
2599+ * OpenLP iOS Remote *
2600+ * --------------------------------------------------------------------------- *
2601+ * Copyright (c) 2008-2016 OpenLP Developers *
2602+ * --------------------------------------------------------------------------- *
2603+ * Permission is hereby granted, free of charge, to any person obtaining a *
2604+ * copy of this software and associated documentation files (the "Software"), *
2605+ * to deal in the Software without restriction, including without limitation *
2606+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
2607+ * and/or sell copies of the Software, and to permit persons to whom the *
2608+ * Software is furnished to do so, subject to the following conditions: *
2609+ * *
2610+ * The above copyright notice and this permission notice shall be included in *
2611+ * all copies or substantial portions of the Software. *
2612+ * *
2613+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
2614+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
2615+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
2616+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
2617+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
2618+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
2619+ * DEALINGS IN THE SOFTWARE. *
2620+ ******************************************************************************/
2621+
2622+import UIKit
2623+
2624+class SlideCell: UITableViewCell {
2625+
2626+ let spinner: UIActivityIndicatorView
2627+
2628+ override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
2629+ spinner = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
2630+ spinner.hidesWhenStopped = true
2631+ super.init(style: style, reuseIdentifier: reuseIdentifier)
2632+ accessoryView = spinner
2633+ textLabel?.numberOfLines = 0
2634+ textLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
2635+ }
2636+
2637+ required init?(coder aDecoder: NSCoder) {
2638+ fatalError("init(coder:) has not been implemented")
2639+ }
2640+
2641+}
2642
2643=== modified file 'Remote/Resources/Settings.bundle/Root.inApp.plist'
2644--- Remote/Resources/Settings.bundle/Root.inApp.plist 2016-07-03 18:04:32 +0000
2645+++ Remote/Resources/Settings.bundle/Root.inApp.plist 2017-01-30 12:52:52 +0000
2646@@ -95,6 +95,22 @@
2647 <string>PSGroupSpecifier</string>
2648 <key>Title</key>
2649 <string></string>
2650+ <key>FooterText</key>
2651+ <string>This switch forces slides tab scroll to decelerate faster and disables bouncing. This enables faster and more precise slide selection.</string>
2652+ </dict>
2653+ <dict>
2654+ <key>Type</key>
2655+ <string>PSToggleSwitchSpecifier</string>
2656+ <key>Title</key>
2657+ <string>Use precise slides scroll</string>
2658+ <key>Key</key>
2659+ <string>ui.preciseScroll</string>
2660+ </dict>
2661+ <dict>
2662+ <key>Type</key>
2663+ <string>PSGroupSpecifier</string>
2664+ <key>Title</key>
2665+ <string></string>
2666 </dict>
2667 <dict>
2668 <key>DefaultValue</key>
2669
2670=== modified file 'Remote/Resources/Settings.bundle/Root.plist'
2671--- Remote/Resources/Settings.bundle/Root.plist 2016-07-03 18:04:32 +0000
2672+++ Remote/Resources/Settings.bundle/Root.plist 2017-01-30 12:52:52 +0000
2673@@ -90,6 +90,24 @@
2674 <key>Key</key>
2675 <string>auth.password</string>
2676 </dict>
2677+ <dict>
2678+ <key>Type</key>
2679+ <string>PSGroupSpecifier</string>
2680+ <key>Title</key>
2681+ <string></string>
2682+ <key>FooterText</key>
2683+ <string>This switch forces slides tab scroll to decelerate faster and disables bouncing. This enables faster and more precise slide selection.</string>
2684+ </dict>
2685+ <dict>
2686+ <key>Type</key>
2687+ <string>PSToggleSwitchSpecifier</string>
2688+ <key>Title</key>
2689+ <string>Use precise slides scroll</string>
2690+ <key>Key</key>
2691+ <string>ui.preciseScroll</string>
2692+ <key>DefaultValue</key>
2693+ <false/>
2694+ </dict>
2695 </array>
2696 </dict>
2697 </plist>
2698
2699=== modified file 'Remote/Resources/Settings.bundle/en.lproj/Root.strings'
2700Binary files Remote/Resources/Settings.bundle/en.lproj/Root.strings 2016-07-03 18:04:32 +0000 and Remote/Resources/Settings.bundle/en.lproj/Root.strings 2017-01-30 12:52:52 +0000 differ

Subscribers

People subscribed via source and target branches

to all changes: