openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #31001
[Merge] lp:~dude-from-by/openlp/my-ios-remote into lp:openlp
andrei has proposed merging lp:~dude-from-by/openlp/my-ios-remote into lp:openlp.
Requested reviews:
OpenLP Core (openlp-core)
For more details, see:
https://code.launchpad.net/~dude-from-by/openlp/my-ios-remote/+merge/315295
--
Your team OpenLP Core is requested to review the proposed merge of lp:~dude-from-by/openlp/my-ios-remote into lp:openlp.
=== added file '.bzrignore'
--- .bzrignore 1970-01-01 00:00:00 +0000
+++ .bzrignore 2017-01-21 18:06:11 +0000
@@ -0,0 +1,75 @@
+# Created by https://www.gitignore.io/api/xcode,swift
+
+.DS_Store
+
+### Xcode ###
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## Build generated
+build/
+DerivedData
+
+## Various settings
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+
+## Other
+*.xccheckout
+*.moved-aside
+*.xcuserstate
+
+
+### Swift ###
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## Build generated
+build/
+DerivedData
+
+## Various settings
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+
+## Other
+*.xccheckout
+*.moved-aside
+*.xcuserstate
+*.xcscmblueprint
+
+## Obj-C/Swift specific
+*.hmap
+*.ipa
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
+#
+Pods/
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build
+
=== renamed file '.bzrignore' => '.bzrignore.moved'
=== added file 'LICENSE'
--- LICENSE 1970-01-01 00:00:00 +0000
+++ LICENSE 2017-01-21 18:06:11 +0000
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2008-2016 OpenLP Developers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
=== renamed file 'LICENSE' => 'LICENSE.moved'
=== added directory 'Media Kit'
=== added file 'Media Kit/LaunchScreen - iPhone-4S.png'
Binary files Media Kit/LaunchScreen - iPhone-4S.png 1970-01-01 00:00:00 +0000 and Media Kit/LaunchScreen - iPhone-4S.png 2017-01-21 18:06:11 +0000 differ
=== added file 'Media Kit/LaunchScreen - iPhone-5.png'
Binary files Media Kit/LaunchScreen - iPhone-5.png 1970-01-01 00:00:00 +0000 and Media Kit/LaunchScreen - iPhone-5.png 2017-01-21 18:06:11 +0000 differ
=== added file 'Media Kit/LaunchScreen - iPhone-6-Plus.png'
Binary files Media Kit/LaunchScreen - iPhone-6-Plus.png 1970-01-01 00:00:00 +0000 and Media Kit/LaunchScreen - iPhone-6-Plus.png 2017-01-21 18:06:11 +0000 differ
=== added file 'Media Kit/LaunchScreen - iPhone-6.png'
Binary files Media Kit/LaunchScreen - iPhone-6.png 1970-01-01 00:00:00 +0000 and Media Kit/LaunchScreen - iPhone-6.png 2017-01-21 18:06:11 +0000 differ
=== added file 'Media Kit/icon.svg'
--- Media Kit/icon.svg 1970-01-01 00:00:00 +0000
+++ Media Kit/icon.svg 2017-01-21 18:06:11 +0000
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1" id="svg5740" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 467.4 467.4" style="enable-background:new 0 0 467.4 467.4;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:url(#rect4108_1_);}
+ .st1{fill:#FFFFFF;}
+</style>
+<linearGradient id="rect4108_1_" gradientUnits="userSpaceOnUse" x1="472.4221" y1="595.4525" x2="58.0621" y2="524.9225" gradientTransform="matrix(1 0 0 1 0 -321.31)">
+ <stop offset="0" style="stop-color:#1E468C"/>
+ <stop offset="1" style="stop-color:#507FDA"/>
+</linearGradient>
+<rect id="rect4108" x="1.1" class="st0" width="467.4" height="467.4"/>
+<path id="path6317" class="st1" d="M234.4,35.8c-109,0-197.3,88.4-197.3,197.3s88.3,197.3,197.3,197.3s197.3-88.4,197.3-197.3
+ S343.4,35.8,234.4,35.8z M233.8,52.3c99.8,0,180.8,81,180.8,180.8c0,14.8-1.8,29.5-5.4,43.8L283.1,175.8L153,71.4
+ C178.1,58.8,205.7,52.3,233.8,52.3z M107.2,104.1l158.6,94.3l128.4,76.4l-129-63.6L89.4,124.4C94.8,117.2,100.8,110.4,107.2,104.1z
+ M63.1,173.4l190.5,63.4l131.5,43.8L253.6,248L56.2,199.2C57.8,190.4,60.1,181.8,63.1,173.4z M54.2,254.6l194,20.8L384.2,290
+ L244,286l-184.7-5.3C57,272.2,55.3,263.4,54.2,254.6L54.2,254.6z M389.6,298.5L240.9,326l-143,26.5c-5.8-6.6-11.2-13.7-16-21.1
+ l163.3-17.4L389.6,298.5z M400.8,302.7c-38.4,92.2-144.3,135.9-236.5,97.4c-8-3.3-15.8-7.3-23.2-11.7l107.5-35.5L400.8,302.7z"/>
+</svg>
=== added directory 'OLP RemoteTests'
=== added file 'OLP RemoteTests/APITest.swift'
--- OLP RemoteTests/APITest.swift 1970-01-01 00:00:00 +0000
+++ OLP RemoteTests/APITest.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import XCTest
+import Foundation
+
+
+@testable import Remote
+
+class APITest: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ }
+
+ override func tearDown() {
+ super.tearDown()
+ }
+
+ func test_api_base_withHTTPS() {
+ let defaults = TestUtils.defaults()
+ defaults.setBool(true, forKey:"server.useHTTPS")
+ let settings = UserSettings(defaults: defaults)
+ let api = API(settings: settings)
+ XCTAssert(api.base.hasPrefix("https"))
+ }
+
+ func test_api_base() {
+ let defaults = TestUtils.defaults()
+ let settings = UserSettings(defaults: defaults)
+ let api = API(settings: settings)
+ XCTAssertEqual(api.base, "http://100.200.200.200:123/api")
+ }
+}
=== added file 'OLP RemoteTests/Info.plist'
--- OLP RemoteTests/Info.plist 1970-01-01 00:00:00 +0000
+++ OLP RemoteTests/Info.plist 2017-01-21 18:06:11 +0000
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
=== added file 'OLP RemoteTests/PollAPITests.swift'
--- OLP RemoteTests/PollAPITests.swift 1970-01-01 00:00:00 +0000
+++ OLP RemoteTests/PollAPITests.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,128 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import XCTest
+import Nimble
+import OHHTTPStubs
+
+@testable import Remote
+
+class PollAPITests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+
+ stub(isPath("/api/poll")) { _ in
+ guard let path = OHPathForFile("poll_response.json", self.dynamicType) else {
+ preconditionFailure("Could not find expected file in test bundle")
+ }
+
+ return OHHTTPStubsResponse(
+ fileAtPath: path,
+ statusCode: 200,
+ headers: [ "ContentType": "application/json" ]
+ )
+ }
+ stub(isPath("/api/service/list")) { _ in
+ guard let path = OHPathForFile("service_response.json", self.dynamicType) else {
+ preconditionFailure("Could not find expected file in test bundle")
+ }
+
+ return OHHTTPStubsResponse(
+ fileAtPath: path,
+ statusCode: 200,
+ headers: [ "ContentType": "application/json" ]
+ )
+
+ }
+ }
+
+ override func tearDown() {
+
+ super.tearDown()
+ }
+
+ class PollAPIServiceDelegateMock: PollAPIServiceDelegate {
+ var serviceList : [ItemModel]?
+ var selectedItem : String?
+ var projectionState: ProjectionState?
+
+ func updateServiceList(items: [ItemModel]) {
+ serviceList = items
+ }
+
+ func updateSelectedItem(itemId id: String) {
+ selectedItem = id
+ }
+
+ func updateProjectionState(state: ProjectionState) {
+ projectionState = state
+ }
+ }
+
+ class PollAPISlidesDelegateMock: PollAPISlidesDelegate {
+
+ var model: [SlideModel]?
+ var selectedSlide: Int?
+ var projectionState: ProjectionState?
+
+ func updateSlides(slides: [SlideModel]) {
+ model = slides
+ }
+
+ func updateSelectedSlide(row: Int) {
+ selectedSlide = row
+ }
+
+ func updateProjectionState(state: ProjectionState) {
+ projectionState = state
+ }
+ }
+
+ func getPollAPI(serviceDelegate: PollAPIServiceDelegate, slidesDelegate: PollAPISlidesDelegate) -> PollAPI {
+ let defaults = TestUtils.defaults()
+ defaults.setBool(true, forKey:"server.useHTTPS")
+ let settings = UserSettings(defaults: defaults)
+ let controllerAPI = ControllerAPI(settings: settings)
+ let serviceAPI = ServiceAPI(settings: settings)
+ let pollAPI = PollAPI(settings: settings, controllerAPI:controllerAPI, serviceAPI: serviceAPI)
+ pollAPI.serviceDelegate = serviceDelegate
+ pollAPI.slidesDelegate = slidesDelegate
+ return pollAPI
+ }
+
+ func test_emptyPollResponse() {
+ let serviceDelegate: PollAPIServiceDelegateMock = PollAPIServiceDelegateMock()
+ let slidesDelegate: PollAPISlidesDelegateMock = PollAPISlidesDelegateMock()
+ getPollAPI(serviceDelegate, slidesDelegate: slidesDelegate).poll()
+ expect(serviceDelegate.projectionState).toEventually(equal(ProjectionState.Desktop))
+ }
+
+ func test_pollSelectedItem() {
+ let serviceDelegate: PollAPIServiceDelegateMock = PollAPIServiceDelegateMock()
+ let slidesDelegate: PollAPISlidesDelegateMock = PollAPISlidesDelegateMock()
+ getPollAPI(serviceDelegate, slidesDelegate: slidesDelegate).poll()
+ expect(serviceDelegate.selectedItem).toEventually(equal("item1"))
+ }
+}
=== added file 'OLP RemoteTests/TestUtils.swift'
--- OLP RemoteTests/TestUtils.swift 1970-01-01 00:00:00 +0000
+++ OLP RemoteTests/TestUtils.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+
+class TestUtils {
+
+ static func defaults() -> NSUserDefaults {
+ let defaults = NSUserDefaults(suiteName:NSUUID().UUIDString)!
+ defaults.setValue("123", forKey: "server.port")
+ defaults.setValue("100.200.200.200", forKey:"server.ip")
+ return defaults
+ }
+
+}
\ No newline at end of file
=== added file 'OLP RemoteTests/poll_response.json'
--- OLP RemoteTests/poll_response.json 1970-01-01 00:00:00 +0000
+++ OLP RemoteTests/poll_response.json 2017-01-21 18:06:11 +0000
@@ -0,0 +1,1 @@
+{"results": {"item": "item1", "twelve": true, "isAuthorised": true, "display": true, "slide": 1, "version": 2, "isSecure": false, "service": 6, "blank": false, "theme": false}}
\ No newline at end of file
=== added file 'OLP RemoteTests/service_response.json'
--- OLP RemoteTests/service_response.json 1970-01-01 00:00:00 +0000
+++ OLP RemoteTests/service_response.json 2017-01-21 18:06:11 +0000
@@ -0,0 +1,1 @@
+{"results": {"items": [{"selected": false, "id": "a5916da4-2821-11e6-9db7-34363bc4e588", "notes": "", "title": "\u0411\u043e\u0433 \u0438\u0441\u043a\u0443\u043f\u0438\u043b \u043d\u0430\u0441 \u0438 \u043f\u043e\u0435\u043c \u043c\u044b", "plugin": "songs"}, {"selected": false, "id": "a75b02e2-2821-11e6-8f22-34363bc4e588", "notes": "", "title": "\u0414\u0430\u0439 \u043c\u043d\u0435 \u043f\u043e\u043d\u044f\u0442\u044c \u0441\u0435\u0440\u0434\u0446\u0435 \u0422\u0432\u043e\u0451, \u0434\u0430\u0439 \u043c\u043d\u0435 \u0443\u0441\u043b\u044b\u0448\u0430\u0442\u044c \u0433\u043b\u0430\u0441 \u043d\u0435\u0431\u0435\u0441\u043d\u044b\u0439 \u0422\u0432\u043e\u0439", "plugin": "songs"}, {"selected": false, "id": "ab246c58-2821-11e6-a684-34363bc4e588", "notes": "", "title": "\u042f \u043d\u0435 \u043c\u043e\u0433\u0443 \u0434\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0442\u0438", "plugin": "songs"}]}}
\ No newline at end of file
=== added file 'OLP RemoteTests/slides_response.json'
--- OLP RemoteTests/slides_response.json 1970-01-01 00:00:00 +0000
+++ OLP RemoteTests/slides_response.json 2017-01-21 18:06:11 +0000
@@ -0,0 +1,1 @@
+{"results": {"item": "ab246c58-2821-11e6-a684-34363bc4e588", "slides": [{"text": "\u042f \u043d\u0435 \u043c\u043e\u0433\u0443 \u0434\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0442\u0438,\n\u041f\u043e\u0442\u0435\u0440\u044f\u043b \u0441\u0435\u0431\u044f, \u043f\u0430\u043b \u043d\u0430 \u043a\u043e\u043b\u0435\u043d\u0438 \u044f.\n\u041c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043b\u0438\u0448\u044c, \u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0437\u0430 \u0422\u0435\u0431\u044f\n\u0414\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0437\u0430 \u0422\u0435\u0431\u044f \u0418\u0438\u0441\u0443\u0441, \u0418\u0438\u0441\u0443\u0441\n\u041e\u0447\u0438\u0441\u0442\u044c \u043c\u0435\u043d\u044f, \u0432\u043e\u0437\u044c\u043c\u0438 \u043c\u0435\u043d\u044f,\n\u0412 \u0421\u043b\u0430\u0432\u0435 \u0422\u0432\u043e\u0435\u0439 \u0441\u0432\u043e\u0431\u043e\u0434\u0435\u043d \u044f\n\u041e\u0447\u0438\u0441\u0442\u044c \u043c\u0435\u043d\u044f, \u0432\u043e\u0437\u044c\u043c\u0438 \u043c\u0435\u043d\u044f.\n\u0412\u0441\u044f \u0436\u0438\u0437\u043d\u044c \u043c\u043e\u044f \u0432 \u0422\u0432\u043e\u0438\u0445 \u0440\u0443\u043a\u0430\u0445", "html": "\u042f \u043d\u0435 \u043c\u043e\u0433\u0443 \u0434\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0442\u0438,<br>\u041f\u043e\u0442\u0435\u0440\u044f\u043b \u0441\u0435\u0431\u044f, \u043f\u0430\u043b \u043d\u0430 \u043a\u043e\u043b\u0435\u043d\u0438 \u044f.<br>\u041c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043b\u0438\u0448\u044c, \u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0437\u0430 \u0422\u0435\u0431\u044f<br>\u0414\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0437\u0430 \u0422\u0435\u0431\u044f \u0418\u0438\u0441\u0443\u0441, \u0418\u0438\u0441\u0443\u0441<br>\u041e\u0447\u0438\u0441\u0442\u044c \u043c\u0435\u043d\u044f, \u0432\u043e\u0437\u044c\u043c\u0438 \u043c\u0435\u043d\u044f,<br>\u0412 \u0421\u043b\u0430\u0432\u0435 \u0422\u0432\u043e\u0435\u0439 \u0441\u0432\u043e\u0431\u043e\u0434\u0435\u043d \u044f<br>\u041e\u0447\u0438\u0441\u0442\u044c \u043c\u0435\u043d\u044f, \u0432\u043e\u0437\u044c\u043c\u0438 \u043c\u0435\u043d\u044f.<br>\u0412\u0441\u044f \u0436\u0438\u0437\u043d\u044c \u043c\u043e\u044f \u0432 \u0422\u0432\u043e\u0438\u0445 \u0440\u0443\u043a\u0430\u0445", "tag": "\u04141", "selected": true}, {"text": "\u041d\u0430\u043f\u043e\u043b\u043d\u044f\u0439 \u0441\u0435\u0440\u0434\u0446\u0435 \u043c\u043e\u0451\n\u0416\u0438\u0437\u043d\u044c \u043c\u043e\u044f, \u0442\u0435\u043f\u0435\u0440\u044c \u0432 \u0422\u0432\u043e\u0438\u0445 \u0440\u0443\u043a\u0430\u0445\n\u0412 \u0441\u043c\u0438\u0440\u0435\u043d\u0438\u0438, \u043f\u0440\u0438\u043f\u0430\u0434\u0443 \u043a\u043e \u0425\u0440\u0438\u0441\u0442\u0443\n\u0422\u043e\u0431\u043e\u044e \u043b\u0438\u0448\u044c \u0436\u0438\u0432\u0443", "html": "\u041d\u0430\u043f\u043e\u043b\u043d\u044f\u0439 \u0441\u0435\u0440\u0434\u0446\u0435 \u043c\u043e\u0451<br>\u0416\u0438\u0437\u043d\u044c \u043c\u043e\u044f, \u0442\u0435\u043f\u0435\u0440\u044c \u0432 \u0422\u0432\u043e\u0438\u0445 \u0440\u0443\u043a\u0430\u0445<br>\u0412 \u0441\u043c\u0438\u0440\u0435\u043d\u0438\u0438, \u043f\u0440\u0438\u043f\u0430\u0434\u0443 \u043a\u043e \u0425\u0440\u0438\u0441\u0442\u0443<br>\u0422\u043e\u0431\u043e\u044e \u043b\u0438\u0448\u044c \u0436\u0438\u0432\u0443", "tag": "\u04142", "selected": false}]}}
\ No newline at end of file
=== added file 'Podfile'
--- Podfile 1970-01-01 00:00:00 +0000
+++ Podfile 2017-01-21 18:06:11 +0000
@@ -0,0 +1,27 @@
+# Uncomment this line to define a global platform for your project
+platform :ios, '8.0'
+use_frameworks!
+inhibit_all_warnings!
+
+target 'Remote' do
+ pod 'Alamofire'
+ pod 'AlamofireObjectMapper'
+ pod 'TPKeyboardAvoiding'
+ pod 'InAppSettingsKit'
+ pod 'BlockLooper'
+ pod 'UITextView+Placeholder'
+ pod 'CWStatusBarNotification'
+end
+
+target 'OLP RemoteTests' do
+ pod 'Alamofire'
+ pod 'AlamofireObjectMapper'
+ pod 'InAppSettingsKit'
+ pod 'BlockLooper'
+ pod 'UITextView+Placeholder'
+ pod 'CWStatusBarNotification'
+ pod 'OHHTTPStubs'
+ pod 'Nimble', '4.1.0'
+ pod 'OHHTTPStubs/Swift'
+end
+
=== added file 'Podfile.lock'
--- Podfile.lock 1970-01-01 00:00:00 +0000
+++ Podfile.lock 2017-01-21 18:06:11 +0000
@@ -0,0 +1,55 @@
+PODS:
+ - Alamofire (3.5.1)
+ - AlamofireObjectMapper (3.0.2):
+ - Alamofire (~> 3.2)
+ - ObjectMapper (~> 1.0)
+ - BlockLooper (0.0.3)
+ - CWStatusBarNotification (2.3.5)
+ - InAppSettingsKit (2.8)
+ - Nimble (4.1.0)
+ - ObjectMapper (1.5.0)
+ - OHHTTPStubs (5.2.1):
+ - OHHTTPStubs/Default (= 5.2.1)
+ - OHHTTPStubs/Core (5.2.1)
+ - OHHTTPStubs/Default (5.2.1):
+ - OHHTTPStubs/Core
+ - OHHTTPStubs/JSON
+ - OHHTTPStubs/NSURLSession
+ - OHHTTPStubs/OHPathHelpers
+ - OHHTTPStubs/JSON (5.2.1):
+ - OHHTTPStubs/Core
+ - OHHTTPStubs/NSURLSession (5.2.1):
+ - OHHTTPStubs/Core
+ - OHHTTPStubs/OHPathHelpers (5.2.1)
+ - OHHTTPStubs/Swift (5.2.1):
+ - OHHTTPStubs/Core
+ - TPKeyboardAvoiding (1.3)
+ - UITextView+Placeholder (1.2.0)
+
+DEPENDENCIES:
+ - Alamofire
+ - AlamofireObjectMapper
+ - BlockLooper
+ - CWStatusBarNotification
+ - InAppSettingsKit
+ - Nimble (= 4.1.0)
+ - OHHTTPStubs
+ - OHHTTPStubs/Swift
+ - TPKeyboardAvoiding
+ - UITextView+Placeholder
+
+SPEC CHECKSUMS:
+ Alamofire: 0dfba1184a543e2aa160f4e39cac4e8aba48d223
+ AlamofireObjectMapper: 70f97cbf45c01c48d26aa07a1a7059a60ed7411d
+ BlockLooper: 8bba05fef76734e8e52e39412a0212ac3474776c
+ CWStatusBarNotification: 3d2738b25c3207f60cc50201388d3c96182545ff
+ InAppSettingsKit: fe3e73f8f9530cdd6270065cd7df7b3773f557e6
+ Nimble: 97a0a4cae5124c117115634b2d055d8c97d0af19
+ ObjectMapper: 386645adca9d9d23b95eda43090b09d66444cf14
+ OHHTTPStubs: 3a42f25c00563b71355ac73112ba2324e9e6cef4
+ TPKeyboardAvoiding: a5138f318c06fb3e151f886e18ce4a72695d9cbe
+ UITextView+Placeholder: 77680995fcdd07c3f52ec92fe1150874a2ac89ff
+
+PODFILE CHECKSUM: 6c9b189ae9fcecc2916031b2ea56b185b35ae475
+
+COCOAPODS: 1.1.1
=== added directory 'Remote'
=== added directory 'Remote.xcodeproj'
=== added file 'Remote.xcodeproj/project.pbxproj'
--- Remote.xcodeproj/project.pbxproj 1970-01-01 00:00:00 +0000
+++ Remote.xcodeproj/project.pbxproj 2017-01-21 18:06:11 +0000
@@ -0,0 +1,840 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 462258CD1BE29EF300A509C8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462258CC1BE29EF300A509C8 /* AppDelegate.swift */; };
+ 462395811BE505EC00B90146 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462395801BE505EC00B90146 /* SettingsViewController.swift */; };
+ 462395831BE50C5A00B90146 /* ViewControllerUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 462395821BE50C5A00B90146 /* ViewControllerUtil.swift */; };
+ 4623B6931C078F70007FFE2B /* DisplayAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4623B6921C078F70007FFE2B /* DisplayAPI.swift */; };
+ 4623B6971C07BC2E007FFE2B /* SlidesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4623B6951C07BC2E007FFE2B /* SlidesViewController.swift */; };
+ 4623B6981C07BC2E007FFE2B /* SlidesViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4623B6961C07BC2E007FFE2B /* SlidesViewController.xib */; };
+ 4623B69A1C07C47D007FFE2B /* SlideModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4623B6991C07C47D007FFE2B /* SlideModel.swift */; };
+ 4623B69C1C07C569007FFE2B /* ControllerAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4623B69B1C07C569007FFE2B /* ControllerAPI.swift */; };
+ 4623BF941BE418A2003A04FB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4623BF911BE418A2003A04FB /* Assets.xcassets */; };
+ 4623BF9B1BE419FE003A04FB /* ServiceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4623BF991BE419FE003A04FB /* ServiceViewController.swift */; };
+ 4623BF9C1BE419FE003A04FB /* ServiceViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4623BF9A1BE419FE003A04FB /* ServiceViewController.xib */; };
+ 4623BF9F1BE42390003A04FB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4623BFA11BE42390003A04FB /* Localizable.strings */; };
+ 4623BFA51BE424BB003A04FB /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4623BFA41BE424BB003A04FB /* LaunchScreen.xib */; };
+ 463A91851C092E6B00D572E6 /* DictionaryUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463A91841C092E6B00D572E6 /* DictionaryUtil.swift */; };
+ 463A91871C093A2300D572E6 /* LiveModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463A91861C093A2300D572E6 /* LiveModel.swift */; };
+ 463A91891C093AE100D572E6 /* ServiceListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463A91881C093AE100D572E6 /* ServiceListModel.swift */; };
+ 463A918D1C093DD500D572E6 /* AlertsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463A918B1C093DD500D572E6 /* AlertsViewController.swift */; };
+ 463A918E1C093DD500D572E6 /* AlertsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 463A918C1C093DD500D572E6 /* AlertsViewController.xib */; };
+ 463A91921C0965E900D572E6 /* AlertAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463A91911C0965E900D572E6 /* AlertAPI.swift */; };
+ 4640F2911BE4274A00E2AA61 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4640F2901BE4274A00E2AA61 /* API.swift */; };
+ 4640F2931BE429B900E2AA61 /* PollAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4640F2921BE429B900E2AA61 /* PollAPI.swift */; };
+ 4640F2951BE42B6E00E2AA61 /* PollModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4640F2941BE42B6E00E2AA61 /* PollModel.swift */; };
+ 469DE5021BFC3B0000C7EB52 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 469DE5011BFC3B0000C7EB52 /* Settings.bundle */; };
+ 46A6122F1C78D65F00B61DC8 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 463A918F1C094F7000D572E6 /* QuartzCore.framework */; };
+ 46A612311C78E75D00B61DC8 /* ColorUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A612301C78E75D00B61DC8 /* ColorUtil.swift */; };
+ 46A612351C79572600B61DC8 /* PluginModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A612341C79572600B61DC8 /* PluginModel.swift */; };
+ 46A9EED61BFD85FF00E8D520 /* ItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A9EED51BFD85FF00E8D520 /* ItemModel.swift */; };
+ 46A9EED81BFD89DF00E8D520 /* ServiceAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A9EED71BFD89DF00E8D520 /* ServiceAPI.swift */; };
+ 46A9EEDC1BFD8FEE00E8D520 /* SuccessModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A9EEDB1BFD8FEE00E8D520 /* SuccessModel.swift */; };
+ 46C133451C0A3A0F0093579F /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C133431C0A3A0F0093579F /* SearchViewController.swift */; };
+ 46C133461C0A3A0F0093579F /* SearchViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 46C133441C0A3A0F0093579F /* SearchViewController.xib */; };
+ 46CC0CED1BE6972300423EB4 /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CC0CEC1BE6972300423EB4 /* UserSettings.swift */; };
+ 46FD37871C7959EF00DED423 /* SearchAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD37861C7959EF00DED423 /* SearchAPI.swift */; };
+ 46FD37891C796C9B00DED423 /* SearchResultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD37881C796C9B00DED423 /* SearchResultViewController.swift */; };
+ 46FD378B1C79770900DED423 /* LiveAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD378A1C79770900DED423 /* LiveAPI.swift */; };
+ 46FD378D1C797E2B00DED423 /* AddAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD378C1C797E2B00DED423 /* AddAPI.swift */; };
+ 46FD378F1C79867C00DED423 /* ErrorUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD378E1C79867C00DED423 /* ErrorUtil.swift */; };
+ 5BEE41450088359D269330AE /* Pods_OLP_RemoteTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BAC8A693E937F5B9F7CF9A6 /* Pods_OLP_RemoteTests.framework */; };
+ 750831B91CFF44FC00CA9299 /* poll_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 750831B81CFF44FC00CA9299 /* poll_response.json */; };
+ 750831BB1CFF594400CA9299 /* service_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 750831BA1CFF594400CA9299 /* service_response.json */; };
+ 750831BD1CFF597D00CA9299 /* slides_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 750831BC1CFF597D00CA9299 /* slides_response.json */; };
+ 75219D021E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75219D011E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift */; };
+ 755A61C91E04878F00D035D4 /* ServiceViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755A61C81E04878F00D035D4 /* ServiceViewControllerDelegate.swift */; };
+ 755C78CE1CCE9080001CF70D /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755C78CD1CCE9080001CF70D /* Service.swift */; };
+ 75667B281CFCA8B1008FDFE0 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4640F2901BE4274A00E2AA61 /* API.swift */; };
+ 75667B291CFCA8C9008FDFE0 /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CC0CEC1BE6972300423EB4 /* UserSettings.swift */; };
+ 75667B2B1CFCAE44008FDFE0 /* PollAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75667B2A1CFCAE44008FDFE0 /* PollAPITests.swift */; };
+ 75667B4C1CFEE85A008FDFE0 /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75667B4B1CFEE85A008FDFE0 /* TestUtils.swift */; };
+ 75667B4D1CFEE92C008FDFE0 /* ControllerAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4623B69B1C07C569007FFE2B /* ControllerAPI.swift */; };
+ 75667B4E1CFEE930008FDFE0 /* PollAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4640F2921BE429B900E2AA61 /* PollAPI.swift */; };
+ 75667B4F1CFEE938008FDFE0 /* ServiceAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A9EED71BFD89DF00E8D520 /* ServiceAPI.swift */; };
+ 75667B501CFEE938008FDFE0 /* SearchAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD37861C7959EF00DED423 /* SearchAPI.swift */; };
+ 75667B511CFEE938008FDFE0 /* LiveAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD378A1C79770900DED423 /* LiveAPI.swift */; };
+ 75667B521CFEE938008FDFE0 /* AddAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD378C1C797E2B00DED423 /* AddAPI.swift */; };
+ 75667B531CFEE938008FDFE0 /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755C78CD1CCE9080001CF70D /* Service.swift */; };
+ 75667B541CFEE93D008FDFE0 /* AlertAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463A91911C0965E900D572E6 /* AlertAPI.swift */; };
+ 75667B551CFEE949008FDFE0 /* SuccessModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A9EEDB1BFD8FEE00E8D520 /* SuccessModel.swift */; };
+ 75667B561CFEE949008FDFE0 /* ItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A9EED51BFD85FF00E8D520 /* ItemModel.swift */; };
+ 75667B571CFEE949008FDFE0 /* PollModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4640F2941BE42B6E00E2AA61 /* PollModel.swift */; };
+ 75667B581CFEE949008FDFE0 /* SlideModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4623B6991C07C47D007FFE2B /* SlideModel.swift */; };
+ 75667B591CFEE949008FDFE0 /* LiveModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463A91861C093A2300D572E6 /* LiveModel.swift */; };
+ 75667B5A1CFEE949008FDFE0 /* ServiceListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463A91881C093AE100D572E6 /* ServiceListModel.swift */; };
+ 75667B5B1CFEE949008FDFE0 /* PluginModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A612341C79572600B61DC8 /* PluginModel.swift */; };
+ 75667B5C1CFEFF7E008FDFE0 /* DictionaryUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463A91841C092E6B00D572E6 /* DictionaryUtil.swift */; };
+ 75667B5D1CFEFF83008FDFE0 /* ColorUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A612301C78E75D00B61DC8 /* ColorUtil.swift */; };
+ 75667B5E1CFEFF86008FDFE0 /* ErrorUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46FD378E1C79867C00DED423 /* ErrorUtil.swift */; };
+ 75667B5F1CFEFFA7008FDFE0 /* DisplayAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4623B6921C078F70007FFE2B /* DisplayAPI.swift */; };
+ 756FA0FD1E28FF060011AE6F /* SlideCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756FA0FC1E28FF060011AE6F /* SlideCell.swift */; };
+ 759464A51CEB8493001A56BF /* SettingsControllerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 759464A41CEB8493001A56BF /* SettingsControllerPresenter.swift */; };
+ 759778AE1CF83AC400C2E4B4 /* APITest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 759778AD1CF83AC400C2E4B4 /* APITest.swift */; };
+ 863574EB78CF355A8463055D /* Pods_Remote.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3194E32378DD6BB8E273BB47 /* Pods_Remote.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 0BAC8A693E937F5B9F7CF9A6 /* Pods_OLP_RemoteTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OLP_RemoteTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 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>"; };
+ 2AEEA392DC2D08B9EAF00B32 /* Pods-OLP RemoteTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OLP RemoteTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-OLP RemoteTests/Pods-OLP RemoteTests.debug.xcconfig"; sourceTree = "<group>"; };
+ 3194E32378DD6BB8E273BB47 /* Pods_Remote.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Remote.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 462258C91BE29EF300A509C8 /* Remote.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Remote.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 462258CC1BE29EF300A509C8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+ 462395801BE505EC00B90146 /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
+ 462395821BE50C5A00B90146 /* ViewControllerUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewControllerUtil.swift; sourceTree = "<group>"; };
+ 4623B6921C078F70007FFE2B /* DisplayAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayAPI.swift; sourceTree = "<group>"; };
+ 4623B6951C07BC2E007FFE2B /* SlidesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SlidesViewController.swift; sourceTree = "<group>"; };
+ 4623B6961C07BC2E007FFE2B /* SlidesViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SlidesViewController.xib; sourceTree = "<group>"; };
+ 4623B6991C07C47D007FFE2B /* SlideModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SlideModel.swift; sourceTree = "<group>"; };
+ 4623B69B1C07C569007FFE2B /* ControllerAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControllerAPI.swift; sourceTree = "<group>"; };
+ 4623BF911BE418A2003A04FB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ 4623BF931BE418A2003A04FB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 4623BF991BE419FE003A04FB /* ServiceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceViewController.swift; sourceTree = "<group>"; };
+ 4623BF9A1BE419FE003A04FB /* ServiceViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ServiceViewController.xib; sourceTree = "<group>"; };
+ 4623BFA01BE42390003A04FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 4623BFA41BE424BB003A04FB /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = "<group>"; };
+ 463A91841C092E6B00D572E6 /* DictionaryUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryUtil.swift; sourceTree = "<group>"; };
+ 463A91861C093A2300D572E6 /* LiveModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveModel.swift; sourceTree = "<group>"; };
+ 463A91881C093AE100D572E6 /* ServiceListModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceListModel.swift; sourceTree = "<group>"; };
+ 463A918B1C093DD500D572E6 /* AlertsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertsViewController.swift; sourceTree = "<group>"; };
+ 463A918C1C093DD500D572E6 /* AlertsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AlertsViewController.xib; sourceTree = "<group>"; };
+ 463A918F1C094F7000D572E6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+ 463A91911C0965E900D572E6 /* AlertAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertAPI.swift; sourceTree = "<group>"; };
+ 4640F2901BE4274A00E2AA61 /* API.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = "<group>"; };
+ 4640F2921BE429B900E2AA61 /* PollAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PollAPI.swift; sourceTree = "<group>"; };
+ 4640F2941BE42B6E00E2AA61 /* PollModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PollModel.swift; sourceTree = "<group>"; };
+ 469DE5011BFC3B0000C7EB52 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
+ 46A612301C78E75D00B61DC8 /* ColorUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorUtil.swift; sourceTree = "<group>"; };
+ 46A612341C79572600B61DC8 /* PluginModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PluginModel.swift; sourceTree = "<group>"; };
+ 46A9EED51BFD85FF00E8D520 /* ItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemModel.swift; sourceTree = "<group>"; };
+ 46A9EED71BFD89DF00E8D520 /* ServiceAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceAPI.swift; sourceTree = "<group>"; };
+ 46A9EEDB1BFD8FEE00E8D520 /* SuccessModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuccessModel.swift; sourceTree = "<group>"; };
+ 46C133431C0A3A0F0093579F /* SearchViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = "<group>"; };
+ 46C133441C0A3A0F0093579F /* SearchViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SearchViewController.xib; sourceTree = "<group>"; };
+ 46CC0CEC1BE6972300423EB4 /* UserSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserSettings.swift; sourceTree = "<group>"; };
+ 46FD37861C7959EF00DED423 /* SearchAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchAPI.swift; sourceTree = "<group>"; };
+ 46FD37881C796C9B00DED423 /* SearchResultViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchResultViewController.swift; sourceTree = "<group>"; };
+ 46FD378A1C79770900DED423 /* LiveAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiveAPI.swift; sourceTree = "<group>"; };
+ 46FD378C1C797E2B00DED423 /* AddAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddAPI.swift; sourceTree = "<group>"; };
+ 46FD378E1C79867C00DED423 /* ErrorUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorUtil.swift; sourceTree = "<group>"; };
+ 6B75984BB421CA7AAB01F229 /* Pods-Remote.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Remote.release.xcconfig"; path = "Pods/Target Support Files/Pods-Remote/Pods-Remote.release.xcconfig"; sourceTree = "<group>"; };
+ 750831B81CFF44FC00CA9299 /* poll_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = poll_response.json; sourceTree = "<group>"; };
+ 750831BA1CFF594400CA9299 /* service_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = service_response.json; sourceTree = "<group>"; };
+ 750831BC1CFF597D00CA9299 /* slides_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = slides_response.json; sourceTree = "<group>"; };
+ 75219D011E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabSwitchingToRightAnimationController.swift; sourceTree = "<group>"; };
+ 755A61C81E04878F00D035D4 /* ServiceViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceViewControllerDelegate.swift; sourceTree = "<group>"; };
+ 755C78CD1CCE9080001CF70D /* Service.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = "<group>"; };
+ 75667B2A1CFCAE44008FDFE0 /* PollAPITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PollAPITests.swift; sourceTree = "<group>"; };
+ 75667B4B1CFEE85A008FDFE0 /* TestUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = "<group>"; };
+ 756FA0FC1E28FF060011AE6F /* SlideCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SlideCell.swift; sourceTree = "<group>"; };
+ 759464A41CEB8493001A56BF /* SettingsControllerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsControllerPresenter.swift; sourceTree = "<group>"; };
+ 759778A31CF839C200C2E4B4 /* OLP RemoteTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "OLP RemoteTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 759778A71CF839C200C2E4B4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 759778AD1CF83AC400C2E4B4 /* APITest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APITest.swift; sourceTree = "<group>"; };
+ BF194B8FEA335C68D241C125 /* Pods-OLP RemoteTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OLP RemoteTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-OLP RemoteTests/Pods-OLP RemoteTests.release.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 462258C61BE29EF300A509C8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 46A6122F1C78D65F00B61DC8 /* QuartzCore.framework in Frameworks */,
+ 863574EB78CF355A8463055D /* Pods_Remote.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 759778A01CF839C200C2E4B4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5BEE41450088359D269330AE /* Pods_OLP_RemoteTests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 11D502B12FB9CEA4D19EAC6E /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 463A918F1C094F7000D572E6 /* QuartzCore.framework */,
+ 0BAC8A693E937F5B9F7CF9A6 /* Pods_OLP_RemoteTests.framework */,
+ 3194E32378DD6BB8E273BB47 /* Pods_Remote.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 462258C01BE29EF300A509C8 = {
+ isa = PBXGroup;
+ children = (
+ 462258CB1BE29EF300A509C8 /* Remote */,
+ 759778A41CF839C200C2E4B4 /* OLP RemoteTests */,
+ 462258CA1BE29EF300A509C8 /* Products */,
+ 11D502B12FB9CEA4D19EAC6E /* Frameworks */,
+ 9BD4CA2C346197F51290E305 /* Pods */,
+ );
+ sourceTree = "<group>";
+ };
+ 462258CA1BE29EF300A509C8 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 462258C91BE29EF300A509C8 /* Remote.app */,
+ 759778A31CF839C200C2E4B4 /* OLP RemoteTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 462258CB1BE29EF300A509C8 /* Remote */ = {
+ isa = PBXGroup;
+ children = (
+ 462258CC1BE29EF300A509C8 /* AppDelegate.swift */,
+ 4623BF8B1BE418A2003A04FB /* Classes */,
+ 4623BF901BE418A2003A04FB /* Resources */,
+ 4623BF921BE418A2003A04FB /* Supporting files */,
+ );
+ path = Remote;
+ sourceTree = "<group>";
+ };
+ 4623957F1BE505C200B90146 /* Settings */ = {
+ isa = PBXGroup;
+ children = (
+ 759464A41CEB8493001A56BF /* SettingsControllerPresenter.swift */,
+ 462395801BE505EC00B90146 /* SettingsViewController.swift */,
+ );
+ path = Settings;
+ sourceTree = "<group>";
+ };
+ 4623B6941C07BC08007FFE2B /* Slides */ = {
+ isa = PBXGroup;
+ children = (
+ 4623B6951C07BC2E007FFE2B /* SlidesViewController.swift */,
+ 4623B6961C07BC2E007FFE2B /* SlidesViewController.xib */,
+ );
+ path = Slides;
+ sourceTree = "<group>";
+ };
+ 4623BF8B1BE418A2003A04FB /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ 4623BF8C1BE418A2003A04FB /* Controller */,
+ 4623BF8D1BE418A2003A04FB /* Model */,
+ 4623BFA61BE4257B003A04FB /* Network */,
+ 4623BF8E1BE418A2003A04FB /* Util */,
+ 4623BF8F1BE418A2003A04FB /* View */,
+ );
+ path = Classes;
+ sourceTree = "<group>";
+ };
+ 4623BF8C1BE418A2003A04FB /* Controller */ = {
+ isa = PBXGroup;
+ children = (
+ 463A918A1C093DBD00D572E6 /* Alerts */,
+ 46C133421C0A39E80093579F /* Search */,
+ 4623BF981BE419B6003A04FB /* Service */,
+ 4623957F1BE505C200B90146 /* Settings */,
+ 4623B6941C07BC08007FFE2B /* Slides */,
+ );
+ path = Controller;
+ sourceTree = "<group>";
+ };
+ 4623BF8D1BE418A2003A04FB /* Model */ = {
+ isa = PBXGroup;
+ children = (
+ 46A9EEDB1BFD8FEE00E8D520 /* SuccessModel.swift */,
+ 46A9EED51BFD85FF00E8D520 /* ItemModel.swift */,
+ 4640F2941BE42B6E00E2AA61 /* PollModel.swift */,
+ 4623B6991C07C47D007FFE2B /* SlideModel.swift */,
+ 46CC0CEC1BE6972300423EB4 /* UserSettings.swift */,
+ 463A91861C093A2300D572E6 /* LiveModel.swift */,
+ 463A91881C093AE100D572E6 /* ServiceListModel.swift */,
+ 46A612341C79572600B61DC8 /* PluginModel.swift */,
+ );
+ path = Model;
+ sourceTree = "<group>";
+ };
+ 4623BF8E1BE418A2003A04FB /* Util */ = {
+ isa = PBXGroup;
+ children = (
+ 75219D011E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift */,
+ 462395821BE50C5A00B90146 /* ViewControllerUtil.swift */,
+ 463A91841C092E6B00D572E6 /* DictionaryUtil.swift */,
+ 46A612301C78E75D00B61DC8 /* ColorUtil.swift */,
+ 46FD378E1C79867C00DED423 /* ErrorUtil.swift */,
+ );
+ path = Util;
+ sourceTree = "<group>";
+ };
+ 4623BF8F1BE418A2003A04FB /* View */ = {
+ isa = PBXGroup;
+ children = (
+ 756FA0FC1E28FF060011AE6F /* SlideCell.swift */,
+ );
+ path = View;
+ sourceTree = "<group>";
+ };
+ 4623BF901BE418A2003A04FB /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 4623BFA41BE424BB003A04FB /* LaunchScreen.xib */,
+ 4623BF911BE418A2003A04FB /* Assets.xcassets */,
+ 4623BFA11BE42390003A04FB /* Localizable.strings */,
+ 469DE5011BFC3B0000C7EB52 /* Settings.bundle */,
+ );
+ path = Resources;
+ sourceTree = "<group>";
+ };
+ 4623BF921BE418A2003A04FB /* Supporting files */ = {
+ isa = PBXGroup;
+ children = (
+ 4623BF931BE418A2003A04FB /* Info.plist */,
+ );
+ path = "Supporting files";
+ sourceTree = "<group>";
+ };
+ 4623BF981BE419B6003A04FB /* Service */ = {
+ isa = PBXGroup;
+ children = (
+ 755A61C81E04878F00D035D4 /* ServiceViewControllerDelegate.swift */,
+ 4623BF991BE419FE003A04FB /* ServiceViewController.swift */,
+ 4623BF9A1BE419FE003A04FB /* ServiceViewController.xib */,
+ );
+ path = Service;
+ sourceTree = "<group>";
+ };
+ 4623BFA61BE4257B003A04FB /* Network */ = {
+ isa = PBXGroup;
+ children = (
+ 4640F2901BE4274A00E2AA61 /* API.swift */,
+ 463A91911C0965E900D572E6 /* AlertAPI.swift */,
+ 4623B69B1C07C569007FFE2B /* ControllerAPI.swift */,
+ 4623B6921C078F70007FFE2B /* DisplayAPI.swift */,
+ 4640F2921BE429B900E2AA61 /* PollAPI.swift */,
+ 46A9EED71BFD89DF00E8D520 /* ServiceAPI.swift */,
+ 46FD37861C7959EF00DED423 /* SearchAPI.swift */,
+ 46FD378A1C79770900DED423 /* LiveAPI.swift */,
+ 46FD378C1C797E2B00DED423 /* AddAPI.swift */,
+ 755C78CD1CCE9080001CF70D /* Service.swift */,
+ );
+ path = Network;
+ sourceTree = "<group>";
+ };
+ 463A918A1C093DBD00D572E6 /* Alerts */ = {
+ isa = PBXGroup;
+ children = (
+ 463A918B1C093DD500D572E6 /* AlertsViewController.swift */,
+ 463A918C1C093DD500D572E6 /* AlertsViewController.xib */,
+ );
+ path = Alerts;
+ sourceTree = "<group>";
+ };
+ 46C133421C0A39E80093579F /* Search */ = {
+ isa = PBXGroup;
+ children = (
+ 46C133431C0A3A0F0093579F /* SearchViewController.swift */,
+ 46C133441C0A3A0F0093579F /* SearchViewController.xib */,
+ 46FD37881C796C9B00DED423 /* SearchResultViewController.swift */,
+ );
+ path = Search;
+ sourceTree = "<group>";
+ };
+ 759778A41CF839C200C2E4B4 /* OLP RemoteTests */ = {
+ isa = PBXGroup;
+ children = (
+ 759778A71CF839C200C2E4B4 /* Info.plist */,
+ 759778AD1CF83AC400C2E4B4 /* APITest.swift */,
+ 75667B2A1CFCAE44008FDFE0 /* PollAPITests.swift */,
+ 75667B4B1CFEE85A008FDFE0 /* TestUtils.swift */,
+ 750831B81CFF44FC00CA9299 /* poll_response.json */,
+ 750831BA1CFF594400CA9299 /* service_response.json */,
+ 750831BC1CFF597D00CA9299 /* slides_response.json */,
+ );
+ path = "OLP RemoteTests";
+ sourceTree = "<group>";
+ };
+ 9BD4CA2C346197F51290E305 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 2AEEA392DC2D08B9EAF00B32 /* Pods-OLP RemoteTests.debug.xcconfig */,
+ BF194B8FEA335C68D241C125 /* Pods-OLP RemoteTests.release.xcconfig */,
+ 20B750141C8B3B45881386FA /* Pods-Remote.debug.xcconfig */,
+ 6B75984BB421CA7AAB01F229 /* Pods-Remote.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 462258C81BE29EF300A509C8 /* Remote */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 462258DB1BE29EF300A509C8 /* Build configuration list for PBXNativeTarget "Remote" */;
+ buildPhases = (
+ A942641CDE6E54B2447D4643 /* [CP] Check Pods Manifest.lock */,
+ 462258C51BE29EF300A509C8 /* Sources */,
+ 462258C61BE29EF300A509C8 /* Frameworks */,
+ 462258C71BE29EF300A509C8 /* Resources */,
+ 097501326E5B3EE754239743 /* [CP] Embed Pods Frameworks */,
+ 86DECB90A25A9BBEE8B49C04 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Remote;
+ productName = Remote;
+ productReference = 462258C91BE29EF300A509C8 /* Remote.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 759778A21CF839C200C2E4B4 /* OLP RemoteTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 759778AA1CF839C200C2E4B4 /* Build configuration list for PBXNativeTarget "OLP RemoteTests" */;
+ buildPhases = (
+ BCF6BCAAAC1529152D882FC6 /* [CP] Check Pods Manifest.lock */,
+ 7597789F1CF839C200C2E4B4 /* Sources */,
+ 759778A01CF839C200C2E4B4 /* Frameworks */,
+ 759778A11CF839C200C2E4B4 /* Resources */,
+ F0EA71C50D6F72431C9A5B4E /* [CP] Embed Pods Frameworks */,
+ 8AFF634069CB54C46B80A56F /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "OLP RemoteTests";
+ productName = "OLP RemoteTests";
+ productReference = 759778A31CF839C200C2E4B4 /* OLP RemoteTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 462258C11BE29EF300A509C8 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ CLASSPREFIX = "";
+ LastSwiftUpdateCheck = 0730;
+ LastUpgradeCheck = 0710;
+ ORGANIZATIONNAME = OpenLP;
+ TargetAttributes = {
+ 462258C81BE29EF300A509C8 = {
+ CreatedOnToolsVersion = 7.1;
+ };
+ 759778A21CF839C200C2E4B4 = {
+ CreatedOnToolsVersion = 7.3.1;
+ };
+ };
+ };
+ buildConfigurationList = 462258C41BE29EF300A509C8 /* Build configuration list for PBXProject "Remote" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 462258C01BE29EF300A509C8;
+ productRefGroup = 462258CA1BE29EF300A509C8 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 462258C81BE29EF300A509C8 /* Remote */,
+ 759778A21CF839C200C2E4B4 /* OLP RemoteTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 462258C71BE29EF300A509C8 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 463A918E1C093DD500D572E6 /* AlertsViewController.xib in Resources */,
+ 4623BFA51BE424BB003A04FB /* LaunchScreen.xib in Resources */,
+ 4623BF9F1BE42390003A04FB /* Localizable.strings in Resources */,
+ 4623B6981C07BC2E007FFE2B /* SlidesViewController.xib in Resources */,
+ 4623BF9C1BE419FE003A04FB /* ServiceViewController.xib in Resources */,
+ 4623BF941BE418A2003A04FB /* Assets.xcassets in Resources */,
+ 46C133461C0A3A0F0093579F /* SearchViewController.xib in Resources */,
+ 469DE5021BFC3B0000C7EB52 /* Settings.bundle in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 759778A11CF839C200C2E4B4 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 750831BB1CFF594400CA9299 /* service_response.json in Resources */,
+ 750831BD1CFF597D00CA9299 /* slides_response.json in Resources */,
+ 750831B91CFF44FC00CA9299 /* poll_response.json in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 097501326E5B3EE754239743 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Remote/Pods-Remote-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 86DECB90A25A9BBEE8B49C04 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Remote/Pods-Remote-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 8AFF634069CB54C46B80A56F /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OLP RemoteTests/Pods-OLP RemoteTests-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ A942641CDE6E54B2447D4643 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ 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";
+ showEnvVarsInLog = 0;
+ };
+ BCF6BCAAAC1529152D882FC6 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ 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";
+ showEnvVarsInLog = 0;
+ };
+ F0EA71C50D6F72431C9A5B4E /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OLP RemoteTests/Pods-OLP RemoteTests-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 462258C51BE29EF300A509C8 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 46FD378B1C79770900DED423 /* LiveAPI.swift in Sources */,
+ 4623B6971C07BC2E007FFE2B /* SlidesViewController.swift in Sources */,
+ 46A9EED81BFD89DF00E8D520 /* ServiceAPI.swift in Sources */,
+ 46FD37871C7959EF00DED423 /* SearchAPI.swift in Sources */,
+ 4623B69C1C07C569007FFE2B /* ControllerAPI.swift in Sources */,
+ 463A91851C092E6B00D572E6 /* DictionaryUtil.swift in Sources */,
+ 462395831BE50C5A00B90146 /* ViewControllerUtil.swift in Sources */,
+ 46CC0CED1BE6972300423EB4 /* UserSettings.swift in Sources */,
+ 46FD37891C796C9B00DED423 /* SearchResultViewController.swift in Sources */,
+ 463A918D1C093DD500D572E6 /* AlertsViewController.swift in Sources */,
+ 4640F2951BE42B6E00E2AA61 /* PollModel.swift in Sources */,
+ 75219D021E276111001B6BC8 /* TabSwitchingToRightAnimationController.swift in Sources */,
+ 46A9EED61BFD85FF00E8D520 /* ItemModel.swift in Sources */,
+ 755C78CE1CCE9080001CF70D /* Service.swift in Sources */,
+ 46A9EEDC1BFD8FEE00E8D520 /* SuccessModel.swift in Sources */,
+ 4640F2911BE4274A00E2AA61 /* API.swift in Sources */,
+ 756FA0FD1E28FF060011AE6F /* SlideCell.swift in Sources */,
+ 4623BF9B1BE419FE003A04FB /* ServiceViewController.swift in Sources */,
+ 463A91891C093AE100D572E6 /* ServiceListModel.swift in Sources */,
+ 463A91871C093A2300D572E6 /* LiveModel.swift in Sources */,
+ 4623B69A1C07C47D007FFE2B /* SlideModel.swift in Sources */,
+ 46A612311C78E75D00B61DC8 /* ColorUtil.swift in Sources */,
+ 46C133451C0A3A0F0093579F /* SearchViewController.swift in Sources */,
+ 462258CD1BE29EF300A509C8 /* AppDelegate.swift in Sources */,
+ 4640F2931BE429B900E2AA61 /* PollAPI.swift in Sources */,
+ 462395811BE505EC00B90146 /* SettingsViewController.swift in Sources */,
+ 4623B6931C078F70007FFE2B /* DisplayAPI.swift in Sources */,
+ 463A91921C0965E900D572E6 /* AlertAPI.swift in Sources */,
+ 46FD378D1C797E2B00DED423 /* AddAPI.swift in Sources */,
+ 46FD378F1C79867C00DED423 /* ErrorUtil.swift in Sources */,
+ 46A612351C79572600B61DC8 /* PluginModel.swift in Sources */,
+ 759464A51CEB8493001A56BF /* SettingsControllerPresenter.swift in Sources */,
+ 755A61C91E04878F00D035D4 /* ServiceViewControllerDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7597789F1CF839C200C2E4B4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 75667B561CFEE949008FDFE0 /* ItemModel.swift in Sources */,
+ 75667B591CFEE949008FDFE0 /* LiveModel.swift in Sources */,
+ 75667B521CFEE938008FDFE0 /* AddAPI.swift in Sources */,
+ 75667B5C1CFEFF7E008FDFE0 /* DictionaryUtil.swift in Sources */,
+ 75667B5E1CFEFF86008FDFE0 /* ErrorUtil.swift in Sources */,
+ 75667B5A1CFEE949008FDFE0 /* ServiceListModel.swift in Sources */,
+ 75667B571CFEE949008FDFE0 /* PollModel.swift in Sources */,
+ 75667B581CFEE949008FDFE0 /* SlideModel.swift in Sources */,
+ 75667B281CFCA8B1008FDFE0 /* API.swift in Sources */,
+ 75667B2B1CFCAE44008FDFE0 /* PollAPITests.swift in Sources */,
+ 75667B4D1CFEE92C008FDFE0 /* ControllerAPI.swift in Sources */,
+ 75667B5F1CFEFFA7008FDFE0 /* DisplayAPI.swift in Sources */,
+ 75667B4E1CFEE930008FDFE0 /* PollAPI.swift in Sources */,
+ 75667B541CFEE93D008FDFE0 /* AlertAPI.swift in Sources */,
+ 75667B531CFEE938008FDFE0 /* Service.swift in Sources */,
+ 75667B291CFCA8C9008FDFE0 /* UserSettings.swift in Sources */,
+ 75667B4C1CFEE85A008FDFE0 /* TestUtils.swift in Sources */,
+ 75667B5D1CFEFF83008FDFE0 /* ColorUtil.swift in Sources */,
+ 75667B551CFEE949008FDFE0 /* SuccessModel.swift in Sources */,
+ 75667B4F1CFEE938008FDFE0 /* ServiceAPI.swift in Sources */,
+ 75667B5B1CFEE949008FDFE0 /* PluginModel.swift in Sources */,
+ 759778AE1CF83AC400C2E4B4 /* APITest.swift in Sources */,
+ 75667B511CFEE938008FDFE0 /* LiveAPI.swift in Sources */,
+ 75667B501CFEE938008FDFE0 /* SearchAPI.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 4623BFA11BE42390003A04FB /* Localizable.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 4623BFA01BE42390003A04FB /* en */,
+ );
+ name = Localizable.strings;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 462258D91BE29EF300A509C8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = "";
+ };
+ name = Debug;
+ };
+ 462258DA1BE29EF300A509C8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SWIFT_VERSION = "";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 462258DC1BE29EF300A509C8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 20B750141C8B3B45881386FA /* Pods-Remote.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ DEFINES_MODULE = NO;
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = "Remote/Supporting files/Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = org.openlp.Remote;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 2.3;
+ };
+ name = Debug;
+ };
+ 462258DD1BE29EF300A509C8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 6B75984BB421CA7AAB01F229 /* Pods-Remote.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ DEFINES_MODULE = NO;
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = "Remote/Supporting files/Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = org.openlp.Remote;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 2.3;
+ };
+ name = Release;
+ };
+ 759778AB1CF839C200C2E4B4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 2AEEA392DC2D08B9EAF00B32 /* Pods-OLP RemoteTests.debug.xcconfig */;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ INFOPLIST_FILE = "OLP RemoteTests/Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.openlp.OLP-RemoteTests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 2.3;
+ };
+ name = Debug;
+ };
+ 759778AC1CF839C200C2E4B4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BF194B8FEA335C68D241C125 /* Pods-OLP RemoteTests.release.xcconfig */;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ INFOPLIST_FILE = "OLP RemoteTests/Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.openlp.OLP-RemoteTests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 2.3;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 462258C41BE29EF300A509C8 /* Build configuration list for PBXProject "Remote" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 462258D91BE29EF300A509C8 /* Debug */,
+ 462258DA1BE29EF300A509C8 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 462258DB1BE29EF300A509C8 /* Build configuration list for PBXNativeTarget "Remote" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 462258DC1BE29EF300A509C8 /* Debug */,
+ 462258DD1BE29EF300A509C8 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 759778AA1CF839C200C2E4B4 /* Build configuration list for PBXNativeTarget "OLP RemoteTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 759778AB1CF839C200C2E4B4 /* Debug */,
+ 759778AC1CF839C200C2E4B4 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 462258C11BE29EF300A509C8 /* Project object */;
+}
=== added directory 'Remote.xcodeproj/project.xcworkspace'
=== added file 'Remote.xcodeproj/project.xcworkspace/contents.xcworkspacedata'
--- Remote.xcodeproj/project.xcworkspace/contents.xcworkspacedata 1970-01-01 00:00:00 +0000
+++ Remote.xcodeproj/project.xcworkspace/contents.xcworkspacedata 2017-01-21 18:06:11 +0000
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:Remote.xcodeproj">
+ </FileRef>
+</Workspace>
=== added directory 'Remote.xcworkspace'
=== added file 'Remote.xcworkspace/contents.xcworkspacedata'
--- Remote.xcworkspace/contents.xcworkspacedata 1970-01-01 00:00:00 +0000
+++ Remote.xcworkspace/contents.xcworkspacedata 2017-01-21 18:06:11 +0000
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "group:Remote.xcodeproj">
+ </FileRef>
+ <FileRef
+ location = "group:Pods/Pods.xcodeproj">
+ </FileRef>
+</Workspace>
=== added file 'Remote/AppDelegate.swift'
--- Remote/AppDelegate.swift 1970-01-01 00:00:00 +0000
+++ Remote/AppDelegate.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,117 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import BlockLooper
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate, ServiceViewControllerDelegate {
+
+ var window: UIWindow?
+ var service: Service!
+ var settings: UserSettings!
+ var tabBarController: UITabBarController!
+ var useAnimator: Bool = false
+
+ enum OpenLPTab: Int {
+ case ServiceTab
+ case SlidesTab
+ case AlertsTab
+ case SearchTab
+ }
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
+
+ settings = UserSettings(defaults: NSUserDefaults.standardUserDefaults())
+ settings.registerDefaults()
+ service = Service(settings: settings)
+
+ var rootViewControllers = [UINavigationController]()
+ var navigationController: UINavigationController
+
+ let serviceViewController = ServiceViewController(settings: settings, service: service, delegate: self)
+ navigationController = UINavigationController(rootViewController: serviceViewController)
+ rootViewControllers.append(navigationController)
+
+ let slidesViewController = SlidesViewController(settings: settings, service: service)
+ navigationController = UINavigationController(rootViewController: slidesViewController)
+ rootViewControllers.append(navigationController)
+
+ service.pollAPI.serviceDelegate = serviceViewController
+ service.pollAPI.slidesDelegate = slidesViewController
+
+ let alertsViewController = AlertsViewController(settings: settings, service: service)
+ navigationController = UINavigationController(rootViewController: alertsViewController)
+ rootViewControllers.append(navigationController)
+
+ let searchViewController = SearchViewController(settings: settings, service: service)
+ navigationController = UINavigationController(rootViewController: searchViewController)
+ rootViewControllers.append(navigationController)
+
+ let tabBarController = UITabBarController()
+ tabBarController.viewControllers = rootViewControllers
+
+ self.tabBarController = tabBarController
+ tabBarController.delegate = self
+
+ self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
+ self.window?.rootViewController = tabBarController
+ self.window?.makeKeyAndVisible()
+
+ settings.resetDefaultsIfNeeded()
+
+ BlockLooper.executeBlockWithRate(2.0) {
+ if self.settings.validateURL() {
+ if self.service.pauseLoopPolling == false {
+ self.service.pollAPI.poll()
+ }
+ }
+ return false
+ }
+
+ return true
+ }
+
+
+ func withAnimator(block:()-> Void) -> Void {
+ useAnimator = true
+ block()
+ useAnimator = false
+ }
+
+
+ // MARK: - ServiceViewControllerDelegate
+ func serviceViewControllerDidSelectItem(item: ItemModel) {
+ withAnimator {
+ self.tabBarController.selectedIndex = OpenLPTab.SlidesTab.rawValue
+ }
+ }
+
+
+ // MARK: - TabBarControllerDelegate
+ func tabBarController(tabBarController: UITabBarController, animationControllerForTransitionFromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
+ return useAnimator ? TabSwitchingToRightAnimationController(tabBarController: self.tabBarController) : nil
+ }
+}
+
=== added directory 'Remote/Classes'
=== added directory 'Remote/Classes/Controller'
=== added directory 'Remote/Classes/Controller/Alerts'
=== added file 'Remote/Classes/Controller/Alerts/AlertsViewController.swift'
--- Remote/Classes/Controller/Alerts/AlertsViewController.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Alerts/AlertsViewController.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,170 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import UITextView_Placeholder
+
+// MARK: - AlertsViewController
+
+class AlertsViewController: UIViewController {
+
+ @IBOutlet weak var textAlert: UITextView!
+ @IBOutlet weak var btShow: UIButton!
+ @IBOutlet weak var btShowBottomConstraint: NSLayoutConstraint!
+
+ private var btCancel: UIBarButtonItem!
+ private let service: Service!
+ private let settingsPresenter: SettingsControllerPresenter!
+
+ // MARK: Init
+
+ init(settings: UserSettings, service: Service) {
+ self.service = service
+ settingsPresenter = SettingsControllerPresenter(settings: settings, pollAPI: service.pollAPI)
+ super.init(nibName: "AlertsViewController", bundle: nil)
+ self.setupNavigationBar()
+ self.setupTabBar()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ self.service = nil
+ self.settingsPresenter = nil
+ super.init(coder: aDecoder)
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.setupAlertTextView()
+ self.setupShowButton()
+ self.setupObservers()
+ }
+
+ // MARK: Setup
+
+ private func setupNavigationBar() {
+ self.navigationItem.leftBarButtonItem = settingsPresenter.settingsBarButton(self)
+
+ self.navigationItem.title = NSLocalizedString("Alerts", comment: "")
+
+ let strCancel = NSLocalizedString("Cancel", comment: "")
+ self.btCancel = UIBarButtonItem(title: strCancel, style: .Plain, target: self, action: #selector(AlertsViewController.clear))
+ self.btCancel.enabled = false
+ self.navigationItem.rightBarButtonItem = self.btCancel
+ }
+
+ private func setupAlertTextView() {
+ self.textAlert.placeholder = NSLocalizedString("Type here...", comment: "")
+ }
+
+ private func setupShowButton() {
+ let strShow = NSLocalizedString("Show", comment: "")
+ self.btShow.setTitle(strShow, forState: .Normal)
+ self.btShow.enabled = false
+ }
+
+ private func setupTabBar() {
+ self.tabBarItem.title = NSLocalizedString("Alerts", comment: "")
+ self.tabBarItem.image = UIImage(named: "ic_alerts")
+ }
+
+ private func setupObservers() {
+ NSNotificationCenter.defaultCenter().addObserver(self,
+ selector: #selector(AlertsViewController.keyboardWillAppear(_:)),
+ name: UIKeyboardWillShowNotification,
+ object: nil)
+ NSNotificationCenter.defaultCenter().addObserver(self,
+ selector: #selector(AlertsViewController.keyboardWillDisappear(_:)),
+ name: UIKeyboardWillHideNotification,
+ object: nil)
+ }
+
+ // MARK: My methods
+
+ @objc private func clear() {
+ self.textAlert.resignFirstResponder()
+ self.textAlert.text = ""
+ }
+
+ @IBAction func showAlert() {
+ self.service.alertAPI.alert(self.textAlert.text) { success, error in
+ if let error = error, message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ } else {
+ let strNotification = NSLocalizedString("Alert showed!", comment: "")
+ self.displayNotification(strNotification)
+ self.clear()
+ }
+ }
+ }
+
+ // MARK: Keyboard
+
+ @objc func keyboardWillAppear(notification: NSNotification) {
+ self.btCancel.enabled = true
+
+ let keyboardRect = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
+ let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
+ self.btShowBottomConstraint.constant = keyboardRect.size.height + 8
+ UIView.animateWithDuration(animationDuration) {
+ self.view.layoutIfNeeded()
+ }
+ }
+
+ @objc func keyboardWillDisappear(notification: NSNotification) {
+ self.btCancel.enabled = false
+
+ let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
+ self.btShowBottomConstraint.constant = 57
+ UIView.animateWithDuration(animationDuration) {
+ self.view.layoutIfNeeded()
+ }
+ }
+
+}
+
+// MARK: - UITextViewDelegate
+
+extension AlertsViewController: UITextViewDelegate {
+
+ func textViewDidChange(textView: UITextView) {
+ if textView.text == "" {
+ self.btShow.enabled = false
+ } else {
+ self.btShow.enabled = true
+ }
+ }
+
+ func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
+
+ if text.containsString("\n") {
+ let newText = text.stringByReplacingOccurrencesOfString("\n", withString: " ")
+ let fullText = (textView.text as NSString).stringByReplacingCharactersInRange(range, withString: newText)
+ textView.text = fullText
+ return false
+ }
+
+ return true
+ }
+
+}
=== added file 'Remote/Classes/Controller/Alerts/AlertsViewController.xib'
--- Remote/Classes/Controller/Alerts/AlertsViewController.xib 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Alerts/AlertsViewController.xib 2017-01-21 18:06:11 +0000
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AlertsViewController" customModule="Remote" customModuleProvider="target">
+ <connections>
+ <outlet property="btShow" destination="Ghe-De-cTK" id="osi-K2-d4M"/>
+ <outlet property="btShowBottomConstraint" destination="K4x-an-92n" id="1F0-Ne-xHI"/>
+ <outlet property="textAlert" destination="2pd-kX-chX" id="QmG-hg-GHI"/>
+ <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+ </connections>
+ </placeholder>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ghe-De-cTK">
+ <rect key="frame" x="8" y="513" width="584" height="30"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="30" id="OBd-Io-d3I"/>
+ </constraints>
+ <state key="normal" title="Show"/>
+ <connections>
+ <action selector="showAlert" destination="-1" eventType="touchUpInside" id="ftd-z4-HVF"/>
+ </connections>
+ </button>
+ <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2pd-kX-chX">
+ <rect key="frame" x="8" y="72" width="584" height="433"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <color key="textColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+ <fontDescription key="fontDescription" type="system" pointSize="18"/>
+ <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
+ <connections>
+ <outlet property="delegate" destination="-1" id="GU4-8w-rq1"/>
+ </connections>
+ </textView>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="bottom" secondItem="Ghe-De-cTK" secondAttribute="bottom" constant="57" id="K4x-an-92n"/>
+ <constraint firstItem="2pd-kX-chX" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="72" id="NMh-Oa-kWf"/>
+ <constraint firstAttribute="trailing" secondItem="2pd-kX-chX" secondAttribute="trailing" constant="8" id="cDZ-4H-D4w"/>
+ <constraint firstItem="2pd-kX-chX" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" constant="8" id="rIu-Xi-k1Q"/>
+ <constraint firstItem="Ghe-De-cTK" firstAttribute="top" secondItem="2pd-kX-chX" secondAttribute="bottom" constant="8" id="rK5-8t-rdT"/>
+ <constraint firstItem="Ghe-De-cTK" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" constant="8" id="vRB-rb-s4P"/>
+ <constraint firstAttribute="trailing" secondItem="Ghe-De-cTK" secondAttribute="trailing" constant="8" id="vx4-De-Ma7"/>
+ </constraints>
+ <simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
+ <simulatedTabBarMetrics key="simulatedBottomBarMetrics"/>
+ <edgeInsets key="layoutMargins" top="72" left="8" bottom="57" right="8"/>
+ </view>
+ </objects>
+</document>
=== added directory 'Remote/Classes/Controller/Search'
=== added file 'Remote/Classes/Controller/Search/SearchResultViewController.swift'
--- Remote/Classes/Controller/Search/SearchResultViewController.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Search/SearchResultViewController.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,135 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+
+class SearchResultViewController: UITableViewController {
+
+ private var items: [ItemModel]!
+ private let service: Service!
+
+ init(items: [ItemModel], service: Service) {
+ self.items = items
+ self.service = service
+ super.init(style: .Plain)
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ self.service = nil
+ super.init(coder: aDecoder)
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.setupNavigationBar()
+ self.setupTableView()
+ }
+
+ // MARK: Setup
+
+ private func setupNavigationBar() {
+ self.navigationItem.title = NSLocalizedString("Results", comment: "")
+ }
+
+ private func setupTableView() {
+ self.tableView.estimatedRowHeight = 44
+ self.tableView.rowHeight = UITableViewAutomaticDimension
+ }
+
+ // MARK: Table view data source
+
+ override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return self.items.count
+ }
+
+ override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ var cell = tableView.dequeueReusableCellWithIdentifier("Cell")
+ if cell == nil {
+ cell = UITableViewCell(style: .Default, reuseIdentifier: "Cell")
+ cell!.textLabel?.numberOfLines = 0
+ }
+ let item = self.items[indexPath.row]
+ cell!.textLabel?.text = item.title
+ return cell!
+ }
+
+ // MARK: Table view delegate
+
+ override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ func showErrorNotification(error: NSError) {
+ if let message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ }
+ }
+ func itemAddedNotification() {
+ let message = NSLocalizedString("Item added.", comment: "")
+ self.displayNotification(message)
+ }
+ let item = self.items[indexPath.row]
+ let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
+ let goLiveStr = NSLocalizedString("Go Live", comment: "")
+ let goLiveAction = UIAlertAction(title: goLiveStr, style: .Default) { _ in
+ tableView.deselectRowAtIndexPath(indexPath, animated: true)
+ self.service.liveAPI.goItemToLive(item, plugin: Plugin(rawValue: item.plugin!)!) { error in
+ if let error = error {
+ showErrorNotification(error)
+ return
+ }
+ self.tabBarController?.selectedIndex = 1
+ }
+ }
+ let addStr = NSLocalizedString("Add to Service", comment: "")
+ let addAction = UIAlertAction(title: addStr, style: .Default) { _ in
+ tableView.deselectRowAtIndexPath(indexPath, animated: true)
+ self.service.addAPI.addItem(item, plugin: Plugin(rawValue: item.plugin!)!) { error in
+ if let error = error {
+ showErrorNotification(error)
+ } else {
+ itemAddedNotification()
+ }
+ }
+ }
+ let addAndGoStr = NSLocalizedString("Add & Go to Service", comment: "")
+ let addAndGoAction = UIAlertAction(title: addAndGoStr, style: .Default) { _ in
+ tableView.deselectRowAtIndexPath(indexPath, animated: true)
+ self.service.addAPI.addItem(item, plugin: Plugin(rawValue: item.plugin!)!) { error in
+ if let error = error {
+ showErrorNotification(error)
+ return
+ }
+ self.tabBarController?.selectedIndex = 0
+ }
+ }
+ let cancelStr = NSLocalizedString("Cancel", comment: "")
+ let cancelAction = UIAlertAction(title: cancelStr, style: .Cancel) { _ in
+ tableView.deselectRowAtIndexPath(indexPath, animated: true)
+ }
+ alertController.addAction(goLiveAction)
+ alertController.addAction(addAction)
+ alertController.addAction(addAndGoAction)
+ alertController.addAction(cancelAction)
+ self.presentViewController(alertController, animated: true, completion: nil)
+ }
+
+}
=== added file 'Remote/Classes/Controller/Search/SearchViewController.swift'
--- Remote/Classes/Controller/Search/SearchViewController.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Search/SearchViewController.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,199 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import CWStatusBarNotification
+
+// MARK: - SearchViewController
+
+class SearchViewController: UIViewController {
+
+ @IBOutlet weak var lbTitle: UILabel!
+ @IBOutlet weak var pickerView: UIPickerView!
+
+ private var notifications: CWStatusBarNotification!
+ private var textField: UITextField!
+ private var plugins: [Plugin]!
+ private let service: Service!
+ private var settingsPresenter: SettingsControllerPresenter!
+
+ // MARK: Init
+
+ init(settings: UserSettings, service: Service) {
+ self.service = service
+ self.settingsPresenter = SettingsControllerPresenter(settings: settings, pollAPI: service.pollAPI)
+ super.init(nibName: "SearchViewController", bundle: nil)
+ self.setupNavigationBar()
+ self.setupTabBar()
+ self.setupOptions()
+ self.setupNotifications()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ self.service = nil
+ self.settingsPresenter = nil
+ super.init(coder: aDecoder)
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.setupPickerView()
+ self.setupGestures()
+ }
+
+ // MARK: Setup
+
+ private func setupNavigationBar() {
+ self.navigationItem.leftBarButtonItem = settingsPresenter.settingsBarButton(self)
+
+ self.textField = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 30))
+ self.textField.backgroundColor = UIColor.whiteColor()
+ self.textField.textAlignment = .Center
+ self.textField.clearButtonMode = .WhileEditing
+ self.textField.placeholder = NSLocalizedString("Type here...", comment: "")
+ self.textField.layer.borderWidth = 0.7
+ self.textField.layer.borderColor = kGreyColor.CGColor
+ self.textField.layer.cornerRadius = 5
+ self.textField.returnKeyType = .Search
+ self.textField.delegate = self
+ self.navigationItem.titleView = self.textField
+
+ let btSearch = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: #selector(SearchViewController.search))
+ self.navigationItem.rightBarButtonItem = btSearch
+ }
+
+ private func setupPickerView() {
+ self.lbTitle.text = NSLocalizedString("Search for", comment: "")
+ self.pickerView.layer.borderColor = kGreyColor.CGColor
+ self.pickerView.layer.borderWidth = 0.7
+ }
+
+ private func setupOptions() {
+ self.plugins = [
+ .Songs,
+ .Bibles,
+ .Presentations,
+ .Images,
+ .Media,
+ .Custom
+ ]
+ }
+
+ private func setupGestures() {
+ var gesture: UIGestureRecognizer
+ gesture = UITapGestureRecognizer(target: self, action: #selector(SearchViewController.dismissKeyboard))
+ gesture.delegate = self
+ self.view.addGestureRecognizer(gesture)
+ gesture = UIPanGestureRecognizer(target: self, action: #selector(SearchViewController.dismissKeyboard))
+ self.pickerView.addGestureRecognizer(gesture)
+ }
+
+ private func setupTabBar() {
+ self.tabBarItem = UITabBarItem(tabBarSystemItem: .Search, tag: 0)
+ self.tabBarItem.title = NSLocalizedString("Search", comment: "")
+ }
+
+ private func setupNotifications() {
+ self.notifications = CWStatusBarNotification()
+ self.notifications.notificationLabelTextColor = UIColor.whiteColor()
+ self.notifications.notificationAnimationInStyle = .Top
+ self.notifications.notificationAnimationOutStyle = .Top
+ }
+
+ // MARK: My functions
+
+ @objc private func search() {
+ self.dismissKeyboard()
+ let plugin = self.plugins[self.pickerView.selectedRowInComponent(0)]
+ let text = self.textField.text!
+ service.searchAPI.search(plugin: plugin, text: text) { items, error in
+ if let error = error {
+ let message = NSLocalizedString("An error occurred. Try again...", comment: "")
+ self.notifications.notificationLabelBackgroundColor = kRedColor
+ self.notifications.displayNotificationWithMessage(message, forDuration: 3)
+ print(error)
+ return
+ } else if items?.count == 0 {
+ let message = NSLocalizedString("No results found", comment: "")
+ self.notifications.notificationLabelBackgroundColor = kBlueColor
+ self.notifications.displayNotificationWithMessage(message, forDuration: 3)
+ return
+ }
+ let resultsViewController = SearchResultViewController(items: items!, service: self.service)
+ self.navigationController?.pushViewController(resultsViewController, animated: true)
+ }
+ }
+
+ @objc private func dismissKeyboard() {
+ self.textField.resignFirstResponder()
+ }
+
+}
+
+// MARK: - UIPickerViewDataSource
+
+extension SearchViewController: UIPickerViewDataSource {
+
+ func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
+ return 1
+ }
+
+ func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
+ return self.plugins.count
+ }
+
+}
+
+// MARK: - UIPickerViewDelegate
+
+extension SearchViewController: UIPickerViewDelegate {
+
+ func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
+ let option = self.plugins[row]
+ return option.name()
+ }
+
+}
+
+// MARK: - UIGestureRecognizerDelegate
+
+extension SearchViewController: UIGestureRecognizerDelegate {
+
+ func gestureRecognizer(gestureRecognizer: UIGestureRecognizer,
+ shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
+ return true
+ }
+
+}
+
+// MARK: - UITextFieldDelegate
+
+extension SearchViewController: UITextFieldDelegate {
+
+ func textFieldShouldReturn(textField: UITextField) -> Bool {
+ self.search()
+ return true
+ }
+
+}
=== added file 'Remote/Classes/Controller/Search/SearchViewController.xib'
--- Remote/Classes/Controller/Search/SearchViewController.xib 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Search/SearchViewController.xib 2017-01-21 18:06:11 +0000
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SearchViewController" customModule="Remote" customModuleProvider="target">
+ <connections>
+ <outlet property="lbTitle" destination="Fs3-0O-h5s" id="bX5-R7-uuQ"/>
+ <outlet property="pickerView" destination="uQH-Hu-pKq" id="dVv-fM-Qne"/>
+ <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+ </connections>
+ </placeholder>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <pickerView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uQH-Hu-pKq">
+ <rect key="frame" x="-1" y="95" width="602" height="216"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="216" id="h0N-rj-bVq"/>
+ </constraints>
+ <connections>
+ <outlet property="dataSource" destination="-1" id="srM-Kj-fVC"/>
+ <outlet property="delegate" destination="-1" id="29G-bI-VU1"/>
+ </connections>
+ </pickerView>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Search for" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fs3-0O-h5s">
+ <rect key="frame" x="0.0" y="75" width="600" height="20"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="20" id="j81-5V-cKH"/>
+ </constraints>
+ <fontDescription key="fontDescription" type="system" pointSize="10"/>
+ <color key="textColor" red="0.1803921568627451" green="0.1803921568627451" blue="0.1803921568627451" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstItem="Fs3-0O-h5s" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="8Xs-Iz-XNF"/>
+ <constraint firstAttribute="trailing" secondItem="Fs3-0O-h5s" secondAttribute="trailing" id="EmD-yx-Afe"/>
+ <constraint firstAttribute="trailing" secondItem="uQH-Hu-pKq" secondAttribute="trailing" constant="-1" id="Ubw-DG-2RK"/>
+ <constraint firstItem="Fs3-0O-h5s" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="75" id="q8W-QU-hlc"/>
+ <constraint firstItem="uQH-Hu-pKq" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" constant="-1" id="raw-ce-rql"/>
+ <constraint firstItem="uQH-Hu-pKq" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="40" id="v0C-VM-VFg"/>
+ <constraint firstItem="uQH-Hu-pKq" firstAttribute="top" secondItem="Fs3-0O-h5s" secondAttribute="bottom" id="vzP-AH-6sj"/>
+ </constraints>
+ <variation key="default">
+ <mask key="constraints">
+ <exclude reference="v0C-VM-VFg"/>
+ </mask>
+ </variation>
+ </view>
+ </objects>
+</document>
=== added directory 'Remote/Classes/Controller/Service'
=== added file 'Remote/Classes/Controller/Service/ServiceViewController.swift'
--- Remote/Classes/Controller/Service/ServiceViewController.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Service/ServiceViewController.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,203 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+
+// MARK: - ServiceViewController
+
+class ServiceViewController: UIViewController {
+
+ @IBOutlet weak var tableView: UITableView!
+ @IBOutlet weak var segProjectionState: UISegmentedControl!
+
+ private var items = [ItemModel]()
+ private var dicItemRow = [String: Int]()
+ private let service: Service!
+ private var settingsPresenter: SettingsControllerPresenter!
+ private let delegate: ServiceViewControllerDelegate!
+
+ // MARK: Init
+
+ init(settings: UserSettings, service: Service, delegate: ServiceViewControllerDelegate) {
+ self.service = service
+ self.settingsPresenter = SettingsControllerPresenter(settings: settings, pollAPI: service.pollAPI)
+ self.delegate = delegate
+ super.init(nibName: "ServiceViewController", bundle: nil)
+ self.setupNavigationBar()
+ self.setupTabBar()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ self.service = nil
+ self.delegate = nil
+ super.init(coder: aDecoder)
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.setupTableView()
+ self.setupSegmentedControl()
+ }
+
+ // MARK: Setup
+
+ private func setupNavigationBar() {
+ let btAdd = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(ServiceViewController.goToSearchViewController))
+ self.navigationItem.leftBarButtonItems = [
+ settingsPresenter.settingsBarButton(self),
+ btAdd
+ ]
+
+ self.navigationItem.title = NSLocalizedString("Service", comment: "")
+
+ let imagePrevious = UIImage(named: "ic_arrow-up")
+ let btPrevious = UIBarButtonItem(image: imagePrevious, style: .Plain, target: self, action: #selector(ServiceViewController.previousItem))
+ let imageNext = UIImage(named: "ic_arrow-down")
+ let btNext = UIBarButtonItem(image: imageNext, style: .Plain, target: self, action: #selector(ServiceViewController.nextItem))
+ self.navigationItem.rightBarButtonItems = [
+ btNext,
+ btPrevious
+ ]
+ }
+
+ private func setupTabBar() {
+ self.tabBarItem.title = NSLocalizedString("Service", comment: "")
+ self.tabBarItem.image = UIImage(named: "ic_service")
+ }
+
+ private func setupTableView() {
+ self.tableView.rowHeight = UITableViewAutomaticDimension
+ self.tableView.estimatedRowHeight = 44
+ self.tableView?.decelerationRate = UIScrollViewDecelerationRateFast
+ }
+
+ private func setupSegmentedControl() {
+ self.segProjectionState.selectedSegmentIndex = -1
+ }
+
+ // MARK: My methods
+
+ @IBAction func sementedControlValueChanged() {
+ let index = self.segProjectionState.selectedSegmentIndex
+ if let state = ProjectionState(rawValue: index) {
+ self.service.displayAPI.projectionState(state) { _, error in
+ if let error = error, let message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ }
+ }
+ }
+ }
+
+ @objc private func goToSearchViewController() {
+ self.tabBarController?.selectedIndex = 3
+ }
+
+ @objc private func previousItem() {
+ self.service.serviceAPI.previous() { _, error in
+ if let error = error, let message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ }
+ }
+ }
+
+ @objc private func nextItem() {
+ self.service.serviceAPI.next() { _, error in
+ if let error = error, let message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ }
+ }
+ }
+
+}
+
+// MARK: - UITableViewDatasource
+
+extension ServiceViewController: UITableViewDataSource {
+
+ func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return self.items.count
+ }
+
+ func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ var cell = tableView.dequeueReusableCellWithIdentifier("Cell")
+
+ if cell == nil {
+ cell = UITableViewCell(style: .Default, reuseIdentifier: "Cell")
+ cell!.textLabel?.numberOfLines = 0
+ }
+
+ let item = self.items[indexPath.row]
+ cell!.textLabel?.text = item.title
+
+ return cell!
+ }
+
+}
+
+// MARK: - UITableViewDelegate
+
+extension ServiceViewController: UITableViewDelegate {
+
+ func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ self.service.serviceAPI.set(row: indexPath.row) { success, error in
+ if let error = error, let message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ tableView.deselectRowAtIndexPath(indexPath, animated: true)
+ } else if success {
+ self.delegate.serviceViewControllerDidSelectItem(self.items[indexPath.row])
+ }
+ }
+ }
+}
+
+// MARK: - PollAPIServiceDelegate
+
+extension ServiceViewController: PollAPIServiceDelegate {
+
+ func updateServiceList(items: [ItemModel]) {
+ self.items = items
+ self.tableView.reloadData()
+
+ if items.count > 0 {
+ for i in 0...items.count-1 {
+ let item = items[i]
+ self.dicItemRow[item.id!] = i
+ }
+ }
+ }
+
+ func updateSelectedItem(itemId id: String) {
+ if let selectedRow = self.dicItemRow[id] {
+ if selectedRow < self.items.count {
+ let indexPath = NSIndexPath(forRow: selectedRow, inSection: 0)
+ self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .None)
+ }
+ }
+ }
+
+ func updateProjectionState(state: ProjectionState) {
+ self.segProjectionState.selectedSegmentIndex = state.rawValue
+ }
+
+}
=== added file 'Remote/Classes/Controller/Service/ServiceViewController.xib'
--- Remote/Classes/Controller/Service/ServiceViewController.xib 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Service/ServiceViewController.xib 2017-01-21 18:06:11 +0000
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+ <device id="retina4_0" orientation="portrait">
+ <adaptation id="fullscreen"/>
+ </device>
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ServiceViewController" customModule="Remote" customModuleProvider="target">
+ <connections>
+ <outlet property="segProjectionState" destination="qVP-Yj-p1e" id="AbF-Sl-UQx"/>
+ <outlet property="tableView" destination="A9d-va-PLe" id="Bt5-Zw-0Tg"/>
+ <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+ </connections>
+ </placeholder>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+ <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <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">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="556"/>
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <connections>
+ <outlet property="dataSource" destination="-1" id="5bH-k5-YRz"/>
+ <outlet property="delegate" destination="-1" id="hnH-to-FEe"/>
+ </connections>
+ </tableView>
+ <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bfe-Nb-Utk">
+ <rect key="frame" x="0.0" y="507" width="600" height="44"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="44" id="IBR-6A-7Oo"/>
+ </constraints>
+ <items>
+ <barButtonItem style="plain" systemItem="flexibleSpace" id="xr9-Is-Mr0"/>
+ <barButtonItem style="plain" id="nQb-HK-2zw">
+ <segmentedControl key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" segmentControlStyle="bar" selectedSegmentIndex="0" id="qVP-Yj-p1e">
+ <rect key="frame" x="150" y="7" width="300" height="30"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <segments>
+ <segment title="Blank"/>
+ <segment title="Theme"/>
+ <segment title="Desktop"/>
+ <segment title="Show"/>
+ </segments>
+ <connections>
+ <action selector="sementedControlValueChanged" destination="-1" eventType="valueChanged" id="YOp-zI-OuN"/>
+ </connections>
+ </segmentedControl>
+ </barButtonItem>
+ <barButtonItem style="plain" systemItem="flexibleSpace" id="Hbq-ee-VXX"/>
+ </items>
+ </toolbar>
+ </subviews>
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <constraints>
+ <constraint firstItem="A9d-va-PLe" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="0X6-ik-XVD"/>
+ <constraint firstAttribute="bottom" secondItem="A9d-va-PLe" secondAttribute="bottom" constant="44" id="OCH-8f-c0t"/>
+ <constraint firstAttribute="trailing" secondItem="A9d-va-PLe" secondAttribute="trailing" id="d2N-qY-fUC"/>
+ <constraint firstAttribute="trailing" secondItem="bfe-Nb-Utk" secondAttribute="trailing" id="hJC-R9-UFZ"/>
+ <constraint firstAttribute="bottom" secondItem="bfe-Nb-Utk" secondAttribute="bottom" constant="49" id="tgT-e3-frG"/>
+ <constraint firstItem="bfe-Nb-Utk" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="u5M-Sh-09Q"/>
+ <constraint firstItem="A9d-va-PLe" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="y6U-4G-9aw"/>
+ </constraints>
+ <simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
+ <simulatedTabBarMetrics key="simulatedBottomBarMetrics"/>
+ </view>
+ </objects>
+</document>
=== added file 'Remote/Classes/Controller/Service/ServiceViewControllerDelegate.swift'
--- Remote/Classes/Controller/Service/ServiceViewControllerDelegate.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Service/ServiceViewControllerDelegate.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+
+protocol ServiceViewControllerDelegate {
+ func serviceViewControllerDidSelectItem(item: ItemModel)
+}
=== added directory 'Remote/Classes/Controller/Settings'
=== added file 'Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift'
--- Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Settings/SettingsControllerPresenter.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+
+import UIKit
+
+class SettingsControllerPresenter: NSObject {
+
+ let pollAPI: PollAPI
+ let settings: UserSettings
+ var fromController: UIViewController?
+
+ init(settings: UserSettings, pollAPI: PollAPI) {
+ self.pollAPI = pollAPI
+ self.settings = settings
+ super.init()
+ }
+
+ func settingsBarButton(fromController: UIViewController) -> UIBarButtonItem {
+ self.fromController = fromController
+ let imageSettings = UIImage(named: "ic_gear")
+ let btSettings = UIBarButtonItem(image: imageSettings, style: .Plain, target: self, action: #selector(SettingsControllerPresenter.presentSettingViewController))
+ return btSettings
+ }
+
+
+ func presentSettingViewController() {
+ let settingsController = SettingsViewController(settings:settings, pollAPI: pollAPI)
+ let navigationController = UINavigationController(rootViewController: settingsController)
+ fromController!.showViewController(navigationController, sender: nil)
+ }
+}
=== added file 'Remote/Classes/Controller/Settings/SettingsViewController.swift'
--- Remote/Classes/Controller/Settings/SettingsViewController.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Settings/SettingsViewController.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,105 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import InAppSettingsKit
+
+class SettingsViewController: IASKAppSettingsViewController {
+
+ private let hiddenSettingsKeys = ["auth.userID", "auth.password"] as Set<NSObject>
+ private let pollAPI: PollAPI!
+ private let settings: UserSettings!
+
+ init(settings: UserSettings, pollAPI: PollAPI) {
+ self.pollAPI = pollAPI
+ self.settings = settings
+ super.init(style: .Grouped)
+ self.setupSettingViewController()
+ self.setupNavigationBar()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ self.pollAPI = nil
+ self.settings = nil
+ super.init(coder: aDecoder)
+ }
+
+ // MARK: My methods
+
+ private func setupSettingViewController() {
+ self.showDoneButton = false
+ self.showCreditsFooter = false
+ self.delegate = self
+
+ let needsAuth = settings.needsAuth
+ self.hiddenKeys = needsAuth ? [] : self.hiddenSettingsKeys
+
+ NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(SettingsViewController.settingsDidChange(_:)), name: kIASKAppSettingChanged, object: nil)
+ }
+
+ @objc private func settingsDidChange(notification: NSNotification) {
+ if let object = notification.object {
+ if object.isEqual("auth.needsAuth") {
+ let enabled = settings.needsAuth
+ let hiddenKeys = enabled ? [] : self.hiddenSettingsKeys
+ self.setHiddenKeys(hiddenKeys, animated: true)
+ }
+ }
+ }
+
+ private func setupNavigationBar() {
+ self.navigationItem.title = NSLocalizedString("Settings", comment: "")
+
+ let strSave = NSLocalizedString("OK", comment: "")
+ let btSave = UIBarButtonItem(title: strSave, style: .Done, target: self, action: #selector(SettingsViewController.dismissViewController))
+ self.navigationItem.rightBarButtonItem = btSave
+ }
+
+ @objc private func dismissViewController() {
+ if !settings.validateServerIP() {
+ let title = NSLocalizedString("Error", comment: "")
+ let message = NSLocalizedString("Please, verify if the server IP is valid.", comment: "")
+ UIAlertView(title: title, message: message, delegate: nil, cancelButtonTitle: "OK")
+ .show()
+ } else if !settings.validateServerPort() {
+ let title = NSLocalizedString("Error", comment: "")
+ let message = NSLocalizedString("Please, verify if the server port is valid.", comment: "")
+ UIAlertView(title: title, message: message, delegate: nil, cancelButtonTitle: "OK")
+ .show()
+ } else {
+ self.synchronizeSettings()
+ self.dismissViewControllerAnimated(true, completion: nil)
+ }
+ }
+
+}
+
+// MARK: - IASKSettingsDelegate
+
+extension SettingsViewController: IASKSettingsDelegate {
+
+ func settingsViewControllerDidEnd(sender: IASKAppSettingsViewController!) {
+ // This is required...
+ }
+}
=== added directory 'Remote/Classes/Controller/Slides'
=== added file 'Remote/Classes/Controller/Slides/SlidesViewController.swift'
--- Remote/Classes/Controller/Slides/SlidesViewController.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Slides/SlidesViewController.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,193 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+
+// MARK: - SlidesViewController
+
+class SlidesViewController: UIViewController {
+
+ @IBOutlet weak var tableView: UITableView?
+ @IBOutlet weak var segProjectionState: UISegmentedControl?
+
+ private var slides = [SlideModel]()
+ private let service: Service!
+ private var settingsPresenter: SettingsControllerPresenter!
+ private let settings: UserSettings!
+
+ private let cellIdentifier = "cell_id"
+
+ // MARK: Init
+
+ init(settings: UserSettings, service: Service) {
+ self.service = service
+ self.settingsPresenter = SettingsControllerPresenter(settings: settings, pollAPI: service.pollAPI)
+ self.settings = settings
+ super.init(nibName: "SlidesViewController", bundle: nil)
+ self.setupTabBar()
+ self.setupNavigationBar()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ self.service = nil
+ self.settingsPresenter = nil
+ self.settings = nil
+ super.init(coder: aDecoder)
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupTableView()
+ setupSegmentedControl()
+ }
+
+ override func viewWillAppear(animated: Bool) {
+ self.tableView?.decelerationRate = settings.preciseSlidesScroll ? UIScrollViewDecelerationRateFast : UIScrollViewDecelerationRateNormal
+ self.tableView?.bounces = !settings.preciseSlidesScroll
+ }
+
+ // MARK: Setup
+
+ private func setupTabBar() {
+ self.tabBarItem.title = NSLocalizedString("Slides", comment: "")
+ self.tabBarItem.image = UIImage(named: "ic_slides")
+ }
+
+ private func setupNavigationBar() {
+ self.navigationItem.leftBarButtonItem = settingsPresenter.settingsBarButton(self)
+
+ self.navigationItem.title = NSLocalizedString("Slides", comment: "")
+
+ let imagePrevious = UIImage(named: "ic_arrow-up")
+ let btPrevious = UIBarButtonItem(image: imagePrevious, style: .Plain, target: self, action: #selector(SlidesViewController.previousSlide))
+ let imageNext = UIImage(named: "ic_arrow-down")
+ let btNext = UIBarButtonItem(image: imageNext, style: .Plain, target: self, action: #selector(SlidesViewController.nextSlide))
+ self.navigationItem.rightBarButtonItems = [
+ btNext,
+ btPrevious
+ ]
+ }
+
+ private func setupTableView() {
+ self.tableView?.rowHeight = UITableViewAutomaticDimension
+ self.tableView?.estimatedRowHeight = 44
+ self.tableView?.registerClass(SlideCell.self, forCellReuseIdentifier: cellIdentifier)
+ }
+
+ private func setupSegmentedControl() {
+ self.segProjectionState?.selectedSegmentIndex = -1
+ }
+
+ // MARK: My methods
+
+ @IBAction func segmentedControlValueChanged() {
+ let index = self.segProjectionState?.selectedSegmentIndex
+ if let state = ProjectionState(rawValue: index!) {
+ self.service.displayAPI.projectionState(state) { _, error in
+ if let error = error, message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ }
+ }
+ }
+ }
+
+ @objc private func previousSlide() {
+ self.service.controllerAPI.livePrevious() { _, error in
+ if let error = error, message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ }
+ }
+ }
+
+ @objc private func nextSlide() {
+ self.service.controllerAPI.liveNext() { _, error in
+ if let error = error, message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ }
+ }
+ }
+
+
+}
+
+// MARK:- UITableViewDatasource
+
+extension SlidesViewController: UITableViewDataSource {
+
+ func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return self.slides.count
+ }
+
+ func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ let cell: SlideCell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! SlideCell
+ let slide = self.slides[indexPath.row]
+ cell.textLabel?.text = slide.text
+ return cell
+ }
+}
+
+
+// MARK: - UITableViewDelegate
+
+extension SlidesViewController: UITableViewDelegate {
+
+ func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ let cell = tableView.cellForRowAtIndexPath(indexPath) as! SlideCell
+ cell.spinner.startAnimating()
+ service.pauseLoopPolling = true
+ self.service.controllerAPI.liveSet(row: indexPath.row) { _, error in
+ self.service.pauseLoopPolling = false
+ cell.spinner.stopAnimating()
+ print("slide selection error: \(error)")
+ if let error = error, let message = verifyError(error) {
+ self.displayNotification(message, isError: true)
+ tableView.deselectRowAtIndexPath(indexPath, animated: true)
+ }
+ }
+ }
+}
+
+
+// MARK: - PollAPISlidesDelegate
+
+extension SlidesViewController: PollAPISlidesDelegate {
+
+ func updateSlides(slides: [SlideModel]) {
+ self.slides = slides
+ self.tableView?.reloadData()
+ self.tableView?.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: true)
+ }
+
+ func updateSelectedSlide(row: Int) {
+ if self.slides.count > 0 {
+ let indexPath = NSIndexPath(forRow: row, inSection: 0)
+ self.tableView?.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .None)
+ }
+ }
+
+ func updateProjectionState(state: ProjectionState) {
+ self.segProjectionState?.selectedSegmentIndex = state.rawValue
+ }
+
+}
=== added file 'Remote/Classes/Controller/Slides/SlidesViewController.xib'
--- Remote/Classes/Controller/Slides/SlidesViewController.xib 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Controller/Slides/SlidesViewController.xib 2017-01-21 18:06:11 +0000
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+ <device id="retina4_0" orientation="portrait">
+ <adaptation id="fullscreen"/>
+ </device>
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SlidesViewController" customModule="Remote" customModuleProvider="target">
+ <connections>
+ <outlet property="segProjectionState" destination="TgF-ve-9tk" id="aVH-pn-mQ0"/>
+ <outlet property="tableView" destination="yep-A9-X97" id="4O9-6e-WsY"/>
+ <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+ </connections>
+ </placeholder>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+ <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <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">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="556"/>
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <connections>
+ <outlet property="dataSource" destination="-1" id="IUL-yU-aAA"/>
+ <outlet property="delegate" destination="-1" id="yTW-CE-U9j"/>
+ </connections>
+ </tableView>
+ <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bd2-0o-H00">
+ <rect key="frame" x="0.0" y="507" width="600" height="44"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="44" id="nTo-A6-Fmk"/>
+ </constraints>
+ <items>
+ <barButtonItem style="plain" systemItem="flexibleSpace" id="fG6-Eu-Rwq"/>
+ <barButtonItem style="plain" id="h48-u1-r58">
+ <segmentedControl key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" segmentControlStyle="bar" selectedSegmentIndex="0" id="TgF-ve-9tk">
+ <rect key="frame" x="150" y="7" width="300" height="30"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <segments>
+ <segment title="Blank"/>
+ <segment title="Theme"/>
+ <segment title="Desktop"/>
+ <segment title="Show"/>
+ </segments>
+ <connections>
+ <action selector="segmentedControlValueChanged" destination="-1" eventType="valueChanged" id="77C-OW-bAd"/>
+ </connections>
+ </segmentedControl>
+ </barButtonItem>
+ <barButtonItem style="plain" systemItem="flexibleSpace" id="9fy-o8-6Wl"/>
+ </items>
+ </toolbar>
+ </subviews>
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <constraints>
+ <constraint firstItem="bd2-0o-H00" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="9Nx-QJ-WEy"/>
+ <constraint firstAttribute="bottom" secondItem="yep-A9-X97" secondAttribute="bottom" constant="44" id="K91-G1-wno"/>
+ <constraint firstItem="yep-A9-X97" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="X3H-ky-s6L"/>
+ <constraint firstItem="yep-A9-X97" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="dOO-1W-uhe"/>
+ <constraint firstAttribute="trailing" secondItem="bd2-0o-H00" secondAttribute="trailing" id="fI8-6i-Wmd"/>
+ <constraint firstAttribute="trailing" secondItem="yep-A9-X97" secondAttribute="trailing" id="nFF-kd-XEt"/>
+ <constraint firstAttribute="bottom" secondItem="bd2-0o-H00" secondAttribute="bottom" constant="49" id="vnf-NL-Kyz"/>
+ </constraints>
+ <simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
+ <simulatedTabBarMetrics key="simulatedBottomBarMetrics"/>
+ </view>
+ </objects>
+</document>
=== added directory 'Remote/Classes/Model'
=== added file 'Remote/Classes/Model/ItemModel.swift'
--- Remote/Classes/Model/ItemModel.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Model/ItemModel.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+import ObjectMapper
+
+class ItemModel: Mappable {
+
+ var id: String?
+ var idInt: Int?
+ var plugin: String?
+ var title: String!
+ var selected: Bool?
+ var notes: String?
+
+ init() {}
+
+ required init?(_ map: Map) {}
+
+ func mapping(map: Map) {
+ self.id <- map["id"]
+ self.plugin <- map["plugin"]
+ self.title <- map["title"]
+ self.selected <- map["selected"]
+ self.notes <- map["notes"]
+ }
+
+}
=== added file 'Remote/Classes/Model/LiveModel.swift'
--- Remote/Classes/Model/LiveModel.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Model/LiveModel.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+import ObjectMapper
+
+class LiveModel: Mappable {
+
+ var item: String!
+ var slides: [SlideModel]!
+
+ required init?(_ map: Map) {}
+
+ func mapping(map: Map) {
+ self.item <- map["results.item"]
+ self.slides <- map["results.slides"]
+ }
+
+}
=== added file 'Remote/Classes/Model/PluginModel.swift'
--- Remote/Classes/Model/PluginModel.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Model/PluginModel.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,51 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+
+enum Plugin: String {
+ case Songs = "songs"
+ case Bibles = "bibles"
+ case Presentations = "presentations"
+ case Images = "images"
+ case Media = "media"
+ case Custom = "custom"
+
+ func name() -> String {
+ switch self {
+ case .Songs:
+ return NSLocalizedString("Songs", comment: "")
+ case .Bibles:
+ return NSLocalizedString("Bibles", comment: "")
+ case .Presentations:
+ return NSLocalizedString("Presentations", comment: "")
+ case .Images:
+ return NSLocalizedString("Images", comment: "")
+ case .Media:
+ return NSLocalizedString("Media", comment: "")
+ case .Custom:
+ return NSLocalizedString("Custom Slides", comment: "")
+ }
+ }
+}
=== added file 'Remote/Classes/Model/PollModel.swift'
--- Remote/Classes/Model/PollModel.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Model/PollModel.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,108 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+import ObjectMapper
+
+enum ProjectionState: Int {
+ case Blank = 0
+ case Theme = 1
+ case Desktop = 2
+ case Show = 3
+
+ func string() -> String {
+ switch self {
+ case .Blank:
+ return "blank"
+ case .Theme:
+ return "theme"
+ case .Desktop:
+ return "desktop"
+ case .Show:
+ return "show"
+ }
+ }
+}
+
+class PollModel: Mappable {
+
+ var item: String!
+ var version: Int!
+ var isSecure: Bool!
+ var isAuthorised: Bool!
+ private var blank: Bool!
+ private var display: Bool!
+ private var theme: Bool!
+ var twelve: Bool!
+ var slide: Int!
+ var service: Int!
+ var projectionState: ProjectionState {
+ if blank.boolValue || display.boolValue || theme.boolValue {
+ if (blank.boolValue) {
+ return .Blank
+ }
+ else if display.boolValue {
+ return .Desktop
+ }
+ else {
+ return .Theme
+ }
+ }
+ else {
+ return .Show
+ }
+ }
+
+ init() {
+ self.item = ""
+ self.version = 0
+ self.isSecure = false
+ self.isAuthorised = false
+ self.blank = false
+ self.display = false
+ self.theme = false
+ self.twelve = false
+ self.slide = 0
+ self.service = 0
+ }
+
+ required init?(_ map: Map) {}
+
+ func mapping(map: Map) {
+ self.item <- map["results.item"]
+ self.version <- map["results.version"]
+ self.isSecure <- map["results.isSecure"]
+ self.isAuthorised <- map["results.isAuthorised"]
+ self.blank <- map["results.blank"]
+ self.display <- map["results.display"]
+ self.theme <- map["results.theme"]
+ self.twelve <- map["results.twelve"]
+ self.slide <- map["results.slide"]
+ self.service <- map["results.service"]
+ }
+
+
+
+
+}
=== added file 'Remote/Classes/Model/ServiceListModel.swift'
--- Remote/Classes/Model/ServiceListModel.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Model/ServiceListModel.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+import ObjectMapper
+
+class ServiceListModel: Mappable {
+
+ private var intern: Dictionary<String, [ItemModel]>!
+ var results: [ItemModel] {
+ return intern["items"]!
+ }
+
+ required init?(_ map: Map) {}
+
+ func mapping(map: Map) {
+ self.intern <- map["results"]
+ }
+
+}
=== added file 'Remote/Classes/Model/SlideModel.swift'
--- Remote/Classes/Model/SlideModel.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Model/SlideModel.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+import ObjectMapper
+
+class SlideModel: Mappable {
+
+ var tag: String!
+ var html: String!
+ var text: String!
+ var selected: Bool!
+
+ required init?(_ map: Map) {}
+
+ func mapping(map: Map) {
+ self.tag <- map["tag"]
+ self.html <- map["html"]
+ self.text <- map["text"]
+ self.selected <- map["selected"]
+ }
+
+}
=== added file 'Remote/Classes/Model/SuccessModel.swift'
--- Remote/Classes/Model/SuccessModel.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Model/SuccessModel.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+import ObjectMapper
+
+class SuccessModel: Mappable {
+
+ var success: Bool!
+
+ required init?(_ map: Map) {}
+
+ func mapping(map: Map) {
+ self.success <- map["results.success"]
+ }
+
+}
=== added file 'Remote/Classes/Model/UserSettings.swift'
--- Remote/Classes/Model/UserSettings.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Model/UserSettings.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+
+struct UserSettings {
+
+ private let userDefaults: NSUserDefaults
+
+ init(defaults: NSUserDefaults) {
+ userDefaults = defaults
+ }
+
+ var serverIP: String {
+ return userDefaults.valueForKey("server.ip") as! String
+ }
+
+ var serverPort: String {
+ return userDefaults.valueForKey("server.port") as! String
+ }
+
+ var useHTTPS: Bool {
+ return userDefaults.boolForKey("server.useHTTPS")
+ }
+
+ var needsAuth: Bool {
+ return userDefaults.boolForKey("auth.needsAuth")
+ }
+
+ var userID: String {
+ return userDefaults.valueForKey("auth.userID") as! String
+ }
+
+ var password: String {
+ return userDefaults.valueForKey("auth.password") as! String
+ }
+
+ var preciseSlidesScroll: Bool {
+ return userDefaults.boolForKey("ui.preciseScroll")
+ }
+
+ func registerDefaults() {
+ userDefaults.registerDefaults([
+ "server.ip": "",
+ "server.port": "4316",
+ "server.useHTTPS": false,
+ "auth.needsAuth": false,
+ "auth.userID": "",
+ "auth.password": "",
+ "ui.preciseScroll": false
+ ])
+ }
+
+ func resetDefaultsIfNeeded() {
+ guard let _ = NSURL(string: serverIP + ":" + serverPort) else {
+ userDefaults.removeObjectForKey("server.ip")
+ userDefaults.removeObjectForKey("server.port")
+ return
+ }
+ }
+
+ func validateServerIP() -> Bool {
+ guard let _ = NSURL(string: serverIP) else {
+ return false
+ }
+ return true
+ }
+
+ func validateServerPort() -> Bool {
+ guard let _ = Int(serverPort) else {
+ return false
+ }
+ return true
+ }
+
+ func validateURL() -> Bool {
+ return validateServerIP() && validateServerPort()
+ }
+
+}
=== added directory 'Remote/Classes/Network'
=== added file 'Remote/Classes/Network/API.swift'
--- Remote/Classes/Network/API.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/API.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,54 @@
+//
+// OLPAPI.swift
+/******************************************************************************
+* OpenLP iOS Remote *
+* --------------------------------------------------------------------------- *
+* Copyright (c) 2008-2016 OpenLP Developers *
+* --------------------------------------------------------------------------- *
+* Permission is hereby granted, free of charge, to any person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction, including without limitation *
+* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+* and/or sell copies of the Software, and to permit persons to whom the *
+* Software is furnished to do so, subject to the following conditions: *
+* *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software. *
+* *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+* DEALINGS IN THE SOFTWARE. *
+******************************************************************************/
+
+import Foundation
+
+class API {
+ let settings: UserSettings
+
+ init(settings: UserSettings) {
+ self.settings = settings
+ }
+
+ var base: String {
+ let serverIP = settings.serverIP
+ let serverPort = settings.serverPort
+ let useHTTPS = settings.useHTTPS
+
+ var scheme = "http"
+ if useHTTPS {
+ scheme += "s"
+ }
+
+ let components: NSURLComponents = NSURLComponents()
+ components.scheme = scheme
+ components.host = serverIP
+ components.port = Int(serverPort)
+ components.path = "/api"
+
+ return components.string!//strUrl
+ }
+}
\ No newline at end of file
=== added file 'Remote/Classes/Network/AddAPI.swift'
--- Remote/Classes/Network/AddAPI.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/AddAPI.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import Alamofire
+
+class AddAPI: API {
+
+ func addItem(item: ItemModel, plugin: Plugin, completion: (NSError?) -> Void) {
+ let url = self.base + "/" + plugin.rawValue + "/add"
+ var params: [String: AnyObject] = [
+ "request": [
+ "id": (item.id == nil ? String(item.idInt!) : item.id!)
+ ]
+ ]
+ if let jsonString = jsonString(fromDictionary: params) {
+ params = ["data": jsonString]
+ let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.response { _, _, _, error in
+ completion(error)
+ }
+ }
+ }
+
+}
=== added file 'Remote/Classes/Network/AlertAPI.swift'
--- Remote/Classes/Network/AlertAPI.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/AlertAPI.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,59 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import Alamofire
+import AlamofireObjectMapper
+
+class AlertAPI: API {
+
+ func alert(text: String, completion: ((Bool, NSError?) -> Void)? = nil) {
+ let url = self.base + "/alert"
+ var params: [String: AnyObject] = [
+ "request": [
+ "text": text
+ ]
+ ]
+
+ if let jsonString = jsonString(fromDictionary: params) {
+ params = ["data": jsonString]
+ let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseObject { (response: Response<SuccessModel, NSError>) in
+ let error = response.result.error
+ var success = response.result.value?.success
+ if success == nil {
+ success = false
+ }
+
+ if let completion = completion {
+ completion(success!, error)
+ }
+ }
+ }
+ }
+
+}
=== added file 'Remote/Classes/Network/ControllerAPI.swift'
--- Remote/Classes/Network/ControllerAPI.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/ControllerAPI.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import Alamofire
+import AlamofireObjectMapper
+
+class ControllerAPI: API {
+
+ func liveText(completion: ([SlideModel]?, NSError?) -> Void) {
+ let url = self.base + "/controller/live/text"
+ let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseObject { (response: Response<LiveModel, NSError>) -> Void in
+ let error = response.result.error
+ let slides = response.result.value?.slides
+ completion(slides, error)
+ }
+ }
+
+ private func action(action: String, completion: ((Bool, NSError?) -> Void)?) {
+ let url = self.base + "/controller/live/" + action
+ let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseObject { (response: Response<SuccessModel, NSError>) -> Void in
+ let error = response.result.error
+ var success = response.result.value?.success
+ if success == nil {
+ success = false
+ }
+
+ if let completion = completion {
+ completion(success!, error)
+ }
+ }
+ }
+
+ func livePrevious(completion: ((Bool, NSError?) -> Void)? = nil) {
+ self.action("previous", completion: completion)
+ }
+
+ func liveNext(completion: ((Bool, NSError?) -> Void)? = nil) {
+ self.action("next", completion: completion)
+ }
+
+ func liveSet(row row: Int, completion: ((Bool, NSError?) -> Void)? = nil) {
+ let url = self.base + "/controller/live/set"
+ var params: [String: AnyObject] = [
+ "request": [
+ "id": "+\(row)"
+ ]
+ ]
+
+ if let jsonString = jsonString(fromDictionary: params) {
+ params = ["data": jsonString]
+ let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseObject { (response: Response<SuccessModel, NSError>) in
+ let error = response.result.error
+ var success = response.result.value?.success
+ if success == nil {
+ success = false
+ }
+
+ if let completion = completion {
+ completion(success!, error)
+ }
+ }
+ } else if let completion = completion {
+ completion(false, nil)
+ }
+ }
+
+}
=== added file 'Remote/Classes/Network/DisplayAPI.swift'
--- Remote/Classes/Network/DisplayAPI.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/DisplayAPI.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import Alamofire
+import AlamofireObjectMapper
+
+class DisplayAPI: API {
+
+ func projectionState(state: ProjectionState, completion: ((Bool, NSError?) -> Void)? = nil) {
+ let url = self.base + "/display/" + state.string()
+ let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseObject { (response: Response<SuccessModel, NSError>) in
+ let error = response.result.error
+ var success = response.result.value?.success
+ if success == nil {
+ success = false
+ }
+
+ if let completion = completion {
+ completion(success!, error)
+ }
+ }
+ }
+
+}
=== added file 'Remote/Classes/Network/LiveAPI.swift'
--- Remote/Classes/Network/LiveAPI.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/LiveAPI.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import Alamofire
+
+class LiveAPI: API {
+
+ func goItemToLive(item: ItemModel, plugin: Plugin, completion: (NSError?) -> Void) {
+ let url = self.base + "/" + plugin.rawValue + "/live"
+ var params: [String: AnyObject] = [
+ "request": [
+ "id": (item.id == nil ? String(item.idInt!) : item.id!)
+ ]
+ ]
+ if let jsonString = jsonString(fromDictionary: params) {
+ params = ["data": jsonString]
+ let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.response { _, _, _, error in
+ completion(error)
+ }
+ }
+ }
+
+}
=== added file 'Remote/Classes/Network/PollAPI.swift'
--- Remote/Classes/Network/PollAPI.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/PollAPI.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,132 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+import Alamofire
+import AlamofireObjectMapper
+
+protocol PollAPIServiceDelegate {
+ func updateServiceList(items: [ItemModel])
+ func updateSelectedItem(itemId id: String)
+ func updateProjectionState(state: ProjectionState)
+}
+
+protocol PollAPISlidesDelegate {
+ func updateSlides(slides: [SlideModel])
+ func updateSelectedSlide(row: Int)
+ func updateProjectionState(state: ProjectionState)
+}
+
+class PollAPI: API {
+
+ private var poll: PollModel = PollModel()
+ var serviceDelegate: PollAPIServiceDelegate?
+ var slidesDelegate: PollAPISlidesDelegate?
+ private let controllerAPI: ControllerAPI
+ private let serviceAPI: ServiceAPI
+
+ init(settings: UserSettings, controllerAPI: ControllerAPI, serviceAPI: ServiceAPI) {
+ self.controllerAPI = controllerAPI
+ self.serviceAPI = serviceAPI
+ super.init(settings: settings)
+ }
+
+ func poll(completion: ((PollModel?, NSError?) -> Void)? = nil) {
+ let url = self.base + "/poll"
+ let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseObject { (response: Response<PollModel, NSError>) in
+ let error = response.result.error
+ let poll = response.result.value
+
+ if let completion = completion {
+ completion(poll, error)
+ }
+
+ self.handlePollResponse(poll)
+ }
+ }
+
+
+ private func updateService(completion: ((Void) -> Void)? = nil) {
+ self.serviceAPI.list { items, error in
+ if let items = items {
+ self.serviceDelegate?.updateServiceList(items)
+ }
+
+ if let completion = completion {
+ completion()
+ }
+ }
+ }
+
+
+ private func updateSlides(completion: ((Void) -> Void)? = nil) {
+ self.controllerAPI.liveText { slides, error in
+ if let slides = slides {
+ self.slidesDelegate?.updateSlides(slides)
+ }
+
+ if let completion = completion {
+ completion()
+ }
+ }
+ }
+
+
+ private func updateProjectionState(projectionState: ProjectionState) {
+ self.serviceDelegate?.updateProjectionState(projectionState)
+ self.slidesDelegate?.updateProjectionState(projectionState)
+ }
+
+
+ private func handlePollResponse(poll: PollModel?) {
+ if let poll = poll {
+ if self.poll.service != poll.service {
+ self.updateService({
+ self.serviceDelegate?.updateSelectedItem(itemId: poll.item)
+ })
+ }
+ else {
+ self.serviceDelegate?.updateSelectedItem(itemId: poll.item)
+ }
+
+ if self.poll.item != poll.item {
+ self.updateSlides({
+ self.slidesDelegate?.updateSelectedSlide(poll.slide)
+ })
+ }
+ else {
+ self.slidesDelegate?.updateSelectedSlide(poll.slide)
+ }
+
+ updateProjectionState(poll.projectionState)
+
+ self.poll = poll
+ }
+ }
+
+}
=== added file 'Remote/Classes/Network/SearchAPI.swift'
--- Remote/Classes/Network/SearchAPI.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/SearchAPI.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,68 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import Alamofire
+
+class SearchAPI: API {
+
+ func search(plugin plugin: Plugin, text: String, completion: ([ItemModel]?, NSError?) -> Void) {
+ let url = self.base + "/" + plugin.rawValue + "/search"
+ var params: [String: AnyObject] = [
+ "request": [
+ "text": text
+ ]
+ ]
+ if let jsonString = jsonString(fromDictionary: params) {
+ params = ["data": jsonString]
+ let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseJSON { (response: Response<AnyObject, NSError>) in
+ var result = [ItemModel]()
+ if let value = response.result.value as? NSDictionary,
+ results = value["results"] as? NSDictionary,
+ items = results["items"] as? NSArray {
+ for item in items {
+ let item = item as! NSArray
+ let i = ItemModel()
+ if let id = item[0] as? String {
+ i.id = id
+ }
+ if let idInt = item[0] as? Int {
+ i.idInt = idInt
+ }
+ i.title = item[1] as! String
+ i.plugin = plugin.rawValue
+ result.append(i)
+ }
+ }
+ let error = response.result.error
+ completion(result, error)
+ }
+ }
+ }
+
+}
=== added file 'Remote/Classes/Network/Service.swift'
--- Remote/Classes/Network/Service.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/Service.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+
+class Service {
+ let serviceAPI: ServiceAPI
+ let pollAPI: PollAPI
+ let displayAPI: DisplayAPI
+ let controllerAPI: ControllerAPI
+ let alertAPI: AlertAPI
+ let searchAPI: SearchAPI
+ let liveAPI: LiveAPI
+ let addAPI: AddAPI
+ var pauseLoopPolling = false
+
+ init(settings: UserSettings) {
+ serviceAPI = ServiceAPI(settings: settings)
+ controllerAPI = ControllerAPI(settings :settings)
+ pollAPI = PollAPI(settings: settings, controllerAPI:controllerAPI, serviceAPI: serviceAPI)
+ displayAPI = DisplayAPI(settings: settings)
+ alertAPI = AlertAPI(settings :settings)
+ searchAPI = SearchAPI(settings :settings)
+ liveAPI = LiveAPI(settings: settings)
+ addAPI = AddAPI(settings: settings)
+ }
+}
=== added file 'Remote/Classes/Network/ServiceAPI.swift'
--- Remote/Classes/Network/ServiceAPI.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Network/ServiceAPI.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import Alamofire
+import AlamofireObjectMapper
+
+class ServiceAPI: API {
+
+ func list(completion: ([ItemModel]?, NSError?) -> Void) {
+ let url = self.base + "/service/list"
+ let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseObject { (response: Response<ServiceListModel, NSError>) in
+ let error = response.result.error
+ let items = response.result.value?.results
+ completion(items, error)
+ }
+ }
+
+ func set(row row: Int, completion: ((Bool, NSError?) -> Void)? = nil) {
+ let url = self.base + "/service/set"
+ var params: [String: AnyObject] = [
+ "request": [
+ "id": "+\(row)"
+ ]
+ ]
+
+ if let jsonString = jsonString(fromDictionary: params) {
+ params = ["data": jsonString]
+ let request = Alamofire.request(.GET, url, parameters: params).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseObject { (response: Response<SuccessModel, NSError>) in
+ let error = response.result.error
+ var success = response.result.value?.success
+ if success == nil {
+ success = false
+ }
+
+ if let completion = completion {
+ completion(success!, error)
+ }
+ }
+ } else if let completion = completion {
+ completion(false, nil)
+ }
+ }
+
+ private func nextPrevious(action: String, completion: ((Bool, NSError?) -> Void)? = nil) {
+ let url = self.base + "/service/" + action
+ let request = Alamofire.request(.GET, url).validate(statusCode: 200...200)
+ if settings.needsAuth {
+ request.authenticate(user: settings.userID, password: settings.password, persistence: .None)
+ }
+ request.responseObject { (response: Response<SuccessModel, NSError>) in
+ let error = response.result.error
+ var success = response.result.value?.success
+ if success == nil {
+ success = false
+ }
+
+ if let completion = completion {
+ completion(success!, error)
+ }
+ }
+ }
+
+ func previous(completion: ((Bool, NSError?) -> Void)? = nil) {
+ self.nextPrevious("previous", completion: completion)
+ }
+
+ func next(completion: ((Bool, NSError?) -> Void)? = nil) {
+ self.nextPrevious("next", completion: completion)
+ }
+
+}
=== added directory 'Remote/Classes/Util'
=== added file 'Remote/Classes/Util/ColorUtil.swift'
--- Remote/Classes/Util/ColorUtil.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Util/ColorUtil.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+
+let kGreyColor = UIColor(red: 207/255, green: 207/255, blue: 207/255, alpha: 1)
+let kBlueColor = UIColor(red: 0, green: 122/255, blue: 255/255, alpha: 1)
+let kRedColor = UIColor.redColor()
=== added file 'Remote/Classes/Util/DictionaryUtil.swift'
--- Remote/Classes/Util/DictionaryUtil.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Util/DictionaryUtil.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,35 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import Foundation
+
+func jsonString(fromDictionary dictionary: [String: AnyObject]) -> String? {
+ do {
+ let jsonData = try NSJSONSerialization.dataWithJSONObject(dictionary, options: NSJSONWritingOptions(rawValue: 0))
+ let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding)!
+ return jsonString
+ } catch {
+ return nil
+ }
+}
=== added file 'Remote/Classes/Util/ErrorUtil.swift'
--- Remote/Classes/Util/ErrorUtil.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Util/ErrorUtil.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+
+func verifyError(error: NSError) -> String? {
+ if error.code == -6003 {
+ return NSLocalizedString("User not authenticated.", comment: "")
+ } else if error.code == -999 {
+ return NSLocalizedString("Verify your credentials of authentication.", comment: "")
+ } else if error.code == -6004 {
+ return nil
+ }
+ return NSLocalizedString("An error occurred. Try again...", comment: "")
+}
=== added file 'Remote/Classes/Util/TabSwitchingToRightAnimationController.swift'
--- Remote/Classes/Util/TabSwitchingToRightAnimationController.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Util/TabSwitchingToRightAnimationController.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,66 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+
+class TabSwitchingToRightAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
+ let tabBarController: UITabBarController
+
+ init(tabBarController: UITabBarController) {
+ self.tabBarController = tabBarController
+ }
+
+ func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
+ return 0.5
+ }
+
+ func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
+ if let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey),
+ let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) {
+ let fromView = fromVC.view
+ let toView: UIView = toVC.view
+
+ let containerView = transitionContext.containerView()
+ containerView.addSubview(toView)
+
+ var fromViewEndFrame = fromView.frame
+ fromViewEndFrame.origin.x -= containerView.frame.width
+
+ let toViewEndFrame = transitionContext.finalFrameForViewController(toVC)
+ let toViewStartFrame = CGRectMake(toViewEndFrame.origin.x + toViewEndFrame.size.width, toViewEndFrame.origin.y, toViewEndFrame.size.width, toViewEndFrame.size.height)
+
+ toView.frame = toViewStartFrame
+
+ containerView.backgroundColor = UIColor.whiteColor()
+
+ UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
+ toView.frame = toViewEndFrame
+ fromView.frame = fromViewEndFrame
+
+ }, completion: { (completed) -> Void in
+ transitionContext.completeTransition(completed)
+ })
+ }
+ }
+}
=== added file 'Remote/Classes/Util/ViewControllerUtil.swift'
--- Remote/Classes/Util/ViewControllerUtil.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/Util/ViewControllerUtil.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,81 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+import CWStatusBarNotification
+
+
+extension UIViewController {
+ func wrapedInNavigationController(controller: UIViewController) -> UINavigationController {
+ let navigationController = UINavigationController(rootViewController: controller)
+ return navigationController
+ }
+
+
+ func displayNotification(message: String, isError: Bool = false) {
+ let notifications = CWStatusBarNotification()
+ notifications.notificationLabelTextColor = UIColor.whiteColor()
+ notifications.notificationLabelBackgroundColor = isError ? kRedColor : kBlueColor
+ notifications.notificationAnimationInStyle = .Top
+ notifications.notificationAnimationOutStyle = .Top
+ notifications.displayNotificationWithMessage(message, forDuration: 3)
+ }
+
+
+ func animateRightBetweenTabViews(fromViewController: UIViewController, toViewController: UIViewController, completion:()->Void) {
+
+ let toView = toViewController.view
+ let fromView = fromViewController.view
+
+
+
+ // Add the toView to the tab bar view
+ fromView.superview!.addSubview(toView)
+
+
+ // Position toView off screen (to the left/right of fromView)
+ let screenWidth = UIScreen.mainScreen().bounds.size.width;
+
+ let offset = screenWidth;
+ toView.center = CGPoint(x: fromView.center.x + offset, y: toView.center.y)
+
+ // Disable interaction during animation
+ view.userInteractionEnabled = false
+
+ UIView.animateWithDuration(0.5, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
+
+ // Slide the views by -offset
+ fromView.center = CGPoint(x: fromView.center.x - offset, y: fromView.center.y);
+ toView.center = CGPoint(x: toView.center.x - offset, y: toView.center.y);
+
+ }, completion: { finished in
+
+ // Remove the old view from the tabbar view.
+ fromView.removeFromSuperview()
+ self.view.userInteractionEnabled = true
+ completion()
+ })
+ }
+
+}
=== added directory 'Remote/Classes/View'
=== added directory 'Remote/Classes/View/Settings'
=== added directory 'Remote/Classes/View/Settings/Cells'
=== added directory 'Remote/Classes/View/Settings/Cells/Button'
=== added directory 'Remote/Classes/View/Settings/Cells/Switch'
=== added directory 'Remote/Classes/View/Settings/Cells/Text field'
=== added file 'Remote/Classes/View/SlideCell.swift'
--- Remote/Classes/View/SlideCell.swift 1970-01-01 00:00:00 +0000
+++ Remote/Classes/View/SlideCell.swift 2017-01-21 18:06:11 +0000
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * OpenLP iOS Remote *
+ * --------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2016 OpenLP Developers *
+ * --------------------------------------------------------------------------- *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the "Software"), *
+ * to deal in the Software without restriction, including without limitation *
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
+ * and/or sell copies of the Software, and to permit persons to whom the *
+ * Software is furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in *
+ * all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
+ * DEALINGS IN THE SOFTWARE. *
+ ******************************************************************************/
+
+import UIKit
+
+class SlideCell: UITableViewCell {
+
+ let spinner: UIActivityIndicatorView
+
+ override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
+ spinner = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
+ spinner.hidesWhenStopped = true
+ super.init(style: style, reuseIdentifier: reuseIdentifier)
+ accessoryView = spinner
+ textLabel?.numberOfLines = 0
+ textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+}
=== added directory 'Remote/Resources'
=== added directory 'Remote/Resources/Assets.xcassets'
=== added directory 'Remote/Resources/Assets.xcassets/AppIcon.appiconset'
=== added file 'Remote/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json'
--- Remote/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json 1970-01-01 00:00:00 +0000
+++ Remote/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json 2017-01-21 18:06:11 +0000
@@ -0,0 +1,44 @@
+{
+ "images" : [
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-Small@xxxxxx",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-Small@xxxxxx",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-Small-40@xxxxxx",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-Small-40@xxxxxx",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@xxxxxx",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@xxxxxx",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
=== added file 'Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@xxxxxx'
Binary files Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@xxxxxx 1970-01-01 00:00:00 +0000 and Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@xxxxxx 2017-01-21 18:06:11 +0000 differ
=== added file 'Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@xxxxxx'
Binary files Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@xxxxxx 1970-01-01 00:00:00 +0000 and Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@xxxxxx 2017-01-21 18:06:11 +0000 differ
=== added file 'Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@xxxxxx'
Binary files Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@xxxxxx 1970-01-01 00:00:00 +0000 and Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@xxxxxx 2017-01-21 18:06:11 +0000 differ
=== added file 'Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@xxxxxx'
Binary files Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@xxxxxx 1970-01-01 00:00:00 +0000 and Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@xxxxxx 2017-01-21 18:06:11 +0000 differ
=== added file 'Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@xxxxxx'
Binary files Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@xxxxxx 1970-01-01 00:00:00 +0000 and Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@xxxxxx 2017-01-21 18:06:11 +0000 differ
=== added file 'Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@xxxxxx'
Binary files Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@xxxxxx 1970-01-01 00:00:00 +0000 and Remote/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@xxxxxx 2017-01-21 18:06:11 +0000 differ
=== added file 'Remote/Resources/Assets.xcassets/Contents.json'
--- Remote/Resources/Assets.xcassets/Contents.json 1970-01-01 00:00:00 +0000
+++ Remote/Resources/Assets.xcassets/Contents.json 2017-01-21 18:06:11 +0000
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
=== added directory 'Remote/Resources/Assets.xcassets/Icons'
=== added file 'Remote/Resources/Assets.xcassets/Icons/Contents.json'
--- Remote/Resources/Assets.xcassets/Icons/Contents.json 1970-01-01 00:00:00 +0000
+++ Remote/Resources/Assets.xcassets/Icons/Contents.json 2017-01-21 18:06:11 +0000
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
=== added directory 'Remote/Resources/Assets.xcassets/Icons/ic_alerts.imageset'
=== added file 'Remote/Resources/Assets.xcassets/Icons/ic_alerts.imageset/Contents.json'
--- Remote/Resources/Assets.xcassets/Icons/ic_alerts.imageset/Contents.json 1970-01-01 00:00:00 +0000
+++ Remote/Resources/Assets.xcassets/Icons/ic_alerts.imageset/Contents.json 2017-01-21 18:06:11 +0000
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "ic_alerts.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
=== added file 'Remote/Resources/Assets.xcassets/Icons/ic_alerts.imageset/ic_alerts.pdf'
Binary files Remote/Resources/Assets.xcassets/Icons/ic_alerts.imageset/ic_alerts.pdf 1970-01-01 00:00:00 +0000 and Remote/Resources/Assets.xcassets/Icons/ic_alerts.imageset/ic_alerts.pdf 2017-01-21 18:06:11 +0000 differ
=== added directory 'Remote/Resources/Assets.xcassets/Icons/ic_arrow-down.imageset'
=== added file 'Remote/Resources/Assets.xcassets/Icons/ic_arrow-down.imageset/Contents.json'
--- Remote/Resources/Assets.xcassets/Icons/ic_arrow-down.imageset/Contents.json 1970-01-01 00:00:00 +0000
+++ Remote/Resources/Assets.xcassets/Icons/ic_arrow-down.imageset/Contents.json 2017-01-21 18:06:11 +0000
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "ic_arrow-down.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
=== added file 'Remote/Resources/Assets.xcassets/Icons/ic_arrow-down.imageset/ic_arrow-down.pdf'
--- Remote/Resources/Assets.xcassets/Icons/ic_arrow-down.imageset/ic_arrow-down.pdf 1970-01-01 00:00:00 +0000
+++ Remote/Resources/Assets.xcassets/Icons/ic_arrow-down.imageset/ic_arrow-down.pdf 2017-01-21 18:06:11 +0000
@@ -0,0 +1,112 @@
+%PDF-1.3
+%����+4 0 obj
+<< /Length 5 0 R /Filter /FlateDecode >>
+stream
+xu��� �w������qw��/�1����� ���B����g�v��1KlI�A���#�!�PS()� ˬL&�����P��%���endstream
+endobj
+5 0 obj
+111
+endobj
+2 0 obj
+<< /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 27 15]
+>>
+endobj
+6 0 obj
+<< /ProcSet [ /PDF ] /XObject << /Fm1 7 0 R >> >>
+endobj
+7 0 obj
+<< /Length 8 0 R /Filter /FlateDecode /Type /XObject /Subtype /Form /FormType
+1 /BBox [0 0 27 15] /Resources 9 0 R /Group << /S /Transparency /CS 10 0 R
+/I true /K false >> >>
+stream
+xe��+�D�9]��{��B+�?������,�4$�(��\1C,h"J�ƴM�IA���XqF���F�'9����c܄��+�W�;ΗU0�o��h\��<#����g)���q�:�F9�
+endstream
+endobj
+8 0 obj
+162
+endobj
+9 0 obj
+<< /ProcSet [ /PDF ] /ColorSpace << /Cs2 11 0 R >> >>
+endobj
+12 0 obj
+<< /Length 13 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >>
+stream
+x��wTS��Ͻ7��" %� �HQ�I�P��&vDF)VdT�G�"cE��b���DE�k ��������