More needed refactoring steps

This commit is contained in:
Raimund Wege committed 2016-07-06 22:15:11 +02:00
1 parent 376bcc2d34
commit cd860fcc08
29 files changed
+805 -552

No files matched your search

@@ -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 = "<group>"; };
7F03FD3F19FA4D7400FA1327 /* bridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bridge.h; sourceTree = "<group>"; };
7F0658FC19F7D6700077FF95 /* ScanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ScanViewController.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
7F0658FE19F7EE910077FF95 /* CheckInData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CheckInData.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
7F0658FE19F7EE910077FF95 /* RegattaData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = RegattaData.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
7F14A0041A13B9A6001C1ECB /* _abkhazia.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = _abkhazia.png; sourceTree = "<group>"; };
7F14A0051A13B9A6001C1ECB /* _basque-country.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "_basque-country.png"; sourceTree = "<group>"; };
7F14A0061A13B9A6001C1ECB /* _british-antarctic-territory.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "_british-antarctic-territory.png"; sourceTree = "<group>"; };
@@ -700,7 +705,6 @@
C852BAAA1CF736680093B0C5 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
C8603D491C528832002B2F28 /* Acknowledgements.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Acknowledgements.markdown; sourceTree = "<group>"; };
C8739D891D21276B00A89F3C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Main.strings; sourceTree = "<group>"; };
C8739D8D1D23D53C00A89F3C /* SendGPSFixesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendGPSFixesController.swift; sourceTree = "<group>"; };
C8739D9A1D25317100A89F3C /* CoreData 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "CoreData 2.xcdatamodel"; sourceTree = "<group>"; };
C8739DFA1D2AA2A500A89F3C /* Regatta+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Regatta+CoreDataProperties.swift"; sourceTree = "<group>"; };
C8739DFB1D2AA2A500A89F3C /* Regatta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Regatta.swift; sourceTree = "<group>"; };
@@ -712,6 +716,12 @@
C8739E011D2AA2A500A89F3C /* Competitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Competitor.swift; sourceTree = "<group>"; };
C8739E021D2AA2A500A89F3C /* Event+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Event+CoreDataProperties.swift"; sourceTree = "<group>"; };
C8739E031D2AA2A500A89F3C /* Event.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = "<group>"; };
C8739E0E1D2BEE7900A89F3C /* RegattaController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegattaController.swift; sourceTree = "<group>"; };
C8739E111D2BF14F00A89F3C /* EventData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventData.swift; sourceTree = "<group>"; };
C8739E131D2BF16300A89F3C /* LeaderboardData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeaderboardData.swift; sourceTree = "<group>"; };
C8739E151D2BF17900A89F3C /* CompetitorData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompetitorData.swift; sourceTree = "<group>"; };
C8739E171D2BF2DC00A89F3C /* BaseData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseData.swift; sourceTree = "<group>"; };
C8739E1B1D2D5F1700A89F3C /* LocationData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationData.swift; sourceTree = "<group>"; };
C89C5FC41D06A289002AAAD2 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = "<group>"; };
C89C5FC91D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusTrackingTableViewCell.swift; sourceTree = "<group>"; };
C89C5FCB1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GPSAccuracyTrackingTableViewCell.swift; sourceTree = "<group>"; };
@@ -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 = "<group>";
@@ -1162,8 +1173,6 @@
C852BAA61CF5E1F40093B0C5 /* CheckIn */ = {
isa = PBXGroup;
children = (
7F0658FE19F7EE910077FF95 /* CheckInData.swift */,
7F23F0871A1A3DEF00F03F1C /* CheckInController.swift */,
);
name = CheckIn;
sourceTree = "<group>";
@@ -1176,17 +1185,11 @@
name = Preferences;
sourceTree = "<group>";
};
C8739D8A1D22CCDB00A89F3C /* GPSFixes */ = {
isa = PBXGroup;
children = (
C8739D8D1D23D53C00A89F3C /* SendGPSFixesController.swift */,
);
name = GPSFixes;
sourceTree = "<group>";
};
C8739D8B1D23C01500A89F3C /* Managers */ = {
isa = PBXGroup;
children = (
7F2C605919F160E400C32D93 /* LocationManager.swift */,
7F1B66F81A0CDCF600904A41 /* BatteryManager.swift */,
C852BAA11CF5E1EA0093B0C5 /* RequestManager.swift */,
);
name = Managers;
@@ -1200,20 +1203,11 @@
name = EULA;
sourceTree = "<group>";
};
C8739DC61D2A650E00A89F3C /* Location */ = {
isa = PBXGroup;
children = (
7F2C605919F160E400C32D93 /* LocationManager.swift */,
);
name = Location;
sourceTree = "<group>";
};
C8739DC71D2A653F00A89F3C /* Classes */ = {
isa = PBXGroup;
children = (
7F06590019F7FE750077FF95 /* CoreData */,
7F06590219F7FEA40077FF95 /* DataController */,
C8739DC61D2A650E00A89F3C /* Location */,
C8739D8B1D23C01500A89F3C /* Managers */,
C852BAA91CF736440093B0C5 /* Preferences */,
7F06590119F7FE920077FF95 /* ViewController */,
@@ -1222,6 +1216,19 @@
name = Classes;
sourceTree = "<group>";
};
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 = "<group>";
};
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;
@@ -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 ?? ""
}
}
@@ -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() {
@@ -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: - CheckIn
// MARK: - Initialize
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)
})
}
private func checkInDidEnd(withSuccess succeed: Bool) {
dispatch_async(dispatch_get_main_queue(), {
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 ""
}
}
}
@@ -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
}
}
@@ -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) } }
}
@@ -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)
})
}
@@ -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
}
}
@@ -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 } }
}
@@ -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)
})
}
@@ -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)
})
}
@@ -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)
}
}
@@ -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,22 +126,15 @@ 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)
}
}
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)
}
}
let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel, handler: nil)
alertController.addAction(settingsAction)
alertController.addAction(aboutAction)
@@ -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
}
}
@@ -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())
}
@@ -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) } }
}
@@ -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;
}
}
}
@@ -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)
}
@@ -96,50 +101,18 @@ class LocationManager: NSObject {
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;
}
}
@@ -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)
})
}
}
@@ -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)")
}
@@ -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
}()
}
@@ -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
}
@@ -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
@@ -345,3 +345,13 @@ extension RegattaViewController: UIImagePickerControllerDelegate {
}
}
// MARK: - RegattaControllerDelegate
extension RegattaViewController: RegattaControllerDelegate {
func showRegattaAlert(regattaController: RegattaController, alertController: UIAlertController) {
presentViewController(alertController, animated: true, completion: nil)
}
}
@@ -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
@@ -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)
@@ -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)")
}
}
@@ -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,7 +56,14 @@ 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)
})
}
@@ -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() {
@@ -33,7 +33,8 @@ class TimerViewController: UIViewController {
target: self,
selector: #selector(tick),
userInfo: nil,
repeats: true)
repeats: true
)
NSRunLoop.currentRunLoop().addTimer(timer, forMode:NSRunLoopCommonModes)
}
@@ -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!