From cd860fcc08cc9ebef2eaff8584205745236301e4 Mon Sep 17 00:00:00 2001 From: Raimund Wege Date: Wed, 6 Jul 2016 22:15:11 +0200 Subject: [PATCH] More needed refactoring steps --- .../SAPTracker.xcodeproj/project.pbxproj | 66 +++-- .../src/xcode/SAPTracker/BaseData.swift | 33 +++ .../CachedFixesTrackingTableViewCell.swift | 5 +- .../xcode/SAPTracker/CheckInController.swift | 237 +++--------------- .../src/xcode/SAPTracker/Competitor.swift | 11 +- .../src/xcode/SAPTracker/CompetitorData.swift | 29 +++ .../SAPTracker/CourseViewController.swift | 15 +- .../src/xcode/SAPTracker/Event.swift | 9 +- .../src/xcode/SAPTracker/EventData.swift | 26 ++ .../GPSAccuracyTrackingTableViewCell.swift | 13 +- .../xcode/SAPTracker/GPSAccuracyView.swift | 13 +- .../src/xcode/SAPTracker/GPSFix.swift | 10 +- .../xcode/SAPTracker/HomeViewController.swift | 24 +- .../src/xcode/SAPTracker/Leaderboard.swift | 4 + .../xcode/SAPTracker/LeaderboardData.swift | 19 ++ .../src/xcode/SAPTracker/LocationData.swift | 34 +++ .../xcode/SAPTracker/LocationManager.swift | 67 ++--- .../ModeTrackingTableViewCell.swift | 55 ++-- .../src/xcode/SAPTracker/Regatta.swift | 6 + .../xcode/SAPTracker/RegattaController.swift | 202 +++++++++++++++ .../{CheckInData.swift => RegattaData.swift} | 60 +++-- .../SAPTracker/RegattaViewController.swift | 96 +++---- .../src/xcode/SAPTracker/RequestManager.swift | 135 ++++++++-- .../xcode/SAPTracker/ScanViewController.swift | 52 ++-- .../SAPTracker/SendGPSFixesController.swift | 129 ---------- .../SAPTracker/SpeedViewController.swift | 19 +- .../StatusTrackingTableViewCell.swift | 10 +- .../SAPTracker/TimerViewController.swift | 3 +- .../SAPTracker/TrackingViewController.swift | 3 +- 29 files changed, 819 insertions(+), 566 deletions(-) create mode 100644 ios/SAPTracker/src/xcode/SAPTracker/BaseData.swift create mode 100644 ios/SAPTracker/src/xcode/SAPTracker/CompetitorData.swift create mode 100644 ios/SAPTracker/src/xcode/SAPTracker/EventData.swift create mode 100644 ios/SAPTracker/src/xcode/SAPTracker/LeaderboardData.swift create mode 100644 ios/SAPTracker/src/xcode/SAPTracker/LocationData.swift create mode 100644 ios/SAPTracker/src/xcode/SAPTracker/RegattaController.swift rename ios/SAPTracker/src/xcode/SAPTracker/{CheckInData.swift => RegattaData.swift} (51%) delete mode 100644 ios/SAPTracker/src/xcode/SAPTracker/SendGPSFixesController.swift diff --git a/ios/SAPTracker/src/xcode/SAPTracker.xcodeproj/project.pbxproj b/ios/SAPTracker/src/xcode/SAPTracker.xcodeproj/project.pbxproj index 72f3cfb3674..c411ae0392d 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker.xcodeproj/project.pbxproj +++ b/ios/SAPTracker/src/xcode/SAPTracker.xcodeproj/project.pbxproj @@ -9,7 +9,7 @@ /* Begin PBXBuildFile section */ 066B0DF652B5D2B188D4884B /* libPods-SAPTracker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B1229BB88872CD20C0AE25DE /* libPods-SAPTracker.a */; }; 7F0658FD19F7D6700077FF95 /* ScanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0658FC19F7D6700077FF95 /* ScanViewController.swift */; }; - 7F0658FF19F7EE910077FF95 /* CheckInData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0658FE19F7EE910077FF95 /* CheckInData.swift */; }; + 7F0658FF19F7EE910077FF95 /* RegattaData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0658FE19F7EE910077FF95 /* RegattaData.swift */; }; 7F14A10A1A13B9A6001C1ECB /* _abkhazia.png in Resources */ = {isa = PBXBuildFile; fileRef = 7F14A0041A13B9A6001C1ECB /* _abkhazia.png */; }; 7F14A10B1A13B9A6001C1ECB /* _basque-country.png in Resources */ = {isa = PBXBuildFile; fileRef = 7F14A0051A13B9A6001C1ECB /* _basque-country.png */; }; 7F14A10C1A13B9A6001C1ECB /* _british-antarctic-territory.png in Resources */ = {isa = PBXBuildFile; fileRef = 7F14A0061A13B9A6001C1ECB /* _british-antarctic-territory.png */; }; @@ -311,7 +311,6 @@ C852BAA21CF5E1EA0093B0C5 /* RequestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C852BAA11CF5E1EA0093B0C5 /* RequestManager.swift */; }; C852BAAB1CF736680093B0C5 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C852BAAA1CF736680093B0C5 /* Preferences.swift */; }; C8603D511C52892A002B2F28 /* Acknowledgements.markdown in Resources */ = {isa = PBXBuildFile; fileRef = C8603D491C528832002B2F28 /* Acknowledgements.markdown */; }; - C8739D8E1D23D53C00A89F3C /* SendGPSFixesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739D8D1D23D53C00A89F3C /* SendGPSFixesController.swift */; }; C8739E041D2AA2A500A89F3C /* Regatta+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DFA1D2AA2A500A89F3C /* Regatta+CoreDataProperties.swift */; }; C8739E051D2AA2A500A89F3C /* Regatta.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DFB1D2AA2A500A89F3C /* Regatta.swift */; }; C8739E061D2AA2A500A89F3C /* GPSFix+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DFC1D2AA2A500A89F3C /* GPSFix+CoreDataProperties.swift */; }; @@ -322,6 +321,12 @@ C8739E0B1D2AA2A500A89F3C /* Competitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E011D2AA2A500A89F3C /* Competitor.swift */; }; C8739E0C1D2AA2A500A89F3C /* Event+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E021D2AA2A500A89F3C /* Event+CoreDataProperties.swift */; }; C8739E0D1D2AA2A500A89F3C /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E031D2AA2A500A89F3C /* Event.swift */; }; + C8739E0F1D2BEE7900A89F3C /* RegattaController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E0E1D2BEE7900A89F3C /* RegattaController.swift */; }; + C8739E121D2BF14F00A89F3C /* EventData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E111D2BF14F00A89F3C /* EventData.swift */; }; + C8739E141D2BF16300A89F3C /* LeaderboardData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E131D2BF16300A89F3C /* LeaderboardData.swift */; }; + C8739E161D2BF17900A89F3C /* CompetitorData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E151D2BF17900A89F3C /* CompetitorData.swift */; }; + C8739E181D2BF2DC00A89F3C /* BaseData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E171D2BF2DC00A89F3C /* BaseData.swift */; }; + C8739E1C1D2D5F1700A89F3C /* LocationData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E1B1D2D5F1700A89F3C /* LocationData.swift */; }; C89C5FC51D06A289002AAAD2 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89C5FC41D06A289002AAAD2 /* GradientView.swift */; }; C89C5FCA1D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89C5FC91D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift */; }; C89C5FCC1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89C5FCB1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift */; }; @@ -391,7 +396,7 @@ 6010190FF03AFE91478240B4 /* Pods-SAPTrackerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SAPTrackerTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SAPTrackerTests/Pods-SAPTrackerTests.debug.xcconfig"; sourceTree = ""; }; 7F03FD3F19FA4D7400FA1327 /* bridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bridge.h; sourceTree = ""; }; 7F0658FC19F7D6700077FF95 /* ScanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ScanViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 7F0658FE19F7EE910077FF95 /* CheckInData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CheckInData.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 7F0658FE19F7EE910077FF95 /* RegattaData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = RegattaData.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 7F14A0041A13B9A6001C1ECB /* _abkhazia.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = _abkhazia.png; sourceTree = ""; }; 7F14A0051A13B9A6001C1ECB /* _basque-country.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "_basque-country.png"; sourceTree = ""; }; 7F14A0061A13B9A6001C1ECB /* _british-antarctic-territory.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "_british-antarctic-territory.png"; sourceTree = ""; }; @@ -700,7 +705,6 @@ C852BAAA1CF736680093B0C5 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; C8603D491C528832002B2F28 /* Acknowledgements.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Acknowledgements.markdown; sourceTree = ""; }; C8739D891D21276B00A89F3C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Main.strings; sourceTree = ""; }; - C8739D8D1D23D53C00A89F3C /* SendGPSFixesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendGPSFixesController.swift; sourceTree = ""; }; C8739D9A1D25317100A89F3C /* CoreData 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "CoreData 2.xcdatamodel"; sourceTree = ""; }; C8739DFA1D2AA2A500A89F3C /* Regatta+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Regatta+CoreDataProperties.swift"; sourceTree = ""; }; C8739DFB1D2AA2A500A89F3C /* Regatta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Regatta.swift; sourceTree = ""; }; @@ -712,6 +716,12 @@ C8739E011D2AA2A500A89F3C /* Competitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Competitor.swift; sourceTree = ""; }; C8739E021D2AA2A500A89F3C /* Event+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Event+CoreDataProperties.swift"; sourceTree = ""; }; C8739E031D2AA2A500A89F3C /* Event.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = ""; }; + C8739E0E1D2BEE7900A89F3C /* RegattaController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegattaController.swift; sourceTree = ""; }; + C8739E111D2BF14F00A89F3C /* EventData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventData.swift; sourceTree = ""; }; + C8739E131D2BF16300A89F3C /* LeaderboardData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeaderboardData.swift; sourceTree = ""; }; + C8739E151D2BF17900A89F3C /* CompetitorData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompetitorData.swift; sourceTree = ""; }; + C8739E171D2BF2DC00A89F3C /* BaseData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseData.swift; sourceTree = ""; }; + C8739E1B1D2D5F1700A89F3C /* LocationData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationData.swift; sourceTree = ""; }; C89C5FC41D06A289002AAAD2 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = ""; }; C89C5FC91D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusTrackingTableViewCell.swift; sourceTree = ""; }; C89C5FCB1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GPSAccuracyTrackingTableViewCell.swift; sourceTree = ""; }; @@ -793,9 +803,10 @@ 7F06590219F7FEA40077FF95 /* DataController */ = { isa = PBXGroup; children = ( - C8739D8A1D22CCDB00A89F3C /* GPSFixes */, + C8739E0E1D2BEE7900A89F3C /* RegattaController.swift */, + 7F23F0871A1A3DEF00F03F1C /* CheckInController.swift */, + C8739E101D2BF13200A89F3C /* Data */, C852BAA61CF5E1F40093B0C5 /* CheckIn */, - 7F1B66F81A0CDCF600904A41 /* BatteryManager.swift */, ); name = DataController; sourceTree = ""; @@ -1162,8 +1173,6 @@ C852BAA61CF5E1F40093B0C5 /* CheckIn */ = { isa = PBXGroup; children = ( - 7F0658FE19F7EE910077FF95 /* CheckInData.swift */, - 7F23F0871A1A3DEF00F03F1C /* CheckInController.swift */, ); name = CheckIn; sourceTree = ""; @@ -1176,17 +1185,11 @@ name = Preferences; sourceTree = ""; }; - C8739D8A1D22CCDB00A89F3C /* GPSFixes */ = { - isa = PBXGroup; - children = ( - C8739D8D1D23D53C00A89F3C /* SendGPSFixesController.swift */, - ); - name = GPSFixes; - sourceTree = ""; - }; C8739D8B1D23C01500A89F3C /* Managers */ = { isa = PBXGroup; children = ( + 7F2C605919F160E400C32D93 /* LocationManager.swift */, + 7F1B66F81A0CDCF600904A41 /* BatteryManager.swift */, C852BAA11CF5E1EA0093B0C5 /* RequestManager.swift */, ); name = Managers; @@ -1200,20 +1203,11 @@ name = EULA; sourceTree = ""; }; - C8739DC61D2A650E00A89F3C /* Location */ = { - isa = PBXGroup; - children = ( - 7F2C605919F160E400C32D93 /* LocationManager.swift */, - ); - name = Location; - sourceTree = ""; - }; C8739DC71D2A653F00A89F3C /* Classes */ = { isa = PBXGroup; children = ( 7F06590019F7FE750077FF95 /* CoreData */, 7F06590219F7FEA40077FF95 /* DataController */, - C8739DC61D2A650E00A89F3C /* Location */, C8739D8B1D23C01500A89F3C /* Managers */, C852BAA91CF736440093B0C5 /* Preferences */, 7F06590119F7FE920077FF95 /* ViewController */, @@ -1222,6 +1216,19 @@ name = Classes; sourceTree = ""; }; + C8739E101D2BF13200A89F3C /* Data */ = { + isa = PBXGroup; + children = ( + 7F0658FE19F7EE910077FF95 /* RegattaData.swift */, + C8739E111D2BF14F00A89F3C /* EventData.swift */, + C8739E131D2BF16300A89F3C /* LeaderboardData.swift */, + C8739E151D2BF17900A89F3C /* CompetitorData.swift */, + C8739E171D2BF2DC00A89F3C /* BaseData.swift */, + C8739E1B1D2D5F1700A89F3C /* LocationData.swift */, + ); + name = Data; + sourceTree = ""; + }; C89C5FC31D06A269002AAAD2 /* Views */ = { isa = PBXGroup; children = ( @@ -1847,9 +1854,13 @@ files = ( 7F1875B31A10F1B800C25BE0 /* TrackingViewController.swift in Sources */, C8739E081D2AA2A500A89F3C /* Leaderboard+CoreDataProperties.swift in Sources */, + C8739E121D2BF14F00A89F3C /* EventData.swift in Sources */, + C8739E0F1D2BEE7900A89F3C /* RegattaController.swift in Sources */, + C8739E1C1D2D5F1700A89F3C /* LocationData.swift in Sources */, 7F83F15819F154F000C53328 /* HomeViewController.swift in Sources */, 7F8B8D431A373D4400C34B88 /* CourseViewController.swift in Sources */, 7FAFA7951A126B5700D230F1 /* AboutViewController.swift in Sources */, + C8739E161D2BF17900A89F3C /* CompetitorData.swift in Sources */, C8739E0A1D2AA2A500A89F3C /* Competitor+CoreDataProperties.swift in Sources */, C8739E0C1D2AA2A500A89F3C /* Event+CoreDataProperties.swift in Sources */, C8739E071D2AA2A500A89F3C /* GPSFix.swift in Sources */, @@ -1859,7 +1870,6 @@ 7FA6551A19F6661900A1B92D /* CoreDataManager.swift in Sources */, C852BAA21CF5E1EA0093B0C5 /* RequestManager.swift in Sources */, C8BBAC791C52649E004CA551 /* LicenseViewController.swift in Sources */, - C8739D8E1D23D53C00A89F3C /* SendGPSFixesController.swift in Sources */, 7F23F0881A1A3DEF00F03F1C /* CheckInController.swift in Sources */, 7F2C605A19F160E400C32D93 /* LocationManager.swift in Sources */, C89C5FCC1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift in Sources */, @@ -1874,16 +1884,18 @@ 9E95C3D61C723AB30016632B /* Constants.swift in Sources */, 7FD9D3031A1236080058FEAD /* Extensions.swift in Sources */, C8739E091D2AA2A500A89F3C /* Leaderboard.swift in Sources */, + C8739E141D2BF16300A89F3C /* LeaderboardData.swift in Sources */, C89C5FC51D06A289002AAAD2 /* GradientView.swift in Sources */, C852BAAB1CF736680093B0C5 /* Preferences.swift in Sources */, 7F0658FD19F7D6700077FF95 /* ScanViewController.swift in Sources */, C8739E061D2AA2A500A89F3C /* GPSFix+CoreDataProperties.swift in Sources */, 7F193A8F1A39ACF500D71773 /* TimerViewController.swift in Sources */, + C8739E181D2BF2DC00A89F3C /* BaseData.swift in Sources */, 7F83F15619F154F000C53328 /* AppDelegate.swift in Sources */, 7F950A911A35E967003C8C5C /* LeaderboardViewController.swift in Sources */, C89C5FCE1D06CF26002AAAD2 /* CachedFixesTrackingTableViewCell.swift in Sources */, C8739E0B1D2AA2A500A89F3C /* Competitor.swift in Sources */, - 7F0658FF19F7EE910077FF95 /* CheckInData.swift in Sources */, + 7F0658FF19F7EE910077FF95 /* RegattaData.swift in Sources */, 7F193A911A39E54600D71773 /* GPSAccuracyView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/SAPTracker/src/xcode/SAPTracker/BaseData.swift b/ios/SAPTracker/src/xcode/SAPTracker/BaseData.swift new file mode 100644 index 00000000000..7637446c72e --- /dev/null +++ b/ios/SAPTracker/src/xcode/SAPTracker/BaseData.swift @@ -0,0 +1,33 @@ +// +// BaseData.swift +// SAPTracker +// +// Created by Raimund Wege on 05.07.16. +// Copyright © 2016 com.sap.sailing. All rights reserved. +// + +import UIKit + +class BaseData: NSObject { + + let dictionary: [String: AnyObject] + + override init() { + self.dictionary = [String: AnyObject]() + super.init() + } + + init(dictionary: [String: AnyObject]?) { + self.dictionary = dictionary ?? [String: AnyObject]() + super.init() + } + + func doubleValue(forKey key: String) -> Double { + return dictionary[key] as? Double ?? 0.0 + } + + func stringValue(forKey key: String) -> String { + return dictionary[key] as? String ?? "" + } + +} diff --git a/ios/SAPTracker/src/xcode/SAPTracker/CachedFixesTrackingTableViewCell.swift b/ios/SAPTracker/src/xcode/SAPTracker/CachedFixesTrackingTableViewCell.swift index f89f23b32f9..cc00f9e5a2e 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/CachedFixesTrackingTableViewCell.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/CachedFixesTrackingTableViewCell.swift @@ -35,8 +35,9 @@ class CachedFixesTrackingTableViewCell: UITableViewCell { private func subscribeForNotifications() { NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(locationManagerUpdated(_:)), - name:LocationManager.NotificationType.LocationManagerUpdated, - object: nil) + name:LocationManager.NotificationType.Updated, + object: nil + ) } private func unsubscribeFromNotifications() { diff --git a/ios/SAPTracker/src/xcode/SAPTracker/CheckInController.swift b/ios/SAPTracker/src/xcode/SAPTracker/CheckInController.swift index 4dfb00da01d..6b1e5c51fc1 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/CheckInController.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/CheckInController.swift @@ -21,134 +21,26 @@ import AVFoundation class CheckInController : NSObject { - private struct EventKeys { - static let EndDate = "endDate" - static let ID = "id" - static let ImageURLs = "imageURLs" - static let Name = "name" - static let StartDate = "startDate" - } - - private struct CompetitorKeys { - static let BoatClassName = "boatClassName" - static let CountryCode = "countryCode" - static let ID = "id" - static let Name = "name" - static let Nationality = "nationality" - static let SailID = "sailID" - } - - private struct LeaderboardKeys { - static let Name = "name" - } - var delegate: CheckInControllerDelegate? - private var checkInData = CheckInData() private var requestManager = RequestManager() - - // Responses - private var eventDictionary: [String: AnyObject]? - private var leaderboardDictionary: [String: AnyObject]? - private var competitorDictionary: [String: AnyObject]? - private var teamImageURL: String? - // MARK: - Initialize + // MARK: - CheckIn - private func initialize(checkInData: CheckInData) { - self.checkInData = checkInData - setupRequestManager() - } - - // MARK: - Setups - - private func setupRequestManager() { - requestManager = RequestManager(baseURLString: checkInData.serverURL) - } - - // MARK: - Start check-in - - func startCheckIn(checkInData: CheckInData) { - initialize(checkInData) + func checkIn(regattaData: RegattaData) { checkInDidStart() - requestManager.getEvent(checkInData.eventID, - success: { (operation, responseObject) -> Void in self.eventSucceed(responseObject) }, - failure: { (operation, error) -> Void in self.eventFailed(error) } + requestManager = RequestManager(baseURLString: regattaData.serverURL) + requestManager.getRegattaData(regattaData, + success: { (regattaData) in self.checkInSuccess(regattaData) }, + failure: { (title, error) in self.checkInFailure(title, error: error) } ) } - // MARK: - Event - - private func eventSucceed(eventResponseObject: AnyObject) { - eventDictionary = eventResponseObject as? [String: AnyObject] - requestManager.getLeaderboard(checkInData.leaderboardName, - success: { (operation, responseObject) -> Void in self.leaderboardSucceed(responseObject) }, - failure: { (operation, error) -> Void in self.leaderboardFailed(error) } - ) - } - - private func eventFailed(error: AnyObject) { - let alertTitle = String(format: NSLocalizedString("Couldn't get event %@", comment: ""), checkInData.eventID) - let alertController = UIAlertController(title: alertTitle, message: error.localizedDescription, preferredStyle: .Alert) - let cancelTitle = NSLocalizedString("Cancel", comment: "") - let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel) { (action) in - self.checkInDidEnd(withSuccess: false) - } - alertController.addAction(cancelAction) - showCheckInAlert(alertController) - } - - // MARK: - Leaderboard - - private func leaderboardSucceed(leaderboardResponseObject: AnyObject) { - leaderboardDictionary = leaderboardResponseObject as? [String: AnyObject] - requestManager.getCompetitor(checkInData.competitorID, - success: { (operation, responseObject) in self.competitorSucceed(responseObject) }, - failure: { (operation, error) in self.competitorFailed(error) } - ) - } - - private func leaderboardFailed(error: AnyObject) { - let alertTitle = String(format: NSLocalizedString("Couldn't get leader board %@", comment: ""), checkInData.leaderboardName) - let alertController = UIAlertController(title: alertTitle, message: error.localizedDescription, preferredStyle: .Alert) - let cancelTitle = NSLocalizedString("Cancel", comment: "") - let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel) { (action) in - self.checkInDidEnd(withSuccess: false) - } - alertController.addAction(cancelAction) - showCheckInAlert(alertController) - } - - // MARK: - Competitor - - private func competitorSucceed(competitorResponseObject: AnyObject) { - competitorDictionary = competitorResponseObject as? [String: AnyObject] - requestManager.getTeamImageURL(competitorID, result: { (imageURL) in self.teamImageURLResult(imageURL) }) - } - - private func competitorFailed(error: AnyObject) { - let alertTitle = String(format: NSLocalizedString("Couldn't get competitor %@", comment: ""), checkInData.competitorID) - let alertController = UIAlertController(title: alertTitle, message: error.localizedDescription, preferredStyle: .Alert) - let cancelTitle = NSLocalizedString("Cancel", comment: "") - let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel) { (action) in - self.checkInDidEnd(withSuccess: false) - } - alertController.addAction(cancelAction) - showCheckInAlert(alertController) - } - - // MARK: - Team - - private func teamImageURLResult(imageURL: String?) { - teamImageURL = imageURL - let alertTitle = String(format:NSLocalizedString("Hello %@. Welcome to %@. You are registered as %@.", comment: ""), - competitorName, - leaderboardName, - competitorSailID) - let alertController = UIAlertController(title: alertTitle, message: nil, preferredStyle: .Alert) + private func checkInSuccess(regattaData: RegattaData) { + let alertController = UIAlertController(title: regattaData.welcomeString, message: nil, preferredStyle: .Alert) let okTitle = NSLocalizedString("OK", comment: "") let okAction = UIAlertAction(title: okTitle, style: .Default) { (action) in - self.checkInOnServer() + self.postCheckIn(regattaData) } let cancelTitle = NSLocalizedString("Cancel", comment: "") let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel) { (action) in @@ -159,47 +51,45 @@ class CheckInController : NSObject { showCheckInAlert(alertController) } - // MARK: - Check-in on server + private func checkInFailure(title: String, error: NSError) { + let alertController = UIAlertController(title: title, message: error.localizedDescription, preferredStyle: .Alert) + let cancelTitle = NSLocalizedString("Cancel", comment: "") + let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel) { (action) in + self.checkInDidEnd(withSuccess: false) + } + alertController.addAction(cancelAction) + showCheckInAlert(alertController) + } - private func checkInOnServer() { + private func postCheckIn(regattaData: RegattaData) { SVProgressHUD.show() - requestManager.postCheckIn(leaderboardName, - competitorID: competitorID, - success: { (operation, responseObject) -> Void in self.checkInOnServerSucceed() }, - failure: { (operation, error) -> Void in self.checkInOnServerFailed(error) } + requestManager.postCheckIn(regattaData.leaderboardData.name, + competitorID: regattaData.competitorData.competitorID, + success: { (operation, responseObject) -> Void in self.postCheckInSuccess(regattaData) }, + failure: { (operation, error) -> Void in self.postCheckInFailure(regattaData, error: error) } ) } - private func checkInOnServerSucceed() { + private func postCheckInSuccess(regattaData: RegattaData) { // Regatta - let regatta = CoreDataManager.sharedManager.fetchRegatta(checkInData.eventID, - leaderboardName: checkInData.leaderboardName, - competitorID: checkInData.competitorID + let regatta = CoreDataManager.sharedManager.fetchRegatta(regattaData.eventID, + leaderboardName: regattaData.leaderboardName, + competitorID: regattaData.competitorID ) ?? CoreDataManager.sharedManager.newRegatta() - regatta.serverURL = checkInData.serverURL - regatta.teamImageURL = teamImageURL - regatta.teamImageRetry = false + regatta.updateWirhRegattaData(regattaData) // Event let event = regatta.event ?? CoreDataManager.sharedManager.newEvent(regatta) - event.endDate = (eventEndDate / 1000) - event.eventID = eventID - event.name = eventName - event.startDate = (eventStartDate / 1000) + event.updateWithEventData(regattaData.eventData) // Leaderboard let leaderboard = regatta.leaderboard ?? CoreDataManager.sharedManager.newLeaderboard(regatta) - leaderboard.name = leaderboardName + leaderboard.updateWithLeaderboardData(regattaData.leaderboardData) // Competitor let competitor = regatta.competitor ?? CoreDataManager.sharedManager.newCompetitor(regatta) - competitor.boatClassName = competitorBoatClassName - competitor.competitorID = competitorID - competitor.countryCode = competitorCountryCode - competitor.name = competitorName - competitor.nationality = competitorNationality - competitor.sailID = competitorSailID + competitor.updateWithCompetitorData(regattaData.competitorData) // Save CoreDataManager.sharedManager.saveContext() @@ -208,8 +98,8 @@ class CheckInController : NSObject { checkInDidEnd(withSuccess: true) } - private func checkInOnServerFailed(error: AnyObject) { - let alertTitle = String(format:NSLocalizedString("Couldn't check-in to %@", comment: ""), checkInData.leaderboardName) + private func postCheckInFailure(regattaData: RegattaData, error: AnyObject) { + let alertTitle = String(format:NSLocalizedString("Couldn't check-in to %@", comment: ""), regattaData.leaderboardName) let alertController = UIAlertController(title: alertTitle, message: error.localizedDescription, preferredStyle: .Alert) let cancelTitle = NSLocalizedString("Cancel", comment: "") let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel) { (action) in @@ -222,67 +112,18 @@ class CheckInController : NSObject { // MARK: - Controller private func checkInDidStart() { - dispatch_async(dispatch_get_main_queue(), { - SVProgressHUD.show() - self.delegate?.checkInDidStart?(self) - }) + SVProgressHUD.show() + self.delegate?.checkInDidStart?(self) } private func checkInDidEnd(withSuccess succeed: Bool) { - dispatch_async(dispatch_get_main_queue(), { - SVProgressHUD.popActivity() - self.delegate?.checkInDidEnd?(self, withSuccess: succeed) - }) + SVProgressHUD.popActivity() + self.delegate?.checkInDidEnd?(self, withSuccess: succeed) } private func showCheckInAlert(alertController: UIAlertController) { - dispatch_async(dispatch_get_main_queue(), { - SVProgressHUD.popActivity() - self.delegate?.showCheckInAlert(self, alertController: alertController) - }) - } - - // MARK: - Event - - var eventID: String { get { return stringFromEvent(forKey: EventKeys.ID) } } - var eventName: String { get { return stringFromEvent(forKey: EventKeys.Name) } } - var eventStartDate: Double { get { return doubleFromEvent(forKey: EventKeys.StartDate) } } - var eventEndDate: Double { get { return doubleFromEvent(forKey: EventKeys.EndDate) } } - - // MARK: - Leaderboard - - var leaderboardName: String { get { return stringFromLeaderboard(forKey: LeaderboardKeys.Name) } } - - // MARK: - Competitor - - var competitorBoatClassName: String { get { return stringFromCompetitor(forKey: CompetitorKeys.BoatClassName) } } - var competitorCountryCode: String { get { return stringFromCompetitor(forKey: CompetitorKeys.CountryCode) } } - var competitorID: String { get { return stringFromCompetitor(forKey: CompetitorKeys.ID) } } - var competitorName: String { get { return stringFromCompetitor(forKey: CompetitorKeys.Name) } } - var competitorNationality: String { get { return stringFromCompetitor(forKey: CompetitorKeys.Nationality) } } - var competitorSailID: String { get { return stringFromCompetitor(forKey: CompetitorKeys.SailID) } } - - // MARK: - Helper - - private func doubleFromEvent(forKey key: String) -> Double { return doubleFromDictionary(eventDictionary, forKey: key) } - private func stringFromEvent(forKey key: String) -> String { return stringFromDictionary(eventDictionary, forKey: key) } - private func stringFromLeaderboard(forKey key: String) -> String { return stringFromDictionary(leaderboardDictionary, forKey: key) } - private func stringFromCompetitor(forKey key: String) -> String { return stringFromDictionary(competitorDictionary, forKey: key) } - - private func doubleFromDictionary(dictionary: [String: AnyObject]?, forKey key: String) -> Double { - if let value = dictionary?[key] as? Double { - return value - } else { - return 0.0 - } - } - - private func stringFromDictionary(dictionary: [String: AnyObject]?, forKey key: String) -> String { - if let value = dictionary?[key] as? String { - return value - } else { - return "" - } + SVProgressHUD.popActivity() + self.delegate?.showCheckInAlert(self, alertController: alertController) } } \ No newline at end of file diff --git a/ios/SAPTracker/src/xcode/SAPTracker/Competitor.swift b/ios/SAPTracker/src/xcode/SAPTracker/Competitor.swift index fd72e2a81af..80c34f621d0 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/Competitor.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/Competitor.swift @@ -12,6 +12,13 @@ import CoreData @objc(Competitor) class Competitor: NSManagedObject { -// Insert code here to add functionality to your managed object subclass - + func updateWithCompetitorData(competitorData: CompetitorData) { + boatClassName = competitorData.boatClassName + competitorID = competitorData.competitorID + countryCode = competitorData.countryCode + name = competitorData.name + nationality = competitorData.nationality + sailID = competitorData.sailID + } + } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/CompetitorData.swift b/ios/SAPTracker/src/xcode/SAPTracker/CompetitorData.swift new file mode 100644 index 00000000000..1c4b0917b65 --- /dev/null +++ b/ios/SAPTracker/src/xcode/SAPTracker/CompetitorData.swift @@ -0,0 +1,29 @@ +// +// CompetitorData.swift +// SAPTracker +// +// Created by Raimund Wege on 05.07.16. +// Copyright © 2016 com.sap.sailing. All rights reserved. +// + +import UIKit + +class CompetitorData: BaseData { + + private struct Keys { + static let BoatClassName = "boatClassName" + static let CountryCode = "countryCode" + static let ID = "id" + static let Name = "name" + static let Nationality = "nationality" + static let SailID = "sailID" + } + + var boatClassName: String { get { return stringValue(forKey: Keys.BoatClassName) } } + var countryCode: String { get { return stringValue(forKey: Keys.CountryCode) } } + var competitorID: String { get { return stringValue(forKey: Keys.ID) } } + var name: String { get { return stringValue(forKey: Keys.Name) } } + var nationality: String { get { return stringValue(forKey: Keys.Nationality) } } + var sailID: String { get { return stringValue(forKey: Keys.SailID) } } + +} diff --git a/ios/SAPTracker/src/xcode/SAPTracker/CourseViewController.swift b/ios/SAPTracker/src/xcode/SAPTracker/CourseViewController.swift index bbc22173eeb..fe5a12c0d70 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/CourseViewController.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/CourseViewController.swift @@ -35,7 +35,11 @@ class CourseViewController: UIViewController { private func subscribeForNotifications() { NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(locationManagerUpdated(_:)), - name:LocationManager.NotificationType.LocationManagerUpdated, + name:LocationManager.NotificationType.Updated, + object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, + selector:#selector(locationManagerFailed(_:)), + name:LocationManager.NotificationType.Failed, object: nil) } @@ -45,7 +49,14 @@ class CourseViewController: UIViewController { func locationManagerUpdated(notification: NSNotification) { dispatch_async(dispatch_get_main_queue(), { - self.setupCourseLabel(notification.userInfo![LocationManager.UserInfo.Course] as! Double) + guard let locationData = notification.userInfo?[LocationManager.UserInfo.LocationData] as? LocationData else { return } + self.setupCourseLabel(locationData.location.course) + }) + } + + func locationManagerFailed(notification: NSNotification) { + dispatch_async(dispatch_get_main_queue(), { + self.setupCourseLabel(-1.0) }) } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/Event.swift b/ios/SAPTracker/src/xcode/SAPTracker/Event.swift index 5e5319b835f..2f6c94b489e 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/Event.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/Event.swift @@ -12,6 +12,11 @@ import CoreData @objc(Event) class Event: NSManagedObject { -// Insert code here to add functionality to your managed object subclass - + func updateWithEventData(eventData: EventData) { + endDate = eventData.endDate + eventID = eventData.eventID + name = eventData.name + startDate = eventData.startDate + } + } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/EventData.swift b/ios/SAPTracker/src/xcode/SAPTracker/EventData.swift new file mode 100644 index 00000000000..655bf292f1c --- /dev/null +++ b/ios/SAPTracker/src/xcode/SAPTracker/EventData.swift @@ -0,0 +1,26 @@ +// +// EventData.swift +// SAPTracker +// +// Created by Raimund Wege on 05.07.16. +// Copyright © 2016 com.sap.sailing. All rights reserved. +// + +import UIKit + +class EventData: BaseData { + + private struct Keys { + static let EndDate = "endDate" + static let ID = "id" + static let ImageURLs = "imageURLs" + static let Name = "name" + static let StartDate = "startDate" + } + + var endDate: Double { get { return doubleValue(forKey: Keys.EndDate) / 1000 } } + var eventID: String { get { return stringValue(forKey: Keys.ID) } } + var name: String { get { return stringValue(forKey: Keys.Name) } } + var startDate: Double { get { return doubleValue(forKey: Keys.StartDate) / 1000 } } + +} diff --git a/ios/SAPTracker/src/xcode/SAPTracker/GPSAccuracyTrackingTableViewCell.swift b/ios/SAPTracker/src/xcode/SAPTracker/GPSAccuracyTrackingTableViewCell.swift index 2a7afed7808..71ba304b070 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/GPSAccuracyTrackingTableViewCell.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/GPSAccuracyTrackingTableViewCell.swift @@ -38,12 +38,14 @@ class GPSAccuracyTrackingTableViewCell: UITableViewCell { private func subscribeForNotifications() { NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(locationManagerUpdated(_:)), - name:LocationManager.NotificationType.LocationManagerUpdated, - object: nil) + name:LocationManager.NotificationType.Updated, + object: nil + ) NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(locationManagerFailed(_:)), - name:LocationManager.NotificationType.LocationManagerFailed, - object: nil) + name:LocationManager.NotificationType.Failed, + object: nil + ) } private func unsubscribeFromNotifications() { @@ -52,7 +54,8 @@ class GPSAccuracyTrackingTableViewCell: UITableViewCell { func locationManagerUpdated(notification: NSNotification) { dispatch_async(dispatch_get_main_queue(), { - self.setupGPSAccuracyLabel(notification.userInfo![LocationManager.UserInfo.HorizontalAccuracy] as! Double) + guard let locationData = notification.userInfo?[LocationManager.UserInfo.LocationData] as? LocationData else { return } + self.setupGPSAccuracyLabel(locationData.location.horizontalAccuracy) }) } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/GPSAccuracyView.swift b/ios/SAPTracker/src/xcode/SAPTracker/GPSAccuracyView.swift index 0ea8c4f3e64..b493243e93e 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/GPSAccuracyView.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/GPSAccuracyView.swift @@ -58,12 +58,14 @@ class GPSAccuracyView : UIView { private func subscribeForNotifications() { NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(locationManagerUpdated(_:)), - name:LocationManager.NotificationType.LocationManagerUpdated, - object: nil) + name:LocationManager.NotificationType.Updated, + object: nil + ) NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(locationManagerFailed(_:)), - name:LocationManager.NotificationType.LocationManagerFailed, - object: nil) + name:LocationManager.NotificationType.Failed, + object: nil + ) } private func unsubscribeFromNotifications() { @@ -72,7 +74,8 @@ class GPSAccuracyView : UIView { func locationManagerUpdated(notification: NSNotification) { dispatch_async(dispatch_get_main_queue(), { - self.drawBar(notification.userInfo![LocationManager.UserInfo.HorizontalAccuracy] as! Double) + guard let locationData = notification.userInfo?[LocationManager.UserInfo.LocationData] as? LocationData else { return } + self.drawBar(locationData.location.horizontalAccuracy) }) } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/GPSFix.swift b/ios/SAPTracker/src/xcode/SAPTracker/GPSFix.swift index fe66d0de74d..0a56e0172a0 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/GPSFix.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/GPSFix.swift @@ -12,6 +12,12 @@ import CoreData @objc(GPSFix) class GPSFix: NSManagedObject { -// Insert code here to add functionality to your managed object subclass - + func updateWithLocationData(locationData: LocationData) { + course = locationData.location.course + latitude = locationData.location.coordinate.latitude + longitude = locationData.location.coordinate.longitude + speed = locationData.location.speed + timestamp = round(locationData.location.timestamp.timeIntervalSince1970 * 1000) + } + } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/HomeViewController.swift b/ios/SAPTracker/src/xcode/SAPTracker/HomeViewController.swift index 6257e3d5ec5..b7363f2dc25 100755 --- a/ios/SAPTracker/src/xcode/SAPTracker/HomeViewController.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/HomeViewController.swift @@ -84,7 +84,7 @@ class HomeViewController: UIViewController { let viewTitle = NSLocalizedString("EULA_view", comment: "") let viewAction = UIAlertAction(title: viewTitle, style: .Cancel, handler: { action in UIApplication.sharedApplication().openURL(URLs.EULA) - self.reviewEULA() // Reopen alert + self.reviewEULA() // Reopen alert again until user confirms }) let confirmTitle = NSLocalizedString("EULA_confirm", comment: "") let confirmAction = UIAlertAction(title: confirmTitle, style: .Default, handler: { action in @@ -99,8 +99,8 @@ class HomeViewController: UIViewController { func reviewNewCheckIn() { guard Preferences.termsAccepted else { return } guard let urlString = Preferences.newCheckInURL else { return } - guard let checkInData = CheckInData(urlString: urlString) else { return } - checkInController.startCheckIn(checkInData) + guard let regattaData = RegattaData(urlString: urlString) else { return } + checkInController.checkIn(regattaData) } // MARK: - Notifications @@ -126,21 +126,14 @@ class HomeViewController: UIViewController { @IBAction func optionButtonTap(sender: AnyObject) { let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet) - // FIXME: - what does this code? - // if let popoverController = actionSheet.popoverPresentationController, - // let barButtonItem = sender as? UIBarButtonItem { - // popoverController.barButtonItem = barButtonItem - // } - // FIXME: - should be a simpler solution than dispatch with magic numbers + if let popoverController = alertController.popoverPresentationController { + popoverController.barButtonItem = sender as? UIBarButtonItem + } let settingsAction = UIAlertAction(title: NSLocalizedString("Settings", comment: ""), style: .Default) { (action) -> Void in - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.6 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in - self.performSegueWithIdentifier("SettingsFromHome", sender: alertController) - } + self.performSegueWithIdentifier("SettingsFromHome", sender: alertController) } let aboutAction = UIAlertAction(title: NSLocalizedString("About", comment: ""), style: .Default) { (action) -> Void in - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.6 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in - self.performSegueWithIdentifier("AboutFromHome", sender: alertController) - } + self.performSegueWithIdentifier("AboutFromHome", sender: alertController) } let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel, handler: nil) alertController.addAction(settingsAction) @@ -159,7 +152,6 @@ class HomeViewController: UIViewController { let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel, handler: nil) alertController.addAction(cancelAction) presentViewController(alertController, animated: true, completion: nil) - return } } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/Leaderboard.swift b/ios/SAPTracker/src/xcode/SAPTracker/Leaderboard.swift index 298fcd76c57..d421cf63c56 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/Leaderboard.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/Leaderboard.swift @@ -12,6 +12,10 @@ import CoreData @objc(Leaderboard) class Leaderboard: NSManagedObject { + func updateWithLeaderboardData(leaderboardData: LeaderboardData) { + name = leaderboardData.name + } + func nameWithQueryAllowedCharacters() -> String? { return name.stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet()) } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/LeaderboardData.swift b/ios/SAPTracker/src/xcode/SAPTracker/LeaderboardData.swift new file mode 100644 index 00000000000..0477dc524d5 --- /dev/null +++ b/ios/SAPTracker/src/xcode/SAPTracker/LeaderboardData.swift @@ -0,0 +1,19 @@ +// +// LeaderboardData.swift +// SAPTracker +// +// Created by Raimund Wege on 05.07.16. +// Copyright © 2016 com.sap.sailing. All rights reserved. +// + +import UIKit + +class LeaderboardData: BaseData { + + private struct Keys { + static let Name = "name" + } + + var name: String { get { return stringValue(forKey: Keys.Name) } } + +} diff --git a/ios/SAPTracker/src/xcode/SAPTracker/LocationData.swift b/ios/SAPTracker/src/xcode/SAPTracker/LocationData.swift new file mode 100644 index 00000000000..c5f7ea2edc8 --- /dev/null +++ b/ios/SAPTracker/src/xcode/SAPTracker/LocationData.swift @@ -0,0 +1,34 @@ +// +// LocationData.swift +// SAPTracker +// +// Created by Raimund Wege on 06.07.16. +// Copyright © 2016 com.sap.sailing. All rights reserved. +// + +import UIKit +import CoreLocation + +class LocationData: NSObject { + + struct LocationValidation { + static let requiredAccuracy: CLLocationAccuracy = 10 + static let maxElapsedTime: NSTimeInterval = 10 + } + + var location: CLLocation + + init(location: CLLocation) { + self.location = location + super.init() + } + + var isValid: Bool { + get { + guard location.horizontalAccuracy >= 0 && location.horizontalAccuracy <= LocationValidation.requiredAccuracy else { return false } + guard location.timestamp.timeIntervalSinceDate(NSDate()) <= LocationValidation.maxElapsedTime else { return false } + return true; + } + } + +} diff --git a/ios/SAPTracker/src/xcode/SAPTracker/LocationManager.swift b/ios/SAPTracker/src/xcode/SAPTracker/LocationManager.swift index 9d81db68c39..81c449732e9 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/LocationManager.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/LocationManager.swift @@ -12,10 +12,15 @@ import CoreLocation class LocationManager: NSObject { struct NotificationType { - static let LocationManagerStarted = "LocationManagerStarted" - static let LocationManagerStopped = "LocationManagerStopped" - static let LocationManagerUpdated = "LocationManagerUpdated" - static let LocationManagerFailed = "LocationManagerFailed" + static let Started = "LocationManager.Started" + static let Stopped = "LocationManager.Stopped" + static let Updated = "LocationManager.Updated" + static let Failed = "LocationManager.Failed" + } + + struct UserInfo { + static let Error = "NSError" + static let LocationData = "LocationData" } enum LocationManagerError: ErrorType { @@ -23,8 +28,8 @@ class LocationManager: NSObject { case LocationServicesDenied var description: String { switch self { - case LocationManagerError.LocationServicesDenied: return NSLocalizedString("Please enable location services for this app.", comment: "") - case LocationManagerError.LocationServicesDisabled: return NSLocalizedString("Please enable location services.", comment: "") + case .LocationServicesDenied: return NSLocalizedString("Please enable location services for this app.", comment: "") + case .LocationServicesDisabled: return NSLocalizedString("Please enable location services.", comment: "") } } } @@ -74,7 +79,7 @@ class LocationManager: NSObject { isTracking = true; // Send notification - let notification = NSNotification(name: NotificationType.LocationManagerStarted, object: self) + let notification = NSNotification(name: NotificationType.Started, object: self) NSNotificationQueue.defaultQueue().enqueueNotification(notification, postingStyle: NSPostingStyle.PostASAP) } @@ -86,7 +91,7 @@ class LocationManager: NSObject { isTracking = false; // Send notification - let notification = NSNotification(name: NotificationType.LocationManagerStopped, object: self) + let notification = NSNotification(name: NotificationType.Stopped, object: self) NSNotificationQueue.defaultQueue().enqueueNotification(notification, postingStyle: NSPostingStyle.PostASAP) } @@ -95,51 +100,19 @@ class LocationManager: NSObject { // MARK: - CLLocationManagerDelegate extension LocationManager: CLLocationManagerDelegate { - - struct UserInfo { - static let Error = "error" - static let Course = "course" - static let HorizontalAccuracy = "horizontalAccuracy" - static let IsValid = "isValid" - static let Latitude = "latitude" - static let Longitude = "longitude" - static let Speed = "speed" - static let Timestamp = "timestamp" - } - - struct LocationValidation { - static let requiredAccuracy: CLLocationAccuracy = 10 - static let maxElapsedTime: NSTimeInterval = 10 - } - + func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { - let notification = NSNotification(name: NotificationType.LocationManagerUpdated, object: self, userInfo:dictionaryForLocation(locations.last!)) + guard let location = locations.last else { return } + let locationData = LocationData(location: location) + let userInfo = [UserInfo.LocationData: locationData] + let notification = NSNotification(name: NotificationType.Updated, object: self, userInfo: userInfo) NSNotificationQueue.defaultQueue().enqueueNotification(notification, postingStyle: NSPostingStyle.PostASAP) } func locationManager(manager: CLLocationManager, didFailWithError error: NSError) { - let notification = NSNotification(name: NotificationType.LocationManagerFailed, object: self, userInfo: [UserInfo.Error: error]) + let userInfo = [UserInfo.Error: error] + let notification = NSNotification(name: NotificationType.Failed, object: self, userInfo: userInfo) NSNotificationQueue.defaultQueue().enqueueNotification(notification, postingStyle: NSPostingStyle.PostASAP) } - // MARK: - Helper - - private func dictionaryForLocation(location: CLLocation) -> [String: AnyObject] { - return [ - UserInfo.Timestamp: location.timestamp.timeIntervalSince1970, - UserInfo.Latitude : location.coordinate.latitude, - UserInfo.Longitude: location.coordinate.longitude, - UserInfo.Speed: location.speed, - UserInfo.Course: location.course, - UserInfo.HorizontalAccuracy: location.horizontalAccuracy, - UserInfo.IsValid: isLocationValid(location) - ] - } - - private func isLocationValid(location: CLLocation) -> Bool { - guard location.horizontalAccuracy >= 0 && location.horizontalAccuracy <= LocationValidation.requiredAccuracy else { return false } - guard location.timestamp.timeIntervalSinceDate(NSDate()) <= LocationValidation.maxElapsedTime else { return false } - return true; - } - } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/ModeTrackingTableViewCell.swift b/ios/SAPTracker/src/xcode/SAPTracker/ModeTrackingTableViewCell.swift index 676bf34eee0..82946ea996e 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/ModeTrackingTableViewCell.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/ModeTrackingTableViewCell.swift @@ -14,48 +14,39 @@ class ModeTrackingTableViewCell: UITableViewCell { override func awakeFromNib() { super.awakeFromNib() - self.setupModeLabel() -// self.subscribeForNotifications() + self.setupModeLabel(RegattaController.Mode.Offline) + self.subscribeForNotifications() } deinit { -// self.unsubscribeFromNotifications() + self.unsubscribeFromNotifications() } // MARK: - Setups - private func setupModeLabel() { - // FIXME: - network availability - //if (APIManager.sharedManager.networkAvailable) { - if !BatteryManager.sharedManager.batterySaving { - modeLabel.text = NSLocalizedString("Online", comment: "") - } else { - modeLabel.text = NSLocalizedString("Battery Saving", comment: "") - } - //} else { - // modeLabel.text = NSLocalizedString("Offline", comment: "") - //} - // FIXME: - Show "API Error" in red in case of response errors + private func setupModeLabel(mode: RegattaController.Mode) { + modeLabel.text = mode.description } // MARK: - Notifications -// FIXME: - Network availability -// private func subscribeForNotifications() { -// NSNotificationCenter.defaultCenter().addObserver(self, -// selector:#selector(networkAvailabilityChanged), -// name:APIManager.NotificationType.networkAvailabilityChanged, -// object: nil) -// } -// -// private func unsubscribeFromNotifications() { -// NSNotificationCenter.defaultCenter().removeObserver(self) -// } -// -// func networkAvailabilityChanged(notification: NSNotification) { -// dispatch_async(dispatch_get_main_queue(), { -// self.setupModeLabel() -// }) -// } + private func subscribeForNotifications() { + NSNotificationCenter.defaultCenter().addObserver(self, + selector:#selector(regattaControllerModeChanged), + name:RegattaController.NotificationType.ModeChanged, + object: nil + ) + } + + private func unsubscribeFromNotifications() { + NSNotificationCenter.defaultCenter().removeObserver(self) + } + + func regattaControllerModeChanged(notification: NSNotification) { + dispatch_async(dispatch_get_main_queue(), { + guard let mode = notification.userInfo?[RegattaController.UserInfo.Mode] as? RegattaController.Mode else { return } + self.setupModeLabel(mode) + }) + } } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/Regatta.swift b/ios/SAPTracker/src/xcode/SAPTracker/Regatta.swift index 7de3a0439b8..b130cbc6a73 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/Regatta.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/Regatta.swift @@ -12,6 +12,12 @@ import CoreData @objc(Regatta) class Regatta: NSManagedObject { + func updateWirhRegattaData(regattaData: RegattaData) { + serverURL = regattaData.serverURL + teamImageURL = regattaData.teamImageURL + teamImageRetry = false + } + func eventURL() -> NSURL? { return NSURL(string: "\(serverURL)/gwt/Home.html?navigationTab=Regattas#EventPlace:eventId=\(event.eventID)") } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/RegattaController.swift b/ios/SAPTracker/src/xcode/SAPTracker/RegattaController.swift new file mode 100644 index 00000000000..1c3e6da5d9e --- /dev/null +++ b/ios/SAPTracker/src/xcode/SAPTracker/RegattaController.swift @@ -0,0 +1,202 @@ +// +// RegattaController.swift +// SAPTracker +// +// Created by Raimund Wege on 05.07.16. +// Copyright © 2016 com.sap.sailing. All rights reserved. +// + +import UIKit + +@objc protocol RegattaControllerDelegate { + + func showRegattaAlert(regattaController: RegattaController, alertController: UIAlertController) + + optional func regattaControllerDidUpdate(regattaController: RegattaController) + +// optional func checkInDidStart(checkInController: CheckInController) +// optional func checkInDidEnd(checkInController: CheckInController, withSuccess succeed: Bool) + +} + +class RegattaController: NSObject { + + struct NotificationType { + static let ModeChanged = "RegattaController.ModeChanged" + } + + struct UserInfo { + static let Mode = "Mode" + } + + enum Mode: String { + case BatterySaving = "Battery Saving" + case Error = "Error" + case Online = "Online" + case Offline = "Offline" + var description: String { + switch self { + case .BatterySaving: return NSLocalizedString("Battery Saving", comment: "") + case .Error: return NSLocalizedString("Error", comment: "") + case .Offline: return NSLocalizedString("Offline", comment: "") + case .Online: return NSLocalizedString("Online", comment: "") + } + } + } + + private struct SendingInterval { + static let Normal: NSTimeInterval = 3 + static let BatterySaving: NSTimeInterval = 30 + } + + let regatta: Regatta + + var delegate: RegattaControllerDelegate? + + private (set) var isTracking: Bool = false + + init(regatta: Regatta) { + self.regatta = regatta + super.init() + } + + // MARK: - Notifications + + private func subscribeForNotifications() { + NSNotificationCenter.defaultCenter().addObserver(self, + selector:#selector(locationManagerUpdated(_:)), + name:LocationManager.NotificationType.Updated, + object: nil + ) + } + + private func unsubscribeFromNotifications() { + NSNotificationCenter.defaultCenter().removeObserver(self) + } + + func locationManagerUpdated(notification: NSNotification) { + dispatch_async(dispatch_get_main_queue(), { + guard self.isTracking else { return } + guard let locationData = notification.userInfo?[LocationManager.UserInfo.LocationData] as? LocationData else { return } + guard locationData.isValid else { return } + let gpsFix = CoreDataManager.sharedManager.newGPSFix(self.regatta) + gpsFix.updateWithLocationData(locationData) + CoreDataManager.sharedManager.saveContext() + }) + } + + // MARK: - Update + + func update() { + SVProgressHUD.show() + let regattaData = RegattaData(serverURL: regatta.serverURL, + eventID: regatta.event.eventID, + leaderboardName: regatta.leaderboard.name, + competitorID: regatta.competitor.competitorID + ) + requestManager.getRegattaData(regattaData, + success: { (regattaData) in self.updateSuccess(regattaData) }, + failure: { (title, error) in self.updateFailure() } + ) + } + + func updateSuccess(regattaData: RegattaData) { + regatta.event.updateWithEventData(regattaData.eventData) + regatta.leaderboard.updateWithLeaderboardData(regattaData.leaderboardData) + regatta.competitor.updateWithCompetitorData(regattaData.competitorData) + CoreDataManager.sharedManager.saveContext() + SVProgressHUD.popActivity() + updateFinished() + } + + func updateFailure() { + updateFinished() + } + + func updateFinished() { + SVProgressHUD.popActivity() + } + + // MARK: - Methods + + func startTracking() -> Bool { + isTracking = false + do { + try LocationManager.sharedManager.startTracking() + isTracking = true + } catch let error as LocationManager.LocationManagerError { + let alertController = UIAlertController(title: error.description, message: nil, preferredStyle: .Alert) + let cancelTitle = NSLocalizedString("Cancel", comment: "") + let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel, handler: nil) + alertController.addAction(cancelAction) + delegate?.showRegattaAlert(self, alertController: alertController) + } catch { + print("Unknown error") + } + + + isTracking = true + sendGPSFixes() + return isTracking + } + + func stopTracking() { + isTracking = false + } + + func sendGPSFixes() { + var gpsFixes = [GPSFix]() + if regatta.gpsFixes != nil { + regatta.gpsFixes!.forEach { (gpsFix) in gpsFixes.append(gpsFix as! GPSFix) } + } + if gpsFixes.count > 0 { + print("\(gpsFixes.count) GPS fixes will be sent") + requestManager.postGPSFixes(gpsFixes, + success: { (operation, responseObject) in self.sendGPSFixesSuccess(gpsFixes) }, + failure: { (operation, error) in self.sendGPSFixesFailure(error) }) + } else { + print("No GPS fixes available") + sendGPSFixesFinished() + } + } + + private func sendGPSFixesSuccess(gpsFixes: [GPSFix]!) { + print(NSThread.isMainThread) + dispatch_async(dispatch_get_main_queue(), { + print("sending \(gpsFixes.count) GPS fixes was successful") + CoreDataManager.sharedManager.deleteGPSFixes(gpsFixes) + CoreDataManager.sharedManager.saveContext() + self.sendGPSFixesFinished() + }) + } + + private func sendGPSFixesFailure(error: AnyObject) { + print(NSThread.isMainThread) + dispatch_async(dispatch_get_main_queue(), { + print("sending GPS fixes failed for reason: \(error)") + self.sendGPSFixesFinished() + }) + } + + private func sendGPSFixesFinished() { + if isTracking { + let delay = sendingPeriod + print("sending next GPS fixes in \(delay) seconds") + performSelector(#selector(RegattaController.sendGPSFixes), withObject: nil, afterDelay: delay) + } else { + print("sending GPS fixes stopped") + } + } + + // MARK: - Helper + + var sendingPeriod: NSTimeInterval { get { return BatteryManager.sharedManager.batterySaving ? SendingInterval.BatterySaving : SendingInterval.Normal } } + + // MARK: - Properties + + lazy var requestManager: RequestManager = { + let requestManager = RequestManager(baseURLString: self.regatta.serverURL) + return requestManager + }() + +} diff --git a/ios/SAPTracker/src/xcode/SAPTracker/CheckInData.swift b/ios/SAPTracker/src/xcode/SAPTracker/RegattaData.swift similarity index 51% rename from ios/SAPTracker/src/xcode/SAPTracker/CheckInData.swift rename to ios/SAPTracker/src/xcode/SAPTracker/RegattaData.swift index f2020aa5876..acd4aa5ec3f 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/CheckInData.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/RegattaData.swift @@ -1,5 +1,5 @@ // -// CheckInData.swift +// RegattaData.swift // SAPTracker // // Created by Raimund Wege on 25.05.16. @@ -8,7 +8,7 @@ import Foundation -public class CheckInData: NSObject { +public class RegattaData: NSObject { private struct ItemNames { static let EventID = "event_id" @@ -16,15 +16,28 @@ public class CheckInData: NSObject { static let CompetitorID = "competitor_id" } - public let serverURL: String - public let eventID: String - public let leaderboardName: String - public let competitorID: String + let serverURL: String + let eventID: String + let leaderboardName: String + let competitorID: String - init(serverURL: String = "", - eventID: String = "", - leaderboardName: String = "", - competitorID: String = "") + var eventData = EventData() + var leaderboardData = LeaderboardData() + var competitorData = CompetitorData() + var teamImageURL: String? + + override init() { + serverURL = "" + eventID = "" + leaderboardName = "" + competitorID = "" + super.init() + } + + init(serverURL: String, + eventID: String, + leaderboardName: String, + competitorID: String) { self.serverURL = serverURL self.eventID = eventID @@ -33,6 +46,14 @@ public class CheckInData: NSObject { super.init() } + init(regatta: Regatta) { + serverURL = regatta.serverURL + eventID = regatta.event.eventID + competitorID = regatta.competitor.competitorID + leaderboardName = regatta.leaderboard.name + super.init() + } + convenience init?(url: NSURL) { guard let host = url.host else { return nil } guard let components = NSURLComponents(string: url.absoluteString) else { return nil } @@ -45,9 +66,9 @@ public class CheckInData: NSObject { let queryItems = components.queryItems // Get check-in items - guard let eventID = CheckInData.queryItemValue(queryItems, itemName: CheckInData.ItemNames.EventID) else { return nil } - guard let leaderboardName = CheckInData.queryItemValue(queryItems, itemName: CheckInData.ItemNames.LeaderboardName) else { return nil } - guard let competitorID = CheckInData.queryItemValue(queryItems, itemName: CheckInData.ItemNames.CompetitorID) else { return nil } + guard let eventID = RegattaData.queryItemValue(queryItems, itemName: ItemNames.EventID) else { return nil } + guard let leaderboardName = RegattaData.queryItemValue(queryItems, itemName: ItemNames.LeaderboardName) else { return nil } + guard let competitorID = RegattaData.queryItemValue(queryItems, itemName: ItemNames.CompetitorID) else { return nil } // Init with values self.init(serverURL: serverURL, @@ -63,9 +84,20 @@ public class CheckInData: NSObject { self.init(url: url) } + // Properties + + var welcomeString: String { + get { + return String(format:NSLocalizedString("Hello %@. Welcome to %@. You are registered as %@.", comment: ""), + competitorData.name, + leaderboardData.name, + competitorData.sailID) + } + } + // MARK: - Helper - private class func queryItemValue(queryItems: [NSURLQueryItem]?, itemName: String) -> String? { + class private func queryItemValue(queryItems: [NSURLQueryItem]?, itemName: String) -> String? { return queryItems?.filter({(item) -> Bool in item.name == itemName}).first?.value } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/RegattaViewController.swift b/ios/SAPTracker/src/xcode/SAPTracker/RegattaViewController.swift index 167a688ff58..fc590c78ddb 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/RegattaViewController.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/RegattaViewController.swift @@ -7,8 +7,6 @@ // import Foundation -import CoreLocation -import Darwin class RegattaViewController : UIViewController, UINavigationControllerDelegate { @@ -51,6 +49,9 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate { setupNavigationBar() setupImageSourceTypes() setupTeamImage() + + // Test + regattaController.update() } // MARK: - Setups @@ -73,7 +74,8 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate { target: self, selector: #selector(RegattaViewController.refreshCountdown), userInfo: nil, - repeats: true) + repeats: true + ) refreshCountdown() } @@ -185,6 +187,9 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate { @IBAction func showMenuActionSheet(sender: AnyObject) { let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet) + if let popoverController = alertController.popoverPresentationController { + popoverController.barButtonItem = sender as? UIBarButtonItem + } let checkOutTitle = NSLocalizedString("Check-Out", comment: "") let checkOutAction = UIAlertAction(title: checkOutTitle, style: .Default) { (action) in self.showCheckOutAlertController() @@ -207,21 +212,35 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate { } @IBAction func startTrackingButtonTapped(sender: AnyObject) { - do { - try LocationManager.sharedManager.startTracking() + if regattaController.startTracking() { performSegueWithIdentifier("Tracking", sender: sender) - } catch let error as LocationManager.LocationManagerError { - let alertController = UIAlertController(title: error.description, message: nil, preferredStyle: .Alert) - let cancelTitle = NSLocalizedString("Cancel", comment: "") - let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel, handler: nil) - alertController.addAction(cancelAction) - presentViewController(alertController, animated: true, completion: nil) - } catch { - print("Unknown error") } } - // MARK: - Image picker + // MARK: - Alerts + + private func showCheckOutAlertController() { + let alertTitle = NSLocalizedString("Check-out of Regatta?", comment: "") + let alertController = UIAlertController(title: alertTitle, message: nil, preferredStyle: .Alert) + let okTitle = NSLocalizedString("OK", comment: "") + let okAction = UIAlertAction(title: okTitle, style: .Default) { (action) in self.preformCheckOut() } + let cancelTitle = NSLocalizedString("Cancel", comment: "") + let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel, handler: nil) + alertController.addAction(okAction) + alertController.addAction(cancelAction) + presentViewController(alertController, animated: true, completion: nil) + } + + private func preformCheckOut() { + requestManager.postCheckOut(regatta.leaderboard.name, + competitorId: regatta.competitor.competitorID, + success: { (operation, responseObject) in }, + failure: { (operation, error) in + }) + CoreDataManager.sharedManager.deleteRegatta(regatta) + CoreDataManager.sharedManager.saveContext() + navigationController!.popViewControllerAnimated(true) + } func showImageAlertController() { if sourceTypes.count == 1 { @@ -245,41 +264,22 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate { } } - // MARK: - Check-out - - func showCheckOutAlertController() { - let alertTitle = NSLocalizedString("Check-out of Regatta?", comment: "") - let alertController = UIAlertController(title: alertTitle, message: nil, preferredStyle: .Alert) - let okTitle = NSLocalizedString("OK", comment: "") - let okAction = UIAlertAction(title: okTitle, style: .Default) { (action) in self.preformCheckOut() } - let cancelTitle = NSLocalizedString("Cancel", comment: "") - let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel, handler: nil) - alertController.addAction(okAction) - alertController.addAction(cancelAction) - presentViewController(alertController, animated: true, completion: nil) - } - - func preformCheckOut() { - requestManager.postCheckOut(regatta.leaderboard.name, - competitorId: regatta.competitor.competitorID, - success: { (operation, responseObject) in }, - failure: { (operation, error) in - }) - CoreDataManager.sharedManager.deleteRegatta(regatta!) - CoreDataManager.sharedManager.saveContext() - navigationController!.popViewControllerAnimated(true) - } - // MARK: - Segue override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if (segue.identifier == "Tracking") { - let nc = segue.destinationViewController as! UINavigationController - let vc = nc.viewControllers[0] as! TrackingViewController - vc.regatta = regatta + let trackingNC = segue.destinationViewController as! UINavigationController + let trackingVC = trackingNC.viewControllers[0] as! TrackingViewController + trackingVC.regatta = regatta } } + // MARK: - Properties + + lazy var regattaController: RegattaController = { + return RegattaController(regatta: self.regatta) + }() + } // MARK: - UIImagePickerControllerDelegate @@ -344,4 +344,14 @@ extension RegattaViewController: UIImagePickerControllerDelegate { setupTeamImage() } -} \ No newline at end of file +} + +// MARK: - RegattaControllerDelegate + +extension RegattaViewController: RegattaControllerDelegate { + + func showRegattaAlert(regattaController: RegattaController, alertController: UIAlertController) { + presentViewController(alertController, animated: true, completion: nil) + } + +} diff --git a/ios/SAPTracker/src/xcode/SAPTracker/RequestManager.swift b/ios/SAPTracker/src/xcode/SAPTracker/RequestManager.swift index d1020e7b837..fa30450c0f1 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/RequestManager.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/RequestManager.swift @@ -10,7 +10,7 @@ import UIKit class RequestManager: NSObject { - + private let basePathString = "/sailingserver/api/v1" private enum BodyKeys { @@ -50,37 +50,142 @@ class RequestManager: NSObject { super.init() } + // MARK: - Regatta + + func getRegattaData(regattaData: RegattaData, + success: (RegattaData) -> Void, + failure: (String, NSError) -> Void) + { + getEventData(regattaData, success: success, failure: failure) + } + + func getEventData(regattaData: RegattaData, + success: (RegattaData) -> Void, + failure: (String, NSError) -> Void) + { + getEvent(regattaData.eventID, + success: { (data) in self.getEventDataSuccess(data, regattaData: regattaData, success: success, failure: failure) }, + failure: { (title, error) in failure(title, error) } + ) + } + + func getEventDataSuccess(eventData: EventData, + regattaData: RegattaData, + success: (RegattaData) -> Void, + failure: (String, NSError) -> Void) + { + regattaData.eventData = eventData + getLeaderboardData(regattaData, success: success, failure: failure) + } + + func getLeaderboardData(regattaData: RegattaData, + success: (RegattaData) -> Void, + failure: (String, NSError) -> Void) + { + getLeaderboard(regattaData.leaderboardName, + success: { (data) in self.getLeaderboardDataSuccess(data, regattaData: regattaData, success: success, failure: failure) }, + failure: { (title, error) in failure(title, error) } + ) + } + + func getLeaderboardDataSuccess(leaderboardData: LeaderboardData, + regattaData: RegattaData, + success: (RegattaData) -> Void, + failure: (String, NSError) -> Void) + { + regattaData.leaderboardData = leaderboardData + getCompetitorData(regattaData, success: success, failure: failure) + } + + func getCompetitorData(regattaData: RegattaData, + success: (RegattaData) -> Void, + failure: (String, NSError) -> Void) + { + getCompetitor(regattaData.competitorID, + success: { (data) in self.getCompetitorDataSuccess(data, regattaData: regattaData, success: success, failure: failure) }, + failure: { (title, error) in failure(title, error) } + ) + } + + func getCompetitorDataSuccess(competitorData: CompetitorData, + regattaData: RegattaData, + success: (RegattaData) -> Void, + failure: (String, NSError) -> Void) + { + regattaData.competitorData = competitorData + getTeamImageURL(regattaData.competitorID, result: { (imageURL) in + regattaData.teamImageURL = imageURL + success(regattaData) + }) + } + // MARK: - Event - func getEvent(eventID: String!, - success: (AFHTTPRequestOperation!, AnyObject!) -> Void, - failure: (AFHTTPRequestOperation!, AnyObject!) -> Void) + func getEvent(eventID: String, + success: (EventData) -> Void, + failure: (String, NSError) -> Void) { - let encodedEventID = eventID.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLPathAllowedCharacterSet()) ?? "" + let encodedEventID = eventID.stringByAddingPercentEncodingWithAllowedCharacters(.URLPathAllowedCharacterSet()) ?? "" let urlString = "\(basePathString)/events/\(encodedEventID)" - manager.GET(urlString, parameters: nil, success: success, failure: failure) + manager.GET(urlString, + parameters: nil, + success: { (requestOperation, responseObject) in self.getEventSuccess(responseObject, success: success) }, + failure: { (requestOperation, error) in self.getEventFailure(eventID, error: error, failure: failure) } + ) + } + + func getEventSuccess(responseObject: AnyObject, success: (EventData) -> Void) { + success(EventData(dictionary: responseObject as? [String: AnyObject])) + } + + func getEventFailure(eventID: String, error: NSError, failure: (String, NSError) -> Void) -> Void { + failure(String(format: NSLocalizedString("Couldn't get event %@", comment: ""), eventID), error) } // MARK: - Leaderboard - func getLeaderboard(leaderboardName: String!, - success: (AFHTTPRequestOperation!, AnyObject!) -> Void, - failure: (AFHTTPRequestOperation!, AnyObject!) -> Void) + func getLeaderboard(leaderboardName: String, + success: (LeaderboardData) -> Void, + failure: (String, NSError) -> Void) { - let encodedLeaderboardName = leaderboardName.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLPathAllowedCharacterSet()) ?? "" + let encodedLeaderboardName = leaderboardName.stringByAddingPercentEncodingWithAllowedCharacters(.URLPathAllowedCharacterSet()) ?? "" let urlString = "\(basePathString)/leaderboards/\(encodedLeaderboardName)" - manager.GET(urlString, parameters: nil, success: success, failure: failure) + manager.GET(urlString, + parameters: nil, + success: { (requestOperation, responseObject) in self.getLeaderboardSuccess(responseObject, success: success) }, + failure: { (requestOperation, error) in self.getLeaderboardFailure(leaderboardName, error: error, failure: failure) } + ) + } + + func getLeaderboardSuccess(responseObject: AnyObject, success: (LeaderboardData) -> Void) { + success(LeaderboardData(dictionary: responseObject as? [String: AnyObject])) + } + + func getLeaderboardFailure(leaderboardName: String, error: NSError, failure: (String, NSError) -> Void) { + failure(String(format: NSLocalizedString("Couldn't get leader board %@", comment: ""), leaderboardName), error) } // MARK: - Competitor - func getCompetitor(competitorID: String!, - success: (AFHTTPRequestOperation!, AnyObject!) -> Void, - failure: (AFHTTPRequestOperation!, AnyObject!) -> Void) + func getCompetitor(competitorID: String, + success: (CompetitorData) -> Void, + failure: (String, NSError) -> Void) { let encodedCompetitorID = competitorID.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLPathAllowedCharacterSet()) ?? "" let urlString = "\(basePathString)/competitors/\(encodedCompetitorID)" - manager.GET(urlString, parameters: nil, success: success, failure: failure) + manager.GET(urlString, + parameters: nil, + success: { (requestOperation, responseObject) in self.getCompetitorSuccess(responseObject, success: success) }, + failure: { (requestOperation, error) in self.getCompetitorFailure(competitorID, error: error, failure: failure) } + ) + } + + func getCompetitorSuccess(responseObject: AnyObject, success: (CompetitorData) -> Void) { + success(CompetitorData(dictionary: responseObject as? [String: AnyObject])) + } + + func getCompetitorFailure(competitorID: String, error: NSError, failure: (String, NSError) -> Void) { + failure(String(format: NSLocalizedString("Couldn't get competitor %@", comment: ""), competitorID), error) } // MARK: - Team diff --git a/ios/SAPTracker/src/xcode/SAPTracker/ScanViewController.swift b/ios/SAPTracker/src/xcode/SAPTracker/ScanViewController.swift index b75d4275b61..bd4282d3ef5 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/ScanViewController.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/ScanViewController.swift @@ -14,15 +14,12 @@ class ScanViewController: UIViewController { @IBOutlet weak var previewView: UIView! @IBOutlet weak var targetImageView: UIImageView! - private let checkInController = CheckInController() - private var session: AVCaptureSession! private var output: AVCaptureMetadataOutput! private var previewLayer: AVCaptureVideoPreviewLayer! override func viewDidLoad() { super.viewDidLoad() - setupCheckInController() setupSession() } @@ -31,12 +28,20 @@ class ScanViewController: UIViewController { startScanning() } - // MARK: - Setups - - private func setupCheckInController() { - checkInController.delegate = self + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + layoutPreviewLayer() } + // MARK: - Layouts + + private func layoutPreviewLayer() { + previewLayer.frame = previewView.bounds + previewLayer.position = CGPointMake(CGRectGetMidX(previewView.bounds), CGRectGetMidY(previewView.bounds)) + } + + // MARK: - Setups + private func setupSession() { session = AVCaptureSession() output = AVCaptureMetadataOutput() @@ -54,6 +59,7 @@ class ScanViewController: UIViewController { output.metadataObjectTypes = [AVMetadataObjectTypeQRCode] previewLayer = AVCaptureVideoPreviewLayer(session: self.session) previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill + previewLayer.connection.videoOrientation = videoOrientation(forInterfaceOrientation: UIApplication.sharedApplication().statusBarOrientation) previewLayer.frame = previewView.bounds previewLayer.position = CGPointMake(CGRectGetMidX(previewView.bounds), CGRectGetMidY(previewView.bounds)) previewView.layer.addSublayer(previewLayer) @@ -65,13 +71,7 @@ class ScanViewController: UIViewController { // MARK: - UIViewControllerDelegate override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { - if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft { - previewLayer!.connection.videoOrientation = AVCaptureVideoOrientation.LandscapeRight - } else if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight { - previewLayer!.connection.videoOrientation = AVCaptureVideoOrientation.LandscapeLeft - } else { - previewLayer!.connection.videoOrientation = AVCaptureVideoOrientation.Portrait - } + previewLayer.connection.videoOrientation = videoOrientation(forInterfaceOrientation: toInterfaceOrientation) } // MARK: - Scanning @@ -90,6 +90,26 @@ class ScanViewController: UIViewController { targetImageView.image = UIImage(named: "scan_green") } + // MARK: - Properties + + lazy var checkInController: CheckInController = { + let checkInController = CheckInController() + checkInController.delegate = self + return checkInController + }() + + // MARK: - Helper + + private func videoOrientation(forInterfaceOrientation orientation: UIInterfaceOrientation) -> AVCaptureVideoOrientation { + switch orientation { + case .LandscapeLeft: return .LandscapeLeft + case .LandscapeRight: return .LandscapeRight + case .Portrait: return .Portrait + case .PortraitUpsideDown: return .PortraitUpsideDown + case .Unknown: return .Portrait + } + } + } // MARK: - CheckInControllerDelegate @@ -120,9 +140,9 @@ extension ScanViewController: AVCaptureMetadataOutputObjectsDelegate { { if metadataObjects.count > 0 { let metadataObject: AVMetadataMachineReadableCodeObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject - if let checkInData = CheckInData(urlString: metadataObject.stringValue) { + if let regattaData = RegattaData(urlString: metadataObject.stringValue) { stopScanning() - checkInController.startCheckIn(checkInData) + checkInController.checkIn(regattaData) } else { let alertTitle = NSLocalizedString("Incorrect QR Code", comment: "") let alertController = UIAlertController(title: alertTitle, message: "", preferredStyle: .Alert) diff --git a/ios/SAPTracker/src/xcode/SAPTracker/SendGPSFixesController.swift b/ios/SAPTracker/src/xcode/SAPTracker/SendGPSFixesController.swift deleted file mode 100644 index 91198f3035d..00000000000 --- a/ios/SAPTracker/src/xcode/SAPTracker/SendGPSFixesController.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// SendGPSFixesController.swift -// SAPTracker -// -// Created by Raimund Wege on 29.06.16. -// Copyright © 2016 com.sap.sailing. All rights reserved. -// - -import UIKit - -class SendGPSFixesController: NSObject { - - private struct SendingInterval { - static let Normal: NSTimeInterval = 3 - static let BatterySaving: NSTimeInterval = 30 - } - - private let regatta: Regatta! - private let requestManager: RequestManager! - - private var isRunning: Bool = false - - init(regatta: Regatta) { - self.regatta = regatta - requestManager = RequestManager(baseURLString: regatta.serverURL) - super.init() - } - - deinit { - unsubscribeFromNotifications() - } - - // MARK: - Notifications - - private func subscribeForNotifications() { - NSNotificationCenter.defaultCenter().addObserver(self, - selector:#selector(locationManagerUpdated(_:)), - name:LocationManager.NotificationType.LocationManagerUpdated, - object: nil) - } - - private func unsubscribeFromNotifications() { - NSNotificationCenter.defaultCenter().removeObserver(self) - } - - func locationManagerUpdated(notification: NSNotification) { - dispatch_async(dispatch_get_main_queue(), { - if let userInfo = notification.userInfo { - if userInfo[LocationManager.UserInfo.IsValid] as? Bool ?? false { - let gpsFix = CoreDataManager.sharedManager.newGPSFix(self.regatta) - gpsFix.course = userInfo[LocationManager.UserInfo.Course] as! Double - gpsFix.latitude = userInfo[LocationManager.UserInfo.Latitude] as! Double - gpsFix.longitude = userInfo[LocationManager.UserInfo.Longitude] as! Double - gpsFix.speed = userInfo[LocationManager.UserInfo.Speed] as! Double - gpsFix.timestamp = round(userInfo[LocationManager.UserInfo.Timestamp] as! Double * 1000) - CoreDataManager.sharedManager.saveContext() - } - } - }) - } - - // MARK: - Methods - - func startSending() { - isRunning = true - sendGPSFixes() - } - - func stopSending() { - isRunning = false - } - - func sendGPSFixes() { - var gpsFixes = [GPSFix]() - if regatta.gpsFixes != nil { - regatta.gpsFixes!.forEach { (gpsFix) in gpsFixes.append(gpsFix as! GPSFix) } - } - if gpsFixes.count > 0 { - log("\(gpsFixes.count) GPS fixes will be sent") - requestManager.postGPSFixes(gpsFixes, - success: { (operation, responseObject) in self.sendGPSFixesSuccess(gpsFixes) }, - failure: { (operation, error) in self.sendGPSFixesFailure(error) }) - } else { - log("No GPS fixes available") - sendGPSFixesFinished() - } - } - - private func sendGPSFixesSuccess(gpsFixes: [GPSFix]!) { - print(NSThread.isMainThread) - dispatch_async(dispatch_get_main_queue(), { - self.log("sending \(gpsFixes.count) GPS fixes was successful") - CoreDataManager.sharedManager.deleteGPSFixes(gpsFixes) - CoreDataManager.sharedManager.saveContext() - self.sendGPSFixesFinished() - }) - } - - private func sendGPSFixesFailure(error: AnyObject) { - print(NSThread.isMainThread) - dispatch_async(dispatch_get_main_queue(), { - self.log("sending GPS fixes failed for reason: \(error)") - self.sendGPSFixesFinished() - }) - } - - private func sendGPSFixesFinished() { - if isRunning { - let delay = sendingPeriod - log("sending next GPS fixes in \(delay) seconds") - performSelector(#selector(SendGPSFixesController.sendGPSFixes), withObject: nil, afterDelay: delay) - } else { - log("sending GPS fixes stopped") - } - } - - // MARK: - Helper - - private var sendingPeriod: NSTimeInterval { - get { - return BatteryManager.sharedManager.batterySaving ? SendingInterval.BatterySaving : SendingInterval.Normal - } - } - - private func log(message: String) { - print("[GPSFixesController] \(message)") - } - -} diff --git a/ios/SAPTracker/src/xcode/SAPTracker/SpeedViewController.swift b/ios/SAPTracker/src/xcode/SAPTracker/SpeedViewController.swift index 5967ea6e168..2f0f00934df 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/SpeedViewController.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/SpeedViewController.swift @@ -40,8 +40,14 @@ class SpeedViewController: UIViewController { private func subscribeForNotifications() { NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(locationManagerUpdated(_:)), - name:LocationManager.NotificationType.LocationManagerUpdated, - object: nil) + name:LocationManager.NotificationType.Updated, + object: nil + ) + NSNotificationCenter.defaultCenter().addObserver(self, + selector:#selector(locationManagerFailed(_:)), + name:LocationManager.NotificationType.Failed, + object: nil + ) } private func unsubscribeFromNotifications() { @@ -50,8 +56,15 @@ class SpeedViewController: UIViewController { func locationManagerUpdated(notification: NSNotification) { dispatch_async(dispatch_get_main_queue(), { - self.setupSpeedLabel(notification.userInfo![LocationManager.UserInfo.Speed] as! Double) + guard let locationData = notification.userInfo?[LocationManager.UserInfo.LocationData] as? LocationData else { return } + self.setupSpeedLabel(locationData.location.speed) }) } + func locationManagerFailed(notification: NSNotification) { + dispatch_async(dispatch_get_main_queue(), { + self.setupSpeedLabel(-1.0) + }) + } + } \ No newline at end of file diff --git a/ios/SAPTracker/src/xcode/SAPTracker/StatusTrackingTableViewCell.swift b/ios/SAPTracker/src/xcode/SAPTracker/StatusTrackingTableViewCell.swift index dd7cbc8ec5d..7424ac28d7e 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/StatusTrackingTableViewCell.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/StatusTrackingTableViewCell.swift @@ -35,12 +35,14 @@ class StatusTrackingTableViewCell: UITableViewCell { private func subscribeForNotifications() { NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(locationManagerUpdated(_:)), - name:LocationManager.NotificationType.LocationManagerUpdated, - object: nil) + name:LocationManager.NotificationType.Updated, + object: nil + ) NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(locationManagerFailed(_:)), - name:LocationManager.NotificationType.LocationManagerFailed, - object: nil) + name:LocationManager.NotificationType.Failed, + object: nil + ) } private func unsubscribeFromNotifications() { diff --git a/ios/SAPTracker/src/xcode/SAPTracker/TimerViewController.swift b/ios/SAPTracker/src/xcode/SAPTracker/TimerViewController.swift index 218c0685e35..260b751ead0 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/TimerViewController.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/TimerViewController.swift @@ -33,7 +33,8 @@ class TimerViewController: UIViewController { target: self, selector: #selector(tick), userInfo: nil, - repeats: true) + repeats: true + ) NSRunLoop.currentRunLoop().addTimer(timer, forMode:NSRunLoopCommonModes) } diff --git a/ios/SAPTracker/src/xcode/SAPTracker/TrackingViewController.swift b/ios/SAPTracker/src/xcode/SAPTracker/TrackingViewController.swift index ffc3e440f7e..82f2e3e77d7 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/TrackingViewController.swift +++ b/ios/SAPTracker/src/xcode/SAPTracker/TrackingViewController.swift @@ -10,7 +10,8 @@ import Foundation class TrackingViewController : UIViewController { - var regatta: Regatta? + var regatta: Regatta! + var regattaController: RegattaController! @IBOutlet weak var tableView: UITableView! @IBOutlet weak var tableViewHeight: NSLayoutConstraint!