More needed refactoring steps

This commit is contained in:
Raimund Wege committed 2016-07-05 15:09:18 +02:00
1 parent 00509c120b
commit 0bc7e2b115
28 files changed
+638 -435

No files matched your search

@@ -295,7 +295,7 @@
7F8B8D411A373B0200C34B88 /* SpeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8B8D401A373B0200C34B88 /* SpeedViewController.swift */; }; 7F8B8D411A373B0200C34B88 /* SpeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8B8D401A373B0200C34B88 /* SpeedViewController.swift */; };
7F8B8D431A373D4400C34B88 /* CourseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8B8D421A373D4400C34B88 /* CourseViewController.swift */; }; 7F8B8D431A373D4400C34B88 /* CourseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8B8D421A373D4400C34B88 /* CourseViewController.swift */; };
7F8CC2081A10D47A00C56D7F /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8CC2071A10D47A00C56D7F /* SettingsViewController.swift */; }; 7F8CC2081A10D47A00C56D7F /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8CC2071A10D47A00C56D7F /* SettingsViewController.swift */; };
7F950A911A35E967003C8C5C /* LeaderBoardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F950A901A35E967003C8C5C /* LeaderBoardViewController.swift */; }; 7F950A911A35E967003C8C5C /* LeaderboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F950A901A35E967003C8C5C /* LeaderboardViewController.swift */; };
7F99DE3C1A126554009B3619 /* RegattaViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F99DE3B1A126554009B3619 /* RegattaViewController.swift */; }; 7F99DE3C1A126554009B3619 /* RegattaViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F99DE3B1A126554009B3619 /* RegattaViewController.swift */; };
7FA2220B1A25E55400FD364B /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F83F17519F1574700C53328 /* CoreLocation.framework */; }; 7FA2220B1A25E55400FD364B /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F83F17519F1574700C53328 /* CoreLocation.framework */; };
7FA6551A19F6661900A1B92D /* CoreDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FA6551919F6661900A1B92D /* CoreDataManager.swift */; }; 7FA6551A19F6661900A1B92D /* CoreDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FA6551919F6661900A1B92D /* CoreDataManager.swift */; };
@@ -312,16 +312,16 @@
C852BAAB1CF736680093B0C5 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C852BAAA1CF736680093B0C5 /* Preferences.swift */; }; C852BAAB1CF736680093B0C5 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = C852BAAA1CF736680093B0C5 /* Preferences.swift */; };
C8603D511C52892A002B2F28 /* Acknowledgements.markdown in Resources */ = {isa = PBXBuildFile; fileRef = C8603D491C528832002B2F28 /* Acknowledgements.markdown */; }; C8603D511C52892A002B2F28 /* Acknowledgements.markdown in Resources */ = {isa = PBXBuildFile; fileRef = C8603D491C528832002B2F28 /* Acknowledgements.markdown */; };
C8739D8E1D23D53C00A89F3C /* SendGPSFixesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739D8D1D23D53C00A89F3C /* SendGPSFixesController.swift */; }; C8739D8E1D23D53C00A89F3C /* SendGPSFixesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739D8D1D23D53C00A89F3C /* SendGPSFixesController.swift */; };
C8739DAF1D2539A900A89F3C /* CheckIn+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DA51D2539A900A89F3C /* CheckIn+CoreDataProperties.swift */; }; C8739E041D2AA2A500A89F3C /* Regatta+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DFA1D2AA2A500A89F3C /* Regatta+CoreDataProperties.swift */; };
C8739DB01D2539A900A89F3C /* CheckIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DA61D2539A900A89F3C /* CheckIn.swift */; }; C8739E051D2AA2A500A89F3C /* Regatta.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DFB1D2AA2A500A89F3C /* Regatta.swift */; };
C8739DB31D2539A900A89F3C /* Event+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DA91D2539A900A89F3C /* Event+CoreDataProperties.swift */; }; C8739E061D2AA2A500A89F3C /* GPSFix+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DFC1D2AA2A500A89F3C /* GPSFix+CoreDataProperties.swift */; };
C8739DB41D2539A900A89F3C /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DAA1D2539A900A89F3C /* Event.swift */; }; C8739E071D2AA2A500A89F3C /* GPSFix.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DFD1D2AA2A500A89F3C /* GPSFix.swift */; };
C8739DB51D2539A900A89F3C /* Competitor+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DAB1D2539A900A89F3C /* Competitor+CoreDataProperties.swift */; }; C8739E081D2AA2A500A89F3C /* Leaderboard+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DFE1D2AA2A500A89F3C /* Leaderboard+CoreDataProperties.swift */; };
C8739DB61D2539A900A89F3C /* Competitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DAC1D2539A900A89F3C /* Competitor.swift */; }; C8739E091D2AA2A500A89F3C /* Leaderboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DFF1D2AA2A500A89F3C /* Leaderboard.swift */; };
C8739DB71D2539A900A89F3C /* GPSFix+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DAD1D2539A900A89F3C /* GPSFix+CoreDataProperties.swift */; }; C8739E0A1D2AA2A500A89F3C /* Competitor+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E001D2AA2A500A89F3C /* Competitor+CoreDataProperties.swift */; };
C8739DB81D2539A900A89F3C /* GPSFix.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DAE1D2539A900A89F3C /* GPSFix.swift */; }; C8739E0B1D2AA2A500A89F3C /* Competitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E011D2AA2A500A89F3C /* Competitor.swift */; };
C8739DBB1D25409700A89F3C /* Leaderboard+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DB91D25409700A89F3C /* Leaderboard+CoreDataProperties.swift */; }; C8739E0C1D2AA2A500A89F3C /* Event+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E021D2AA2A500A89F3C /* Event+CoreDataProperties.swift */; };
C8739DBC1D25409700A89F3C /* Leaderboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739DBA1D25409700A89F3C /* Leaderboard.swift */; }; C8739E0D1D2AA2A500A89F3C /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8739E031D2AA2A500A89F3C /* Event.swift */; };
C89C5FC51D06A289002AAAD2 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89C5FC41D06A289002AAAD2 /* GradientView.swift */; }; C89C5FC51D06A289002AAAD2 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89C5FC41D06A289002AAAD2 /* GradientView.swift */; };
C89C5FCA1D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89C5FC91D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift */; }; C89C5FCA1D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89C5FC91D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift */; };
C89C5FCC1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89C5FCB1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift */; }; C89C5FCC1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89C5FCB1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift */; };
@@ -683,7 +683,7 @@
7F8B8D401A373B0200C34B88 /* SpeedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpeedViewController.swift; sourceTree = "<group>"; }; 7F8B8D401A373B0200C34B88 /* SpeedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpeedViewController.swift; sourceTree = "<group>"; };
7F8B8D421A373D4400C34B88 /* CourseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseViewController.swift; sourceTree = "<group>"; }; 7F8B8D421A373D4400C34B88 /* CourseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseViewController.swift; sourceTree = "<group>"; };
7F8CC2071A10D47A00C56D7F /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; }; 7F8CC2071A10D47A00C56D7F /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
7F950A901A35E967003C8C5C /* LeaderBoardViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeaderBoardViewController.swift; sourceTree = "<group>"; }; 7F950A901A35E967003C8C5C /* LeaderboardViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeaderboardViewController.swift; sourceTree = "<group>"; };
7F99DE3B1A126554009B3619 /* RegattaViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegattaViewController.swift; sourceTree = "<group>"; }; 7F99DE3B1A126554009B3619 /* RegattaViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegattaViewController.swift; sourceTree = "<group>"; };
7FA6551919F6661900A1B92D /* CoreDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CoreDataManager.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 7FA6551919F6661900A1B92D /* CoreDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CoreDataManager.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
7FAFA7941A126B5700D230F1 /* AboutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; }; 7FAFA7941A126B5700D230F1 /* AboutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
@@ -702,16 +702,16 @@
C8739D891D21276B00A89F3C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Main.strings; 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>"; }; 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>"; }; C8739D9A1D25317100A89F3C /* CoreData 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "CoreData 2.xcdatamodel"; sourceTree = "<group>"; };
C8739DA51D2539A900A89F3C /* CheckIn+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CheckIn+CoreDataProperties.swift"; sourceTree = "<group>"; }; C8739DFA1D2AA2A500A89F3C /* Regatta+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Regatta+CoreDataProperties.swift"; sourceTree = "<group>"; };
C8739DA61D2539A900A89F3C /* CheckIn.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckIn.swift; sourceTree = "<group>"; }; C8739DFB1D2AA2A500A89F3C /* Regatta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Regatta.swift; sourceTree = "<group>"; };
C8739DA91D2539A900A89F3C /* Event+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Event+CoreDataProperties.swift"; sourceTree = "<group>"; }; C8739DFC1D2AA2A500A89F3C /* GPSFix+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GPSFix+CoreDataProperties.swift"; sourceTree = "<group>"; };
C8739DAA1D2539A900A89F3C /* Event.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = "<group>"; }; C8739DFD1D2AA2A500A89F3C /* GPSFix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GPSFix.swift; sourceTree = "<group>"; };
C8739DAB1D2539A900A89F3C /* Competitor+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Competitor+CoreDataProperties.swift"; sourceTree = "<group>"; }; C8739DFE1D2AA2A500A89F3C /* Leaderboard+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Leaderboard+CoreDataProperties.swift"; sourceTree = "<group>"; };
C8739DAC1D2539A900A89F3C /* Competitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Competitor.swift; sourceTree = "<group>"; }; C8739DFF1D2AA2A500A89F3C /* Leaderboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Leaderboard.swift; sourceTree = "<group>"; };
C8739DAD1D2539A900A89F3C /* GPSFix+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GPSFix+CoreDataProperties.swift"; sourceTree = "<group>"; }; C8739E001D2AA2A500A89F3C /* Competitor+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Competitor+CoreDataProperties.swift"; sourceTree = "<group>"; };
C8739DAE1D2539A900A89F3C /* GPSFix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GPSFix.swift; sourceTree = "<group>"; }; C8739E011D2AA2A500A89F3C /* Competitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Competitor.swift; sourceTree = "<group>"; };
C8739DB91D25409700A89F3C /* Leaderboard+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Leaderboard+CoreDataProperties.swift"; sourceTree = "<group>"; }; C8739E021D2AA2A500A89F3C /* Event+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Event+CoreDataProperties.swift"; sourceTree = "<group>"; };
C8739DBA1D25409700A89F3C /* Leaderboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Leaderboard.swift; sourceTree = "<group>"; }; C8739E031D2AA2A500A89F3C /* Event.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = "<group>"; };
C89C5FC41D06A289002AAAD2 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientView.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>"; }; 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>"; }; C89C5FCB1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GPSAccuracyTrackingTableViewCell.swift; sourceTree = "<group>"; };
@@ -763,16 +763,16 @@
children = ( children = (
7FA6551919F6661900A1B92D /* CoreDataManager.swift */, 7FA6551919F6661900A1B92D /* CoreDataManager.swift */,
7F44095919F65B5B0021BF22 /* CoreData.xcdatamodeld */, 7F44095919F65B5B0021BF22 /* CoreData.xcdatamodeld */,
C8739DA51D2539A900A89F3C /* CheckIn+CoreDataProperties.swift */, C8739DFA1D2AA2A500A89F3C /* Regatta+CoreDataProperties.swift */,
C8739DA61D2539A900A89F3C /* CheckIn.swift */, C8739DFB1D2AA2A500A89F3C /* Regatta.swift */,
C8739DA91D2539A900A89F3C /* Event+CoreDataProperties.swift */, C8739DFC1D2AA2A500A89F3C /* GPSFix+CoreDataProperties.swift */,
C8739DAA1D2539A900A89F3C /* Event.swift */, C8739DFD1D2AA2A500A89F3C /* GPSFix.swift */,
C8739DAB1D2539A900A89F3C /* Competitor+CoreDataProperties.swift */, C8739DFE1D2AA2A500A89F3C /* Leaderboard+CoreDataProperties.swift */,
C8739DAC1D2539A900A89F3C /* Competitor.swift */, C8739DFF1D2AA2A500A89F3C /* Leaderboard.swift */,
C8739DAD1D2539A900A89F3C /* GPSFix+CoreDataProperties.swift */, C8739E001D2AA2A500A89F3C /* Competitor+CoreDataProperties.swift */,
C8739DAE1D2539A900A89F3C /* GPSFix.swift */, C8739E011D2AA2A500A89F3C /* Competitor.swift */,
C8739DB91D25409700A89F3C /* Leaderboard+CoreDataProperties.swift */, C8739E021D2AA2A500A89F3C /* Event+CoreDataProperties.swift */,
C8739DBA1D25409700A89F3C /* Leaderboard.swift */, C8739E031D2AA2A500A89F3C /* Event.swift */,
); );
name = CoreData; name = CoreData;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1267,7 +1267,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7F99DE3B1A126554009B3619 /* RegattaViewController.swift */, 7F99DE3B1A126554009B3619 /* RegattaViewController.swift */,
7F950A901A35E967003C8C5C /* LeaderBoardViewController.swift */, 7F950A901A35E967003C8C5C /* LeaderboardViewController.swift */,
C89C5FC61D06CE62002AAAD2 /* Tracking */, C89C5FC61D06CE62002AAAD2 /* Tracking */,
); );
name = Regatta; name = Regatta;
@@ -1845,16 +1845,16 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
C8739DB61D2539A900A89F3C /* Competitor.swift in Sources */,
7F1875B31A10F1B800C25BE0 /* TrackingViewController.swift in Sources */, 7F1875B31A10F1B800C25BE0 /* TrackingViewController.swift in Sources */,
C8739E081D2AA2A500A89F3C /* Leaderboard+CoreDataProperties.swift in Sources */,
7F83F15819F154F000C53328 /* HomeViewController.swift in Sources */, 7F83F15819F154F000C53328 /* HomeViewController.swift in Sources */,
C8739DAF1D2539A900A89F3C /* CheckIn+CoreDataProperties.swift in Sources */,
7F8B8D431A373D4400C34B88 /* CourseViewController.swift in Sources */, 7F8B8D431A373D4400C34B88 /* CourseViewController.swift in Sources */,
C8739DB81D2539A900A89F3C /* GPSFix.swift in Sources */,
7FAFA7951A126B5700D230F1 /* AboutViewController.swift in Sources */, 7FAFA7951A126B5700D230F1 /* AboutViewController.swift in Sources */,
C8739E0A1D2AA2A500A89F3C /* Competitor+CoreDataProperties.swift in Sources */,
C8739E0C1D2AA2A500A89F3C /* Event+CoreDataProperties.swift in Sources */,
C8739E071D2AA2A500A89F3C /* GPSFix.swift in Sources */,
7F44095B19F65B5B0021BF22 /* CoreData.xcdatamodeld in Sources */, 7F44095B19F65B5B0021BF22 /* CoreData.xcdatamodeld in Sources */,
C89C5FD01D06CF46002AAAD2 /* ModeTrackingTableViewCell.swift in Sources */, C89C5FD01D06CF46002AAAD2 /* ModeTrackingTableViewCell.swift in Sources */,
C8739DB71D2539A900A89F3C /* GPSFix+CoreDataProperties.swift in Sources */,
7F1B66F91A0CDCF600904A41 /* BatteryManager.swift in Sources */, 7F1B66F91A0CDCF600904A41 /* BatteryManager.swift in Sources */,
7FA6551A19F6661900A1B92D /* CoreDataManager.swift in Sources */, 7FA6551A19F6661900A1B92D /* CoreDataManager.swift in Sources */,
C852BAA21CF5E1EA0093B0C5 /* RequestManager.swift in Sources */, C852BAA21CF5E1EA0093B0C5 /* RequestManager.swift in Sources */,
@@ -1863,26 +1863,26 @@
7F23F0881A1A3DEF00F03F1C /* CheckInController.swift in Sources */, 7F23F0881A1A3DEF00F03F1C /* CheckInController.swift in Sources */,
7F2C605A19F160E400C32D93 /* LocationManager.swift in Sources */, 7F2C605A19F160E400C32D93 /* LocationManager.swift in Sources */,
C89C5FCC1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift in Sources */, C89C5FCC1D06CF0C002AAAD2 /* GPSAccuracyTrackingTableViewCell.swift in Sources */,
C8739E041D2AA2A500A89F3C /* Regatta+CoreDataProperties.swift in Sources */,
C89C5FCA1D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift in Sources */, C89C5FCA1D06CECD002AAAD2 /* StatusTrackingTableViewCell.swift in Sources */,
C8739E051D2AA2A500A89F3C /* Regatta.swift in Sources */,
7F8B8D3F1A37356C00C34B88 /* TrackingPageViewController.swift in Sources */, 7F8B8D3F1A37356C00C34B88 /* TrackingPageViewController.swift in Sources */,
7F99DE3C1A126554009B3619 /* RegattaViewController.swift in Sources */, 7F99DE3C1A126554009B3619 /* RegattaViewController.swift in Sources */,
7F8CC2081A10D47A00C56D7F /* SettingsViewController.swift in Sources */, 7F8CC2081A10D47A00C56D7F /* SettingsViewController.swift in Sources */,
C8739E0D1D2AA2A500A89F3C /* Event.swift in Sources */,
7F8B8D411A373B0200C34B88 /* SpeedViewController.swift in Sources */, 7F8B8D411A373B0200C34B88 /* SpeedViewController.swift in Sources */,
C8739DB51D2539A900A89F3C /* Competitor+CoreDataProperties.swift in Sources */,
C8739DBB1D25409700A89F3C /* Leaderboard+CoreDataProperties.swift in Sources */,
9E95C3D61C723AB30016632B /* Constants.swift in Sources */, 9E95C3D61C723AB30016632B /* Constants.swift in Sources */,
C8739DB41D2539A900A89F3C /* Event.swift in Sources */,
7FD9D3031A1236080058FEAD /* Extensions.swift in Sources */, 7FD9D3031A1236080058FEAD /* Extensions.swift in Sources */,
C8739E091D2AA2A500A89F3C /* Leaderboard.swift in Sources */,
C89C5FC51D06A289002AAAD2 /* GradientView.swift in Sources */, C89C5FC51D06A289002AAAD2 /* GradientView.swift in Sources */,
C8739DBC1D25409700A89F3C /* Leaderboard.swift in Sources */,
C8739DB01D2539A900A89F3C /* CheckIn.swift in Sources */,
C852BAAB1CF736680093B0C5 /* Preferences.swift in Sources */, C852BAAB1CF736680093B0C5 /* Preferences.swift in Sources */,
C8739DB31D2539A900A89F3C /* Event+CoreDataProperties.swift in Sources */,
7F0658FD19F7D6700077FF95 /* ScanViewController.swift in Sources */, 7F0658FD19F7D6700077FF95 /* ScanViewController.swift in Sources */,
C8739E061D2AA2A500A89F3C /* GPSFix+CoreDataProperties.swift in Sources */,
7F193A8F1A39ACF500D71773 /* TimerViewController.swift in Sources */, 7F193A8F1A39ACF500D71773 /* TimerViewController.swift in Sources */,
7F83F15619F154F000C53328 /* AppDelegate.swift in Sources */, 7F83F15619F154F000C53328 /* AppDelegate.swift in Sources */,
7F950A911A35E967003C8C5C /* LeaderBoardViewController.swift in Sources */, 7F950A911A35E967003C8C5C /* LeaderboardViewController.swift in Sources */,
C89C5FCE1D06CF26002AAAD2 /* CachedFixesTrackingTableViewCell.swift in Sources */, C89C5FCE1D06CF26002AAAD2 /* CachedFixesTrackingTableViewCell.swift in Sources */,
C8739E0B1D2AA2A500A89F3C /* Competitor.swift in Sources */,
7F0658FF19F7EE910077FF95 /* CheckInData.swift in Sources */, 7F0658FF19F7EE910077FF95 /* CheckInData.swift in Sources */,
7F193A911A39E54600D71773 /* GPSAccuracyView.swift in Sources */, 7F193A911A39E54600D71773 /* GPSAccuracyView.swift in Sources */,
); );
@@ -36,7 +36,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
} }
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool { func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
Preferences.lastCheckInURLString = urlStringForDeeplink(url) Preferences.newCheckInURL = urlStringForDeeplink(url)
return true return true
} }
@@ -68,11 +68,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private func setupNavigationBarApperance() { private func setupNavigationBarApperance() {
let tintColor = UIColor(hex: 0x009de0) let tintColor = UIColor(hex: 0x009de0)
let font = UIFont(name: "OpenSans-Bold", size: CGFloat(17.0)) ?? UIFont.systemFontOfSize(17.0)
UINavigationBar.appearance().tintColor = tintColor UINavigationBar.appearance().tintColor = tintColor
UINavigationBar.appearance().titleTextAttributes = UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: tintColor, NSFontAttributeName: font]
[NSForegroundColorAttributeName: tintColor,
NSFontAttributeName: UIFont(name: "OpenSans-Bold", size: CGFloat(17.0))!
]
} }
private func setupPageControlApperance() { private func setupPageControlApperance() {
@@ -89,6 +87,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// FIXME: - Two prefixes are not allowed // FIXME: - Two prefixes are not allowed
// Deeplink needs another structure (if possible) because of allowed characters in URL // Deeplink needs another structure (if possible) because of allowed characters in URL
// https:// -> http// // https:// -> http//
urlString = urlString.hasPrefix(appPrefix) ? urlString.substringFromIndex(appPrefix.endIndex) : urlString urlString = urlString.hasPrefix(appPrefix) ? urlString.substringFromIndex(appPrefix.endIndex) : urlString
let httpPrefix : String = "http//" let httpPrefix : String = "http//"
urlString = urlString.hasPrefix(httpPrefix) ? "http://" + urlString.substringFromIndex(httpPrefix.endIndex) : urlString urlString = urlString.hasPrefix(httpPrefix) ? "http://" + urlString.substringFromIndex(httpPrefix.endIndex) : urlString
@@ -190,6 +190,9 @@
<accessibility key="accessibilityConfiguration" label="You can find your QR code on your registration confirmation"/> <accessibility key="accessibilityConfiguration" label="You can find your QR code on your registration confirmation"/>
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="14"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="14"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="200" width="260" height="16.5"/>
</variation>
</label> </label>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@@ -384,6 +387,9 @@
<rect key="frame" x="526" y="8" width="54" height="22"/> <rect key="frame" x="526" y="8" width="54" height="22"/>
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="16"/> <fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="16"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="224.5" y="9.5" width="55.5" height="19"/>
</variation>
</label> </label>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="DE.png" translatesAutoresizingMaskIntoConstraints="NO" id="szG-Mg-huO"> <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="DE.png" translatesAutoresizingMaskIntoConstraints="NO" id="szG-Mg-huO">
<rect key="frame" x="494" y="7" width="24" height="24"/> <rect key="frame" x="494" y="7" width="24" height="24"/>
@@ -391,11 +397,17 @@
<constraint firstAttribute="width" constant="24" id="Ina-uK-atY"/> <constraint firstAttribute="width" constant="24" id="Ina-uK-atY"/>
<constraint firstAttribute="height" constant="24" id="TVX-WF-dOi"/> <constraint firstAttribute="height" constant="24" id="TVX-WF-dOi"/>
</constraints> </constraints>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="192.5" y="7" width="24" height="24"/>
</variation>
</imageView> </imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Max Mustermann" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="oJS-dM-2B6" userLabel="Name Label"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Max Mustermann" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="oJS-dM-2B6" userLabel="Name Label">
<rect key="frame" x="20" y="8" width="142" height="22"/> <rect key="frame" x="20" y="8" width="142" height="22"/>
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="16"/> <fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="16"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="9.5" width="125.5" height="19"/>
</variation>
</label> </label>
</subviews> </subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.59999999999999998" colorSpace="calibratedRGB"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="0.59999999999999998" colorSpace="calibratedRGB"/>
@@ -468,6 +480,9 @@
<color key="value" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> <color key="value" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</userDefinedRuntimeAttribute> </userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes> </userDefinedRuntimeAttributes>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="50" y="133.5" width="200" height="33"/>
</variation>
<connections> <connections>
<action selector="teamImageAddButtonTapped:" destination="G3a-SV-Maf" eventType="touchUpInside" id="cs9-h3-kj2"/> <action selector="teamImageAddButtonTapped:" destination="G3a-SV-Maf" eventType="touchUpInside" id="cs9-h3-kj2"/>
</connections> </connections>
@@ -533,12 +548,18 @@
<rect key="frame" x="8" y="0.0" width="59" height="29"/> <rect key="frame" x="8" y="0.0" width="59" height="29"/>
<fontDescription key="fontDescription" name="OpenSans-Semibold" family="Open Sans" pointSize="21"/> <fontDescription key="fontDescription" name="OpenSans-Semibold" family="Open Sans" pointSize="21"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="8" y="0.0" width="55.5" height="24.5"/>
</variation>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Days" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l8F-Sg-cUb" userLabel="Days Description Label"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Days" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l8F-Sg-cUb" userLabel="Days Description Label">
<rect key="frame" x="8" y="28" width="59" height="22"/> <rect key="frame" x="8" y="28" width="59" height="22"/>
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="16"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="16"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="8" y="31" width="55.5" height="19"/>
</variation>
</label> </label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="joW-cG-ai8" userLabel="Separator View"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="joW-cG-ai8" userLabel="Separator View">
<rect key="frame" x="75" y="10" width="1" height="30"/> <rect key="frame" x="75" y="10" width="1" height="30"/>
@@ -547,6 +568,9 @@
<constraint firstAttribute="height" constant="30" id="Jj2-tX-SU9"/> <constraint firstAttribute="height" constant="30" id="Jj2-tX-SU9"/>
<constraint firstAttribute="width" constant="1" id="sJJ-vK-Ocb"/> <constraint firstAttribute="width" constant="1" id="sJJ-vK-Ocb"/>
</constraints> </constraints>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="71.5" y="10" width="1" height="30"/>
</variation>
</view> </view>
</subviews> </subviews>
<constraints> <constraints>
@@ -559,6 +583,9 @@
<constraint firstItem="sGD-0U-P4b" firstAttribute="top" secondItem="pjH-rV-MGI" secondAttribute="top" id="row-df-nQb"/> <constraint firstItem="sGD-0U-P4b" firstAttribute="top" secondItem="pjH-rV-MGI" secondAttribute="top" id="row-df-nQb"/>
<constraint firstAttribute="bottom" secondItem="l8F-Sg-cUb" secondAttribute="bottom" id="zUW-Uk-XQr"/> <constraint firstAttribute="bottom" secondItem="l8F-Sg-cUb" secondAttribute="bottom" id="zUW-Uk-XQr"/>
</constraints> </constraints>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="0.0" y="0.0" width="73" height="50"/>
</variation>
</view> </view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5is-0I-Kv3" userLabel="Hours View"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5is-0I-Kv3" userLabel="Hours View">
<rect key="frame" x="76" y="0.0" width="76.5" height="50"/> <rect key="frame" x="76" y="0.0" width="76.5" height="50"/>
@@ -567,12 +594,18 @@
<rect key="frame" x="8" y="0.0" width="60.5" height="29"/> <rect key="frame" x="8" y="0.0" width="60.5" height="29"/>
<fontDescription key="fontDescription" name="OpenSans-Semibold" family="Open Sans" pointSize="21"/> <fontDescription key="fontDescription" name="OpenSans-Semibold" family="Open Sans" pointSize="21"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="8" y="0.0" width="57" height="24.5"/>
</variation>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hours" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c2J-Uj-KEg" userLabel="Hours Description Label"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hours" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c2J-Uj-KEg" userLabel="Hours Description Label">
<rect key="frame" x="8" y="28" width="60.5" height="22"/> <rect key="frame" x="8" y="28" width="60.5" height="22"/>
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="16"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="16"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="8" y="31" width="57" height="19"/>
</variation>
</label> </label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JBv-xm-KUq" userLabel="Separator View"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JBv-xm-KUq" userLabel="Separator View">
<rect key="frame" x="75" y="10" width="1" height="30"/> <rect key="frame" x="75" y="10" width="1" height="30"/>
@@ -581,6 +614,9 @@
<constraint firstAttribute="width" constant="1" id="Gck-dw-et7"/> <constraint firstAttribute="width" constant="1" id="Gck-dw-et7"/>
<constraint firstAttribute="height" constant="30" id="gVK-VO-Bq4"/> <constraint firstAttribute="height" constant="30" id="gVK-VO-Bq4"/>
</constraints> </constraints>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="71.5" y="10" width="1" height="30"/>
</variation>
</view> </view>
</subviews> </subviews>
<constraints> <constraints>
@@ -593,6 +629,9 @@
<constraint firstItem="gaG-Iv-Xyq" firstAttribute="top" secondItem="5is-0I-Kv3" secondAttribute="top" id="ryA-23-kxC"/> <constraint firstItem="gaG-Iv-Xyq" firstAttribute="top" secondItem="5is-0I-Kv3" secondAttribute="top" id="ryA-23-kxC"/>
<constraint firstAttribute="trailing" secondItem="JBv-xm-KUq" secondAttribute="trailing" id="z4K-rX-taw"/> <constraint firstAttribute="trailing" secondItem="JBv-xm-KUq" secondAttribute="trailing" id="z4K-rX-taw"/>
</constraints> </constraints>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="72.5" y="0.0" width="73" height="50"/>
</variation>
</view> </view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tvc-eS-Us6" userLabel="Minutes View"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tvc-eS-Us6" userLabel="Minutes View">
<rect key="frame" x="152" y="0.0" width="76.5" height="50"/> <rect key="frame" x="152" y="0.0" width="76.5" height="50"/>
@@ -601,12 +640,18 @@
<rect key="frame" x="8" y="0.0" width="60.5" height="29"/> <rect key="frame" x="8" y="0.0" width="60.5" height="29"/>
<fontDescription key="fontDescription" name="OpenSans-Semibold" family="Open Sans" pointSize="21"/> <fontDescription key="fontDescription" name="OpenSans-Semibold" family="Open Sans" pointSize="21"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="8" y="0.0" width="57" height="24.5"/>
</variation>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Minutes" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EES-a9-qxv" userLabel="Minutes Description Label"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Minutes" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EES-a9-qxv" userLabel="Minutes Description Label">
<rect key="frame" x="8" y="28" width="60.5" height="22"/> <rect key="frame" x="8" y="28" width="60.5" height="22"/>
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="16"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="16"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="8" y="31" width="57" height="19"/>
</variation>
</label> </label>
</subviews> </subviews>
<constraints> <constraints>
@@ -617,6 +662,9 @@
<constraint firstAttribute="bottom" secondItem="EES-a9-qxv" secondAttribute="bottom" id="jdu-Od-J49"/> <constraint firstAttribute="bottom" secondItem="EES-a9-qxv" secondAttribute="bottom" id="jdu-Od-J49"/>
<constraint firstItem="Txm-uf-MP4" firstAttribute="top" secondItem="tvc-eS-Us6" secondAttribute="top" id="vpc-a8-Iuw"/> <constraint firstItem="Txm-uf-MP4" firstAttribute="top" secondItem="tvc-eS-Us6" secondAttribute="top" id="vpc-a8-Iuw"/>
</constraints> </constraints>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="145" y="0.0" width="73" height="50"/>
</variation>
</view> </view>
</subviews> </subviews>
<constraints> <constraints>
@@ -642,6 +690,9 @@
<constraint firstAttribute="bottom" secondItem="5is-0I-Kv3" secondAttribute="bottom" id="ngY-tF-5EI"/> <constraint firstAttribute="bottom" secondItem="5is-0I-Kv3" secondAttribute="bottom" id="ngY-tF-5EI"/>
<constraint firstItem="tvc-eS-Us6" firstAttribute="top" secondItem="6rV-hv-c3D" secondAttribute="top" id="wUO-8b-mHS"/> <constraint firstItem="tvc-eS-Us6" firstAttribute="top" secondItem="6rV-hv-c3D" secondAttribute="top" id="wUO-8b-mHS"/>
</constraints> </constraints>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="41.5" y="38" width="218.5" height="50"/>
</variation>
</view> </view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lzv-E6-gsr"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lzv-E6-gsr">
<rect key="frame" x="20" y="96" width="276" height="48"/> <rect key="frame" x="20" y="96" width="276" height="48"/>
@@ -948,6 +999,9 @@
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="16" width="49" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="20" y="35.5" width="49" height="20"/> <rect key="frame" x="20" y="35.5" width="49" height="20"/>
</variation> </variation>
@@ -956,6 +1010,9 @@
<rect key="frame" x="444" y="14" width="136" height="24"/> <rect key="frame" x="444" y="14" width="136" height="24"/>
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="448" y="16" width="132" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="648" y="35.5" width="132" height="20"/> <rect key="frame" x="648" y="35.5" width="132" height="20"/>
</variation> </variation>
@@ -985,6 +1042,9 @@
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="16" width="44" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="20" y="96" width="44" height="20"/> <rect key="frame" x="20" y="96" width="44" height="20"/>
</variation> </variation>
@@ -993,6 +1053,9 @@
<rect key="frame" x="527.5" y="14" width="52.5" height="23.5"/> <rect key="frame" x="527.5" y="14" width="52.5" height="23.5"/>
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="231" y="16" width="49" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="731" y="96" width="49" height="20"/> <rect key="frame" x="731" y="96" width="49" height="20"/>
</variation> </variation>
@@ -1022,6 +1085,9 @@
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="16" width="104" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="20" y="64" width="104" height="24"/> <rect key="frame" x="20" y="64" width="104" height="24"/>
</variation> </variation>
@@ -1030,6 +1096,9 @@
<rect key="frame" x="570" y="14" width="10" height="24"/> <rect key="frame" x="570" y="14" width="10" height="24"/>
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="270" y="16" width="10" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="770" y="64" width="10" height="24"/> <rect key="frame" x="770" y="64" width="10" height="24"/>
</variation> </variation>
@@ -1059,6 +1128,9 @@
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="16" width="111" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="20" y="8" width="111" height="20"/> <rect key="frame" x="20" y="8" width="111" height="20"/>
</variation> </variation>
@@ -1068,6 +1140,9 @@
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="501" y="16" width="59" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="705" y="8" width="59" height="20"/> <rect key="frame" x="705" y="8" width="59" height="20"/>
</variation> </variation>
@@ -1179,6 +1254,9 @@
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="8" width="106" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="20" y="0.0" width="106" height="24"/> <rect key="frame" x="20" y="0.0" width="106" height="24"/>
</variation> </variation>
@@ -1188,6 +1266,9 @@
<fontDescription key="fontDescription" name="OpenSans-Light" family="Open Sans" pointSize="72"/> <fontDescription key="fontDescription" name="OpenSans-Light" family="Open Sans" pointSize="72"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="117" width="560" height="84"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="20" y="358" width="760" height="84"/> <rect key="frame" x="20" y="358" width="760" height="84"/>
</variation> </variation>
@@ -1228,12 +1309,18 @@
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="8" width="49.5" height="20"/>
</variation>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0.0 kn" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l5u-i3-029"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0.0 kn" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l5u-i3-029">
<rect key="frame" x="203" y="210" width="195.5" height="98.5"/> <rect key="frame" x="203" y="210" width="195.5" height="98.5"/>
<fontDescription key="fontDescription" name="OpenSans-Light" family="Open Sans" pointSize="72"/> <fontDescription key="fontDescription" name="OpenSans-Light" family="Open Sans" pointSize="72"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="202" y="117" width="197.5" height="84"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="301.5" y="358" width="197.5" height="84"/> <rect key="frame" x="301.5" y="358" width="197.5" height="84"/>
</variation> </variation>
@@ -1271,6 +1358,9 @@
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="8" width="38.5" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="20" y="0.0" width="38.5" height="20"/> <rect key="frame" x="20" y="0.0" width="38.5" height="20"/>
</variation> </variation>
@@ -1280,6 +1370,9 @@
<fontDescription key="fontDescription" name="OpenSans-Light" family="Open Sans" pointSize="72"/> <fontDescription key="fontDescription" name="OpenSans-Light" family="Open Sans" pointSize="72"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="256" y="117" width="89" height="84"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="355.5" y="358" width="89" height="84"/> <rect key="frame" x="355.5" y="358" width="89" height="84"/>
</variation> </variation>
@@ -1532,12 +1625,18 @@ Cg
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="256" width="43" height="15.5"/>
</variation>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1.0.0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jsi-LA-7jU"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1.0.0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jsi-LA-7jU">
<rect key="frame" x="20" y="202" width="30" height="18"/> <rect key="frame" x="20" y="202" width="30" height="18"/>
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="20" y="279.5" width="29" height="15.5"/>
</variation>
</label> </label>
</subviews> </subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@@ -1582,21 +1681,21 @@ Cg
</constraints> </constraints>
<variation key="default"> <variation key="default">
<mask key="constraints"> <mask key="constraints">
<exclude reference="HxP-XV-1as"/>
<exclude reference="Htc-F9-k7d"/> <exclude reference="Htc-F9-k7d"/>
<exclude reference="i64-7l-JjE"/> <exclude reference="i64-7l-JjE"/>
<exclude reference="rI9-vl-bNT"/> <exclude reference="rI9-vl-bNT"/>
<exclude reference="HxP-XV-1as"/>
</mask> </mask>
</variation> </variation>
<variation key="heightClass=compact"> <variation key="heightClass=compact">
<mask key="constraints"> <mask key="constraints">
<exclude reference="YBh-Y6-NK3"/> <exclude reference="YBh-Y6-NK3"/>
<include reference="HxP-XV-1as"/>
<exclude reference="08e-KJ-Dpa"/> <exclude reference="08e-KJ-Dpa"/>
<exclude reference="Bht-kB-G6p"/> <exclude reference="Bht-kB-G6p"/>
<include reference="Htc-F9-k7d"/> <include reference="Htc-F9-k7d"/>
<include reference="i64-7l-JjE"/> <include reference="i64-7l-JjE"/>
<include reference="rI9-vl-bNT"/> <include reference="rI9-vl-bNT"/>
<include reference="HxP-XV-1as"/>
</mask> </mask>
</variation> </variation>
</view> </view>
@@ -1681,6 +1780,9 @@ Cg
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="14" y="12" width="111.5" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="15" y="10" width="111.5" height="24"/> <rect key="frame" x="15" y="10" width="111.5" height="24"/>
</variation> </variation>
@@ -1710,6 +1812,9 @@ Cg
<fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="17"/> <fontDescription key="fontDescription" name="OpenSans-Bold" family="Open Sans" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="14" y="2" width="127" height="20"/>
</variation>
<variation key="heightClass=regular-widthClass=regular" misplaced="YES"> <variation key="heightClass=regular-widthClass=regular" misplaced="YES">
<rect key="frame" x="15" y="10" width="111.5" height="24"/> <rect key="frame" x="15" y="10" width="111.5" height="24"/>
</variation> </variation>
@@ -1719,6 +1824,9 @@ Cg
<fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/> <fontDescription key="fontDescription" name="OpenSans" family="Open Sans" pointSize="13"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="heightClass=compact" misplaced="YES">
<rect key="frame" x="14" y="26" width="32" height="15.5"/>
</variation>
</label> </label>
</subviews> </subviews>
<constraints> <constraints>
@@ -1791,7 +1899,7 @@ Cg
<!--Leader Board--> <!--Leader Board-->
<scene sceneID="BcW-Cr-BGq"> <scene sceneID="BcW-Cr-BGq">
<objects> <objects>
<viewController id="86Y-sl-Zhj" customClass="LeaderBoardViewController" customModule="SAPTracker" customModuleProvider="target" sceneMemberID="viewController"> <viewController id="86Y-sl-Zhj" customClass="LeaderboardViewController" customModule="SAPTracker" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides> <layoutGuides>
<viewControllerLayoutGuide type="top" id="Dlt-1X-fN2"/> <viewControllerLayoutGuide type="top" id="Dlt-1X-fN2"/>
<viewControllerLayoutGuide type="bottom" id="Ehu-33-1iX"/> <viewControllerLayoutGuide type="bottom" id="Ehu-33-1iX"/>
@@ -1825,7 +1933,7 @@ Cg
<navigationItem key="navigationItem" title="Leader Board" id="8qz-J9-1KL"> <navigationItem key="navigationItem" title="Leader Board" id="8qz-J9-1KL">
<barButtonItem key="rightBarButtonItem" systemItem="done" id="NSL-iA-JLn"> <barButtonItem key="rightBarButtonItem" systemItem="done" id="NSL-iA-JLn">
<connections> <connections>
<action selector="done:" destination="86Y-sl-Zhj" id="BdJ-Hv-zJb"/> <action selector="doneButtonTapped:" destination="86Y-sl-Zhj" id="Xm9-iN-s5q"/>
</connections> </connections>
</barButtonItem> </barButtonItem>
</navigationItem> </navigationItem>
@@ -1868,8 +1976,8 @@ Cg
<image name="settings" width="22" height="22"/> <image name="settings" width="22" height="22"/>
</resources> </resources>
<inferredMetricsTieBreakers> <inferredMetricsTieBreakers>
<segue reference="QMa-LQ-D8c"/> <segue reference="tzB-PL-31j"/>
<segue reference="HaH-Jc-FNR"/> <segue reference="Irs-ey-Uhs"/>
</inferredMetricsTieBreakers> </inferredMetricsTieBreakers>
<color key="tintColor" red="0.0" green="0.61568627450980395" blue="0.8784313725490196" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="0.0" green="0.61568627450980395" blue="0.8784313725490196" alpha="1" colorSpace="calibratedRGB"/>
</document> </document>
@@ -10,7 +10,7 @@ import UIKit
class CachedFixesTrackingTableViewCell: UITableViewCell { class CachedFixesTrackingTableViewCell: UITableViewCell {
var checkIn: CheckIn? var regatta: Regatta?
@IBOutlet weak var cachedFixesLabel: UILabel! @IBOutlet weak var cachedFixesLabel: UILabel!
@@ -27,7 +27,7 @@ class CachedFixesTrackingTableViewCell: UITableViewCell {
// MARK: - Setups // MARK: - Setups
private func setupCachedFixesLabel() { private func setupCachedFixesLabel() {
self.cachedFixesLabel.text = String(format: "%d", checkIn?.gpsFixes?.count ?? 0) self.cachedFixesLabel.text = String(format: "%d", regatta?.gpsFixes?.count ?? 0)
} }
// MARK: - Notifications // MARK: - Notifications
@@ -1,17 +0,0 @@
//
// CheckIn.swift
// SAPTracker
//
// Created by Raimund Wege on 30.06.16.
// Copyright © 2016 com.sap.sailing. All rights reserved.
//
import Foundation
import CoreData
@objc(CheckIn)
class CheckIn: NSManagedObject {
// Insert code here to add functionality to your managed object subclass
}
@@ -42,30 +42,39 @@ class CheckInController : NSObject {
static let Name = "name" static let Name = "name"
} }
private let checkInData: CheckInData! var delegate: CheckInControllerDelegate?
private let delegate: CheckInControllerDelegate!
private let requestManager: RequestManager!
private var checkInData = CheckInData()
private var requestManager = RequestManager()
// Responses // Responses
private var eventDictionary: [String: AnyObject]? private var eventDictionary: [String: AnyObject]?
private var leaderboardDictionary: [String: AnyObject]? private var leaderboardDictionary: [String: AnyObject]?
private var competitorDictionary: [String: AnyObject]? private var competitorDictionary: [String: AnyObject]?
private var teamImageURL: String? private var teamImageURL: String?
init(checkInData: CheckInData, delegate: CheckInControllerDelegate) { // MARK: - Initialize
private func initialize(checkInData: CheckInData) {
self.checkInData = checkInData self.checkInData = checkInData
self.delegate = delegate setupRequestManager()
}
// MARK: - Setups
private func setupRequestManager() {
requestManager = RequestManager(baseURLString: checkInData.serverURL) requestManager = RequestManager(baseURLString: checkInData.serverURL)
super.init()
} }
// MARK: - Start check-in // MARK: - Start check-in
func startCheckIn() { func startCheckIn(checkInData: CheckInData) {
initialize(checkInData)
checkInDidStart() checkInDidStart()
requestManager.getEvent(checkInData.eventID, requestManager.getEvent(checkInData.eventID,
success: { (operation, responseObject) -> Void in self.eventSucceed(responseObject) }, success: { (operation, responseObject) -> Void in self.eventSucceed(responseObject) },
failure: { (operation, error) -> Void in self.eventFailed(error) }) failure: { (operation, error) -> Void in self.eventFailed(error) }
)
} }
// MARK: - Event // MARK: - Event
@@ -74,7 +83,8 @@ class CheckInController : NSObject {
eventDictionary = eventResponseObject as? [String: AnyObject] eventDictionary = eventResponseObject as? [String: AnyObject]
requestManager.getLeaderboard(checkInData.leaderboardName, requestManager.getLeaderboard(checkInData.leaderboardName,
success: { (operation, responseObject) -> Void in self.leaderboardSucceed(responseObject) }, success: { (operation, responseObject) -> Void in self.leaderboardSucceed(responseObject) },
failure: { (operation, error) -> Void in self.leaderboardFailed(error) }) failure: { (operation, error) -> Void in self.leaderboardFailed(error) }
)
} }
private func eventFailed(error: AnyObject) { private func eventFailed(error: AnyObject) {
@@ -94,7 +104,8 @@ class CheckInController : NSObject {
leaderboardDictionary = leaderboardResponseObject as? [String: AnyObject] leaderboardDictionary = leaderboardResponseObject as? [String: AnyObject]
requestManager.getCompetitor(checkInData.competitorID, requestManager.getCompetitor(checkInData.competitorID,
success: { (operation, responseObject) in self.competitorSucceed(responseObject) }, success: { (operation, responseObject) in self.competitorSucceed(responseObject) },
failure: { (operation, error) in self.competitorFailed(error) }) failure: { (operation, error) in self.competitorFailed(error) }
)
} }
private func leaderboardFailed(error: AnyObject) { private func leaderboardFailed(error: AnyObject) {
@@ -112,7 +123,7 @@ class CheckInController : NSObject {
private func competitorSucceed(competitorResponseObject: AnyObject) { private func competitorSucceed(competitorResponseObject: AnyObject) {
competitorDictionary = competitorResponseObject as? [String: AnyObject] competitorDictionary = competitorResponseObject as? [String: AnyObject]
requestManager.getTeamImageURL(competitorID(), result: { (imageURL) in self.teamImageURLResult(imageURL) }) requestManager.getTeamImageURL(competitorID, result: { (imageURL) in self.teamImageURLResult(imageURL) })
} }
private func competitorFailed(error: AnyObject) { private func competitorFailed(error: AnyObject) {
@@ -131,9 +142,9 @@ class CheckInController : NSObject {
private func teamImageURLResult(imageURL: String?) { private func teamImageURLResult(imageURL: String?) {
teamImageURL = imageURL teamImageURL = imageURL
let alertTitle = String(format:NSLocalizedString("Hello %@. Welcome to %@. You are registered as %@.", comment: ""), let alertTitle = String(format:NSLocalizedString("Hello %@. Welcome to %@. You are registered as %@.", comment: ""),
competitorName(), competitorName,
leaderboardName(), leaderboardName,
competitorSailID()) competitorSailID)
let alertController = UIAlertController(title: alertTitle, message: nil, preferredStyle: .Alert) let alertController = UIAlertController(title: alertTitle, message: nil, preferredStyle: .Alert)
let okTitle = NSLocalizedString("OK", comment: "") let okTitle = NSLocalizedString("OK", comment: "")
let okAction = UIAlertAction(title: okTitle, style: .Default) { (action) in let okAction = UIAlertAction(title: okTitle, style: .Default) { (action) in
@@ -145,76 +156,67 @@ class CheckInController : NSObject {
} }
alertController.addAction(okAction) alertController.addAction(okAction)
alertController.addAction(cancelAction) alertController.addAction(cancelAction)
self.showCheckInAlert(alertController) showCheckInAlert(alertController)
} }
// MARK: - Check-in on server // MARK: - Check-in on server
private func checkInOnServer() { private func checkInOnServer() {
SVProgressHUD.show() SVProgressHUD.show()
requestManager.postCheckIn(leaderboardName(), requestManager.postCheckIn(leaderboardName,
competitorID: competitorID(), competitorID: competitorID,
success: { (operation, responseObject) -> Void in self.checkInOnServerSucceed() }, success: { (operation, responseObject) -> Void in self.checkInOnServerSucceed() },
failure: { (operation, error) -> Void in self.checkInOnServerFailed(error) }) failure: { (operation, error) -> Void in self.checkInOnServerFailed(error) }
)
} }
private func checkInOnServerSucceed() { private func checkInOnServerSucceed() {
// Check database if check-in already exist // Regatta
if let checkIn = CoreDataManager.sharedManager.fetchCheckIn(checkInData.eventID, let regatta = CoreDataManager.sharedManager.fetchRegatta(checkInData.eventID,
leaderboardName: checkInData.leaderboardName, leaderboardName: checkInData.leaderboardName,
competitorID: checkInData.competitorID) { competitorID: checkInData.competitorID
// Delete old check-in ) ?? CoreDataManager.sharedManager.newRegatta()
CoreDataManager.sharedManager.deleteCheckIn(checkIn) regatta.serverURL = checkInData.serverURL
CoreDataManager.sharedManager.saveContext() regatta.teamImageURL = teamImageURL
} regatta.teamImageRetry = false
// Create new check-in // Event
let checkIn = CoreDataManager.sharedManager.newCheckIn() let event = regatta.event ?? CoreDataManager.sharedManager.newEvent(regatta)
checkIn.competitorID = checkInData!.competitorID event.endDate = (eventEndDate / 1000)
checkIn.eventID = checkInData.eventID event.eventID = eventID
checkIn.lastSyncDate = NSDate().timeIntervalSince1970 event.name = eventName
checkIn.leaderboardName = checkInData!.leaderboardName event.startDate = (eventStartDate / 1000)
checkIn.serverURL = checkInData!.serverURL
checkIn.teamImageURL = teamImageURL
checkIn.teamImageRetry = false
// Create new event // Leaderboard
let event = CoreDataManager.sharedManager.newEvent(checkIn) let leaderboard = regatta.leaderboard ?? CoreDataManager.sharedManager.newLeaderboard(regatta)
event.endDate = (eventEndDate() / 1000) leaderboard.name = leaderboardName
event.eventID = eventID()
event.name = eventName()
event.startDate = (eventStartDate() / 1000)
// Create new leaderboard
let leaderboard = CoreDataManager.sharedManager.newLeaderBoard(checkIn)
leaderboard.name = leaderboardName()
// Create new competitor // Competitor
let competitor = CoreDataManager.sharedManager.newCompetitor(checkIn) let competitor = regatta.competitor ?? CoreDataManager.sharedManager.newCompetitor(regatta)
competitor.boatClassName = competitorBoatClassName() competitor.boatClassName = competitorBoatClassName
competitor.competitorID = competitorID() competitor.competitorID = competitorID
competitor.countryCode = competitorCountryCode() competitor.countryCode = competitorCountryCode
competitor.name = competitorName() competitor.name = competitorName
competitor.nationality = competitorNationality() competitor.nationality = competitorNationality
competitor.sailID = competitorSailID() competitor.sailID = competitorSailID
// Save objects // Save
CoreDataManager.sharedManager.saveContext() CoreDataManager.sharedManager.saveContext()
// Check-in completed // Check-in completed
self.checkInDidEnd(withSuccess: true) checkInDidEnd(withSuccess: true)
} }
private func checkInOnServerFailed(error: AnyObject) { private func checkInOnServerFailed(error: AnyObject) {
let alertTitle = String(format:NSLocalizedString("Couldn't check-in to %@", comment: ""), checkInData!.leaderboardName) let alertTitle = String(format:NSLocalizedString("Couldn't check-in to %@", comment: ""), checkInData.leaderboardName)
let alertController = UIAlertController(title: alertTitle, message: error.localizedDescription, preferredStyle: .Alert) let alertController = UIAlertController(title: alertTitle, message: error.localizedDescription, preferredStyle: .Alert)
let cancelTitle = NSLocalizedString("Cancel", comment: "") let cancelTitle = NSLocalizedString("Cancel", comment: "")
let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel) { (action) in let cancelAction = UIAlertAction(title: cancelTitle, style: .Cancel) { (action) in
self.checkInDidEnd(withSuccess: false) self.checkInDidEnd(withSuccess: false)
} }
alertController.addAction(cancelAction) alertController.addAction(cancelAction)
self.showCheckInAlert(alertController) showCheckInAlert(alertController)
} }
// MARK: - Controller // MARK: - Controller
@@ -222,51 +224,52 @@ class CheckInController : NSObject {
private func checkInDidStart() { private func checkInDidStart() {
dispatch_async(dispatch_get_main_queue(), { dispatch_async(dispatch_get_main_queue(), {
SVProgressHUD.show() SVProgressHUD.show()
self.delegate.checkInDidStart?(self) self.delegate?.checkInDidStart?(self)
}) })
} }
private func checkInDidEnd(withSuccess succeed: Bool) { private func checkInDidEnd(withSuccess succeed: Bool) {
dispatch_async(dispatch_get_main_queue(), { dispatch_async(dispatch_get_main_queue(), {
SVProgressHUD.popActivity() SVProgressHUD.popActivity()
self.delegate.checkInDidEnd?(self, withSuccess: succeed) self.delegate?.checkInDidEnd?(self, withSuccess: succeed)
}) })
} }
private func showCheckInAlert(alertController: UIAlertController) { private func showCheckInAlert(alertController: UIAlertController) {
dispatch_async(dispatch_get_main_queue(), { dispatch_async(dispatch_get_main_queue(), {
SVProgressHUD.popActivity() SVProgressHUD.popActivity()
self.delegate.showCheckInAlert(self, alertController: alertController) self.delegate?.showCheckInAlert(self, alertController: alertController)
}) })
} }
// MARK: - Event // MARK: - Event
private func eventID() -> String! { return stringFromEvent(forKey: EventKeys.ID) } var eventID: String { get { return stringFromEvent(forKey: EventKeys.ID) } }
private func eventName() -> String! { return stringFromEvent(forKey: EventKeys.Name) } var eventName: String { get { return stringFromEvent(forKey: EventKeys.Name) } }
private func eventStartDate() -> Double! { return doubleFromEvent(forKey: EventKeys.StartDate) } var eventStartDate: Double { get { return doubleFromEvent(forKey: EventKeys.StartDate) } }
private func eventEndDate() -> Double! { return doubleFromEvent(forKey: EventKeys.EndDate) } var eventEndDate: Double { get { return doubleFromEvent(forKey: EventKeys.EndDate) } }
private func doubleFromEvent(forKey key: String) -> Double { return doubleFromDictionary(eventDictionary, forKey: key) }
private func stringFromEvent(forKey key: String) -> String { return stringFromDictionary(eventDictionary, forKey: key) }
// MARK: - Leaderboard // MARK: - Leaderboard
private func leaderboardName() -> String! { return stringFromLeaderboard(forKey: LeaderboardKeys.Name) } var leaderboardName: String { get { return stringFromLeaderboard(forKey: LeaderboardKeys.Name) } }
private func stringFromLeaderboard(forKey key: String) -> String { return stringFromDictionary(leaderboardDictionary, forKey: key) }
// MARK: - Competitor // MARK: - Competitor
private func competitorBoatClassName() -> String! { return stringFromCompetitor(forKey: CompetitorKeys.BoatClassName) } var competitorBoatClassName: String { get { return stringFromCompetitor(forKey: CompetitorKeys.BoatClassName) } }
private func competitorCountryCode() -> String! { return stringFromCompetitor(forKey: CompetitorKeys.CountryCode) } var competitorCountryCode: String { get { return stringFromCompetitor(forKey: CompetitorKeys.CountryCode) } }
private func competitorID() -> String { return stringFromCompetitor(forKey: CompetitorKeys.ID) } var competitorID: String { get { return stringFromCompetitor(forKey: CompetitorKeys.ID) } }
private func competitorName() -> String! { return stringFromCompetitor(forKey: CompetitorKeys.Name) } var competitorName: String { get { return stringFromCompetitor(forKey: CompetitorKeys.Name) } }
private func competitorNationality() -> String! { return stringFromCompetitor(forKey: CompetitorKeys.Nationality) } var competitorNationality: String { get { return stringFromCompetitor(forKey: CompetitorKeys.Nationality) } }
private func competitorSailID() -> String! { return stringFromCompetitor(forKey: CompetitorKeys.SailID) } var competitorSailID: String { get { return stringFromCompetitor(forKey: CompetitorKeys.SailID) } }
private func stringFromCompetitor(forKey key: String) -> String { return stringFromDictionary(competitorDictionary, forKey: key) }
// MARK: - Helper // 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 { private func doubleFromDictionary(dictionary: [String: AnyObject]?, forKey key: String) -> Double {
if let value = dictionary?[key] as? Double { if let value = dictionary?[key] as? Double {
return value return value
} else { } else {
@@ -274,7 +277,7 @@ class CheckInController : NSObject {
} }
} }
private func stringFromDictionary(dictionary: [String: AnyObject]?, forKey key: String!) -> String { private func stringFromDictionary(dictionary: [String: AnyObject]?, forKey key: String) -> String {
if let value = dictionary?[key] as? String { if let value = dictionary?[key] as? String {
return value return value
} else { } else {
@@ -16,17 +16,16 @@ public class CheckInData: NSObject {
static let CompetitorID = "competitor_id" static let CompetitorID = "competitor_id"
} }
public let serverURL: String! public let serverURL: String
public let eventID: String! public let eventID: String
public let leaderboardName: String! public let leaderboardName: String
public let competitorID: String! public let competitorID: String
init?(serverURL: String!, init(serverURL: String = "",
eventID: String!, eventID: String = "",
leaderboardName: String!, leaderboardName: String = "",
competitorID: String!) competitorID: String = "")
{ {
guard serverURL != nil && eventID != nil && leaderboardName != nil && competitorID != nil else { return nil }
self.serverURL = serverURL self.serverURL = serverURL
self.eventID = eventID self.eventID = eventID
self.leaderboardName = leaderboardName self.leaderboardName = leaderboardName
@@ -34,19 +33,21 @@ public class CheckInData: NSObject {
super.init() super.init()
} }
convenience init?(url: NSURL!) { convenience init?(url: NSURL) {
guard url != nil && url.host != nil && url.query != nil else { return nil } guard let host = url.host else { return nil }
guard let components = NSURLComponents(string: url.absoluteString) else { return nil } guard let components = NSURLComponents(string: url.absoluteString) else { return nil }
// Set server URL
let serverURL = url.scheme + "://" + host + (url.port != nil ? ":" + url.port!.stringValue : "")
// In query component replace '+' occurrences with '%20' as a workaround for bug 3664 // In query component replace '+' occurrences with '%20' as a workaround for bug 3664
components.percentEncodedQuery = components.percentEncodedQuery?.stringByReplacingOccurrencesOfString("+", withString: "%20") components.percentEncodedQuery = components.percentEncodedQuery?.stringByReplacingOccurrencesOfString("+", withString: "%20")
let queryItems = components.queryItems let queryItems = components.queryItems
// Set server URL and check-in items // Get check-in items
let serverURL = url.scheme + "://" + url.host! + (url.port == nil ? "" : ":" + url.port!.stringValue) guard let eventID = CheckInData.queryItemValue(queryItems, itemName: CheckInData.ItemNames.EventID) else { return nil }
let eventID = CheckInData.queryItemValue(queryItems, itemName: CheckInData.ItemNames.EventID) guard let leaderboardName = CheckInData.queryItemValue(queryItems, itemName: CheckInData.ItemNames.LeaderboardName) else { return nil }
let leaderboardName = CheckInData.queryItemValue(queryItems, itemName: CheckInData.ItemNames.LeaderboardName) guard let competitorID = CheckInData.queryItemValue(queryItems, itemName: CheckInData.ItemNames.CompetitorID) else { return nil }
let competitorID = CheckInData.queryItemValue(queryItems, itemName: CheckInData.ItemNames.CompetitorID)
// Init with values // Init with values
self.init(serverURL: serverURL, self.init(serverURL: serverURL,
@@ -55,8 +56,10 @@ public class CheckInData: NSObject {
competitorID: competitorID) competitorID: competitorID)
} }
convenience init?(urlString: String!) { convenience init?(urlString: String) {
guard let url = NSURL(string: urlString) else { return nil } guard let url = NSURL(string: urlString) else { return nil }
// Init with URL
self.init(url: url) self.init(url: url)
} }
@@ -2,7 +2,7 @@
// Competitor+CoreDataProperties.swift // Competitor+CoreDataProperties.swift
// SAPTracker // SAPTracker
// //
// Created by Raimund Wege on 01.07.16. // Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved. // Copyright © 2016 com.sap.sailing. All rights reserved.
// //
// Choose "Create NSManagedObject Subclass…" from the Core Data editor menu // Choose "Create NSManagedObject Subclass…" from the Core Data editor menu
@@ -14,12 +14,12 @@ import CoreData
extension Competitor { extension Competitor {
@NSManaged var boatClassName: String? @NSManaged var boatClassName: String
@NSManaged var competitorID: String? @NSManaged var competitorID: String
@NSManaged var countryCode: String? @NSManaged var countryCode: String
@NSManaged var name: String? @NSManaged var name: String
@NSManaged var nationality: String? @NSManaged var nationality: String
@NSManaged var sailID: String? @NSManaged var sailID: String
@NSManaged var checkIn: CheckIn? @NSManaged var regatta: Regatta
} }
@@ -2,7 +2,7 @@
// Competitor.swift // Competitor.swift
// SAPTracker // SAPTracker
// //
// Created by Raimund Wege on 30.06.16. // Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved. // Copyright © 2016 com.sap.sailing. All rights reserved.
// //
@@ -1,34 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10171" systemVersion="15E65" minimumToolsVersion="Xcode 4.3"> <model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="10171" systemVersion="15E65" minimumToolsVersion="Xcode 4.3">
<entity name="CheckIn" representedClassName="CheckIn" syncable="YES">
<attribute name="competitorID" attributeType="String" syncable="YES"/>
<attribute name="eventID" attributeType="String" syncable="YES"/>
<attribute name="lastSyncDate" optional="YES" attributeType="Date" syncable="YES"/>
<attribute name="leaderboardName" attributeType="String" syncable="YES"/>
<attribute name="serverURL" attributeType="String" syncable="YES"/>
<attribute name="teamImageData" optional="YES" attributeType="Binary" syncable="YES"/>
<attribute name="teamImageRetry" optional="YES" attributeType="Boolean" syncable="YES"/>
<attribute name="teamImageURL" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="competitor" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="Competitor" inverseName="checkIn" inverseEntity="Competitor" syncable="YES"/>
<relationship name="event" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="Event" inverseName="checkIn" inverseEntity="Event" syncable="YES"/>
<relationship name="gpsFixes" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="GPSFix" inverseName="checkIn" inverseEntity="GPSFix" syncable="YES"/>
<relationship name="leaderboard" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="Leaderboard" inverseName="checkIn" inverseEntity="Leaderboard" syncable="YES"/>
</entity>
<entity name="Competitor" representedClassName="Competitor" syncable="YES"> <entity name="Competitor" representedClassName="Competitor" syncable="YES">
<attribute name="boatClassName" optional="YES" attributeType="String" syncable="YES"/> <attribute name="boatClassName" attributeType="String" syncable="YES"/>
<attribute name="competitorID" attributeType="String" indexed="YES" syncable="YES"/> <attribute name="competitorID" attributeType="String" indexed="YES" syncable="YES"/>
<attribute name="countryCode" optional="YES" attributeType="String" syncable="YES"/> <attribute name="countryCode" attributeType="String" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/> <attribute name="name" attributeType="String" syncable="YES"/>
<attribute name="nationality" optional="YES" attributeType="String" syncable="YES"/> <attribute name="nationality" attributeType="String" syncable="YES"/>
<attribute name="sailID" optional="YES" attributeType="String" syncable="YES"/> <attribute name="sailID" attributeType="String" syncable="YES"/>
<relationship name="checkIn" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CheckIn" inverseName="competitor" inverseEntity="CheckIn" syncable="YES"/> <relationship name="regatta" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Regatta" inverseName="competitor" inverseEntity="Regatta" syncable="YES"/>
</entity> </entity>
<entity name="Event" representedClassName="Event" syncable="YES"> <entity name="Event" representedClassName="Event" syncable="YES">
<attribute name="endDate" optional="YES" attributeType="Date" syncable="YES"/> <attribute name="endDate" attributeType="Date" syncable="YES"/>
<attribute name="eventID" attributeType="String" indexed="YES" syncable="YES"/> <attribute name="eventID" attributeType="String" indexed="YES" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/> <attribute name="name" attributeType="String" syncable="YES"/>
<attribute name="startDate" optional="YES" attributeType="Date" syncable="YES"/> <attribute name="startDate" attributeType="Date" syncable="YES"/>
<relationship name="checkIn" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CheckIn" inverseName="event" inverseEntity="CheckIn" syncable="YES"/> <relationship name="regatta" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Regatta" inverseName="event" inverseEntity="Regatta" syncable="YES"/>
</entity> </entity>
<entity name="GPSFix" representedClassName="GPSFix" syncable="YES"> <entity name="GPSFix" representedClassName="GPSFix" syncable="YES">
<attribute name="course" attributeType="Double" defaultValueString="0.0" syncable="YES"/> <attribute name="course" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
@@ -36,17 +22,27 @@
<attribute name="longitude" attributeType="Double" defaultValueString="0.0" syncable="YES"/> <attribute name="longitude" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
<attribute name="speed" attributeType="Double" defaultValueString="0.0" syncable="YES"/> <attribute name="speed" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
<attribute name="timestamp" attributeType="Double" defaultValueString="0.0" syncable="YES"/> <attribute name="timestamp" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
<relationship name="checkIn" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CheckIn" inverseName="gpsFixes" inverseEntity="CheckIn" syncable="YES"/> <relationship name="regatta" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Regatta" inverseName="gpsFixes" inverseEntity="Regatta" syncable="YES"/>
</entity> </entity>
<entity name="Leaderboard" representedClassName="Leaderboard" syncable="YES"> <entity name="Leaderboard" representedClassName="Leaderboard" syncable="YES">
<attribute name="name" attributeType="String" indexed="YES" syncable="YES"/> <attribute name="name" attributeType="String" indexed="YES" syncable="YES"/>
<relationship name="checkIn" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CheckIn" inverseName="leaderboard" inverseEntity="CheckIn" syncable="YES"/> <relationship name="regatta" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Regatta" inverseName="leaderboard" inverseEntity="Regatta" syncable="YES"/>
</entity>
<entity name="Regatta" representedClassName="Regatta" syncable="YES">
<attribute name="serverURL" attributeType="String" syncable="YES"/>
<attribute name="teamImageData" optional="YES" attributeType="Binary" syncable="YES"/>
<attribute name="teamImageRetry" attributeType="Boolean" syncable="YES"/>
<attribute name="teamImageURL" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="competitor" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="Competitor" inverseName="regatta" inverseEntity="Competitor" syncable="YES"/>
<relationship name="event" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="Event" inverseName="regatta" inverseEntity="Event" syncable="YES"/>
<relationship name="gpsFixes" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="GPSFix" inverseName="regatta" inverseEntity="GPSFix" syncable="YES"/>
<relationship name="leaderboard" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="Leaderboard" inverseName="regatta" inverseEntity="Leaderboard" syncable="YES"/>
</entity> </entity>
<elements> <elements>
<element name="CheckIn" positionX="-36" positionY="90" width="128" height="225"/> <element name="Regatta" positionX="-36" positionY="90" width="128" height="165"/>
<element name="Competitor" positionX="-9" positionY="81" width="128" height="150"/> <element name="Competitor" positionX="-9" positionY="81" width="128" height="150"/>
<element name="Event" positionX="-63" positionY="27" width="128" height="120"/> <element name="Event" positionX="-63" positionY="27" width="128" height="120"/>
<element name="GPSFix" positionX="-63" positionY="-18" width="128" height="133"/> <element name="GPSFix" positionX="-63" positionY="-18" width="128" height="135"/>
<element name="Leaderboard" positionX="-36" positionY="72" width="128" height="75"/> <element name="Leaderboard" positionX="-36" positionY="72" width="128" height="75"/>
</elements> </elements>
</model> </model>
@@ -20,13 +20,13 @@ public class CoreDataManager: NSObject {
// MARK: - Fetch // MARK: - Fetch
func fetchCheckIn(eventID: String, func fetchRegatta(eventID: String,
leaderboardName: String, leaderboardName: String,
competitorID: String) -> CheckIn? competitorID: String) -> Regatta?
{ {
let fetchRequest = NSFetchRequest() let fetchRequest = NSFetchRequest()
fetchRequest.entity = NSEntityDescription.entityForName("CheckIn", inManagedObjectContext: managedObjectContext!) fetchRequest.entity = NSEntityDescription.entityForName("Regatta", inManagedObjectContext: managedObjectContext!)
fetchRequest.predicate = NSPredicate(format: "eventID = %@ AND leaderboardName = %@ AND competitorID = %@", fetchRequest.predicate = NSPredicate(format: "event.eventID = %@ AND leaderboard.name = %@ AND competitor.competitorID = %@",
eventID, eventID,
leaderboardName, leaderboardName,
competitorID) competitorID)
@@ -35,7 +35,7 @@ public class CoreDataManager: NSObject {
if results.count == 0 { if results.count == 0 {
return nil return nil
} else { } else {
return results[0] as? CheckIn return results[0] as? Regatta
} }
} catch { } catch {
print(error) print(error)
@@ -43,46 +43,46 @@ public class CoreDataManager: NSObject {
return nil return nil
} }
func checkInFetchedResultsController() -> NSFetchedResultsController { func regattaFetchedResultsController() -> NSFetchedResultsController {
let fetchRequest = NSFetchRequest(entityName: "CheckIn") let fetchRequest = NSFetchRequest(entityName: "Regatta")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "leaderboardName", ascending: true)] fetchRequest.sortDescriptors = [NSSortDescriptor(key: "leaderboard.name", ascending: true)]
return NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil) return NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
} }
// MARK: - Insert // MARK: - Insert
func newCheckIn() -> CheckIn { func newRegatta() -> Regatta {
return NSEntityDescription.insertNewObjectForEntityForName("CheckIn", inManagedObjectContext: managedObjectContext!) as! CheckIn return NSEntityDescription.insertNewObjectForEntityForName("Regatta", inManagedObjectContext: managedObjectContext!) as! Regatta
} }
func newEvent(checkIn: CheckIn) -> Event { func newEvent(regatta: Regatta) -> Event {
let event = NSEntityDescription.insertNewObjectForEntityForName("Event", inManagedObjectContext: managedObjectContext!) as! Event let event = NSEntityDescription.insertNewObjectForEntityForName("Event", inManagedObjectContext: managedObjectContext!) as! Event
event.checkIn = checkIn event.regatta = regatta
return event return event
} }
func newLeaderBoard(checkIn: CheckIn) -> Leaderboard { func newLeaderboard(regatta: Regatta) -> Leaderboard {
let leaderBoard = NSEntityDescription.insertNewObjectForEntityForName("Leaderboard", inManagedObjectContext: managedObjectContext!) as! Leaderboard let leaderboard = NSEntityDescription.insertNewObjectForEntityForName("Leaderboard", inManagedObjectContext: managedObjectContext!) as! Leaderboard
leaderBoard.checkIn = checkIn leaderboard.regatta = regatta
return leaderBoard return leaderboard
} }
func newCompetitor(checkIn: CheckIn) -> Competitor { func newCompetitor(regatta: Regatta) -> Competitor {
let competitor = NSEntityDescription.insertNewObjectForEntityForName("Competitor", inManagedObjectContext: managedObjectContext!) as! Competitor let competitor = NSEntityDescription.insertNewObjectForEntityForName("Competitor", inManagedObjectContext: managedObjectContext!) as! Competitor
competitor.checkIn = checkIn competitor.regatta = regatta
return competitor return competitor
} }
func newGPSFix(checkIn: CheckIn) -> GPSFix { func newGPSFix(regatta: Regatta) -> GPSFix {
let gpsFix = NSEntityDescription.insertNewObjectForEntityForName("GPSFix", inManagedObjectContext: managedObjectContext!) as! GPSFix let gpsFix = NSEntityDescription.insertNewObjectForEntityForName("GPSFix", inManagedObjectContext: managedObjectContext!) as! GPSFix
gpsFix.checkIn = checkIn gpsFix.regatta = regatta
return gpsFix return gpsFix
} }
// MARK: - Delete // MARK: - Delete
func deleteCheckIn(checkIn: CheckIn) { func deleteRegatta(regatta: Regatta) {
managedObjectContext!.deleteObject(checkIn) managedObjectContext!.deleteObject(regatta)
} }
func deleteGPSFixes(gpsFixes: [GPSFix]) { func deleteGPSFixes(gpsFixes: [GPSFix]) {
@@ -2,7 +2,7 @@
// Event+CoreDataProperties.swift // Event+CoreDataProperties.swift
// SAPTracker // SAPTracker
// //
// Created by Raimund Wege on 01.07.16. // Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved. // Copyright © 2016 com.sap.sailing. All rights reserved.
// //
// Choose "Create NSManagedObject Subclass…" from the Core Data editor menu // Choose "Create NSManagedObject Subclass…" from the Core Data editor menu
@@ -15,9 +15,9 @@ import CoreData
extension Event { extension Event {
@NSManaged var endDate: NSTimeInterval @NSManaged var endDate: NSTimeInterval
@NSManaged var eventID: String? @NSManaged var eventID: String
@NSManaged var name: String? @NSManaged var name: String
@NSManaged var startDate: NSTimeInterval @NSManaged var startDate: NSTimeInterval
@NSManaged var checkIn: CheckIn? @NSManaged var regatta: Regatta
} }
@@ -2,7 +2,7 @@
// Event.swift // Event.swift
// SAPTracker // SAPTracker
// //
// Created by Raimund Wege on 30.06.16. // Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved. // Copyright © 2016 com.sap.sailing. All rights reserved.
// //
@@ -2,7 +2,7 @@
// GPSFix+CoreDataProperties.swift // GPSFix+CoreDataProperties.swift
// SAPTracker // SAPTracker
// //
// Created by Raimund Wege on 01.07.16. // Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved. // Copyright © 2016 com.sap.sailing. All rights reserved.
// //
// Choose "Create NSManagedObject Subclass…" from the Core Data editor menu // Choose "Create NSManagedObject Subclass…" from the Core Data editor menu
@@ -19,6 +19,6 @@ extension GPSFix {
@NSManaged var longitude: Double @NSManaged var longitude: Double
@NSManaged var speed: Double @NSManaged var speed: Double
@NSManaged var timestamp: Double @NSManaged var timestamp: Double
@NSManaged var checkIn: CheckIn? @NSManaged var regatta: Regatta
} }
@@ -2,7 +2,7 @@
// GPSFix.swift // GPSFix.swift
// SAPTracker // SAPTracker
// //
// Created by Raimund Wege on 30.06.16. // Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved. // Copyright © 2016 com.sap.sailing. All rights reserved.
// //
@@ -17,23 +17,30 @@ class HomeViewController: UIViewController {
@IBOutlet weak var noCodeButton: UIButton! @IBOutlet weak var noCodeButton: UIButton!
@IBOutlet weak var infoCodeLabel: UILabel! @IBOutlet weak var infoCodeLabel: UILabel!
private var fetchedResultsController: NSFetchedResultsController?
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
setups()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
reviews()
subscribeForNewCheckInURLNotifications()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
unsubscribeFromNewCheckInURLNotifications()
}
// MARK: - Setups
private func setups() {
setupButtons() setupButtons()
setupLanguage() setupLanguage()
setupNavigationBar() setupNavigationBar()
setupTableViewDataSource() setupTableViewDataSource()
subscribeForNotifications()
checkEULA(NSNotification.init(name: "", object: nil))
} }
deinit {
self.unsubscribeForNotifications()
}
// MARK: - Setups
private func setupButtons() { private func setupButtons() {
scanCodeButton.setBackgroundImage(Images.BlueHighlighted, forState: .Highlighted) scanCodeButton.setBackgroundImage(Images.BlueHighlighted, forState: .Highlighted)
@@ -53,45 +60,66 @@ class HomeViewController: UIViewController {
} }
private func setupTableViewDataSource() { private func setupTableViewDataSource() {
fetchedResultsController = CoreDataManager.sharedManager.checkInFetchedResultsController()
fetchedResultsController!.delegate = self
do { do {
try fetchedResultsController!.performFetch() try fetchedResultsController.performFetch()
} catch { } catch {
print(error) print(error)
} }
} }
// MARK: - Reviews
func reviews() {
if !Preferences.termsAccepted {
reviewEULA()
} else {
reviewNewCheckIn()
}
}
func reviewEULA() {
let alertTitle = NSLocalizedString("EULA_title", comment: "")
let alertMessage = NSLocalizedString("EULA_content", comment: "")
let alertController = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .Alert)
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
})
let confirmTitle = NSLocalizedString("EULA_confirm", comment: "")
let confirmAction = UIAlertAction(title: confirmTitle, style: .Default, handler: { action in
Preferences.termsAccepted = true
self.reviewNewCheckIn()
})
alertController.addAction(viewAction)
alertController.addAction(confirmAction)
presentViewController(alertController, animated: true, completion: nil)
}
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)
}
// MARK: - Notifications // MARK: - Notifications
private func subscribeForNotifications() { private func subscribeForNewCheckInURLNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(HomeViewController.checkEULA(_:)), selector: #selector(HomeViewController.newCheckInURLNotification(_:)),
name: UIApplicationWillEnterForegroundNotification, name: Preferences.NotificationType.NewCheckInURLChanged,
object: nil) object: nil)
} }
private func unsubscribeForNotifications() { private func unsubscribeFromNewCheckInURLNotifications() {
NSNotificationCenter.defaultCenter().removeObserver(self) NSNotificationCenter.defaultCenter().removeObserver(self)
} }
func checkEULA(notification: NSNotification) { func newCheckInURLNotification(notification: NSNotification) {
if !Preferences.acceptedTerms { dispatch_async(dispatch_get_main_queue(), {
let alertTitle = NSLocalizedString("EULA_title", comment: "") self.reviewNewCheckIn()
let alertMessage = NSLocalizedString("EULA_content", comment: "") })
let alertController = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .Alert)
let viewTitle = NSLocalizedString("EULA_view", comment: "")
let viewAction = UIAlertAction(title: viewTitle, style: .Cancel, handler: { action in
UIApplication.sharedApplication().openURL(URLs.EULA)
})
let confirmTitle = NSLocalizedString("EULA_confirm", comment: "")
let confirmAction = UIAlertAction(title: confirmTitle, style: .Default, handler: { action in
Preferences.acceptedTerms = true
})
alertController.addAction(viewAction)
alertController.addAction(confirmAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
} }
// MARK: - Actions // MARK: - Actions
@@ -148,13 +176,28 @@ class HomeViewController: UIViewController {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.destinationViewController.isKindOfClass(RegattaViewController)) { if (segue.destinationViewController.isKindOfClass(RegattaViewController)) {
let regattaVC = segue.destinationViewController as! RegattaViewController guard let regattaVC = segue.destinationViewController as? RegattaViewController else { return }
let indexPath = self.tableView.indexPathForSelectedRow guard let indexPath = tableView.indexPathForSelectedRow else { return }
regattaVC.checkIn = self.fetchedResultsController?.objectAtIndexPath(indexPath!) as? CheckIn guard let regatta = fetchedResultsController.objectAtIndexPath(indexPath) as? Regatta else { return }
self.tableView.deselectRowAtIndexPath(indexPath!, animated: true) regattaVC.regatta = regatta
tableView.deselectRowAtIndexPath(indexPath, animated: true)
} }
} }
// MARK: - Properties
lazy var checkInController: CheckInController = {
let checkInController = CheckInController()
checkInController.delegate = self
return checkInController
}()
lazy var fetchedResultsController: NSFetchedResultsController = {
let fetchedResultsController = CoreDataManager.sharedManager.regattaFetchedResultsController()
fetchedResultsController.delegate = self
return fetchedResultsController
}()
} }
// MARK: - UITableViewDataSource // MARK: - UITableViewDataSource
@@ -162,18 +205,18 @@ class HomeViewController: UIViewController {
extension HomeViewController: UITableViewDataSource { extension HomeViewController: UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController!.sections![section].numberOfObjects return fetchedResultsController.sections?[section].numberOfObjects ?? 0
} }
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Regatta") as UITableViewCell! let cell = tableView.dequeueReusableCellWithIdentifier("Regatta") ?? UITableViewCell()
self.configureCell(cell, atIndexPath: indexPath) self.configureCell(cell, atIndexPath: indexPath)
return cell return cell
} }
func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) { func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
let checkIn = fetchedResultsController!.objectAtIndexPath(indexPath) as! CheckIn guard let regatta = fetchedResultsController.objectAtIndexPath(indexPath) as? Regatta else { return }
cell.textLabel?.text = checkIn.leaderboardName cell.textLabel?.text = regatta.leaderboard.name
} }
} }
@@ -224,3 +267,17 @@ extension HomeViewController: NSFetchedResultsControllerDelegate {
} }
} }
// MARK: - CheckInControllerDelegate
extension HomeViewController: CheckInControllerDelegate {
func showCheckInAlert(checkInController: CheckInController, alertController: UIAlertController) {
presentViewController(alertController, animated: true, completion: nil)
}
func checkInDidEnd(checkInController: CheckInController, withSuccess succeed: Bool) {
Preferences.newCheckInURL = nil
}
}
@@ -1,43 +0,0 @@
//
// LeaderBoardViewController.swift
// SAPTracker
//
// Created by computing on 08/12/14.
// Copyright (c) 2014 com.sap.sailing. All rights reserved.
//
import Foundation
class LeaderBoardViewController: UIViewController, UIWebViewDelegate, UIAlertViewDelegate {
weak var checkIn: CheckIn?
@IBOutlet weak var webView: UIWebView!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
let serverUrl = self.checkIn?.serverURL
let leaderboardName = self.checkIn?.leaderboardName?.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let url = "\(serverUrl)/gwt/Leaderboard.html?name=\(leaderboardName)&showRaceDetails=false&embedded=true&hideToolbar=true"
webView!.loadRequest(NSURLRequest(URL: NSURL(string: url)!))
}
@IBAction func done(sender: AnyObject) {
presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
func webViewDidFinishLoad(webView: UIWebView) {
activityIndicator.stopAnimating()
}
func wwebView(webView: UIWebView, didFailLoadWithError error: NSError) {
activityIndicator.hidden = true
let alertView = UIAlertView(title: NSLocalizedString("Couldn't load about view", comment: ""), message: nil, delegate: nil, cancelButtonTitle: NSLocalizedString("Cancel", comment: ""))
alertView.show()
}
func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
@@ -2,7 +2,7 @@
// Leaderboard+CoreDataProperties.swift // Leaderboard+CoreDataProperties.swift
// SAPTracker // SAPTracker
// //
// Created by Raimund Wege on 01.07.16. // Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved. // Copyright © 2016 com.sap.sailing. All rights reserved.
// //
// Choose "Create NSManagedObject Subclass…" from the Core Data editor menu // Choose "Create NSManagedObject Subclass…" from the Core Data editor menu
@@ -14,7 +14,7 @@ import CoreData
extension Leaderboard { extension Leaderboard {
@NSManaged var name: String? @NSManaged var name: String
@NSManaged var checkIn: CheckIn? @NSManaged var regatta: Regatta
} }
@@ -2,7 +2,7 @@
// Leaderboard.swift // Leaderboard.swift
// SAPTracker // SAPTracker
// //
// Created by Raimund Wege on 30.06.16. // Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved. // Copyright © 2016 com.sap.sailing. All rights reserved.
// //
@@ -12,6 +12,8 @@ import CoreData
@objc(Leaderboard) @objc(Leaderboard)
class Leaderboard: NSManagedObject { class Leaderboard: NSManagedObject {
// Insert code here to add functionality to your managed object subclass func nameWithQueryAllowedCharacters() -> String? {
return name.stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet())
}
} }
@@ -0,0 +1,59 @@
//
// LeaderboardViewController.swift
// SAPTracker
//
// Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved.
//
import Foundation
class LeaderboardViewController: UIViewController {
weak var regatta: Regatta?
@IBOutlet weak var webView: UIWebView!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
setupWebView()
}
// MARK: - Setups
private func setupWebView() {
guard let url = regatta?.leaderboardURL() else { return }
webView.loadRequest(NSURLRequest(URL: url))
}
// MARK: - Actions
@IBAction func doneButtonTapped(sender: AnyObject) {
presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
// MARK: - UIWebViewDelegate
extension LeaderboardViewController: UIWebViewDelegate {
func webViewDidFinishLoad(webView: UIWebView) {
activityIndicator.stopAnimating()
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError?) {
activityIndicator.stopAnimating()
// FIXME: - Translation
let alertTitle = NSLocalizedString("Couldn't load leaderboard view", 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.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
alertController.addAction(okAction)
presentViewController(alertController, animated: true, completion: nil)
}
}
@@ -10,35 +10,43 @@ import UIKit
class Preferences: NSObject { class Preferences: NSObject {
struct NotificationType {
static let NewCheckInURLChanged = "NewCheckInURLStringChanged"
}
struct PreferenceKey { struct PreferenceKey {
static let BatterySaving = "BatterySaving" static let BatterySaving = "BatterySaving"
static let LastCheckInURLString = "lastCheckInURLString" static let NewCheckInURL = "NewCheckInURL"
static let AcceptedTerms = "acceptedTerms" static let TermsAccepted = "TermsAccepted"
static let UUID = "udid" static let UUID = "udid"
} }
private static let preferences = NSUserDefaults.standardUserDefaults() private static let preferences = NSUserDefaults.standardUserDefaults()
// MARK: - LastCheckInData // MARK: - NewCheckInURL
class var lastCheckInURLString: String? { class var newCheckInURL: String? {
get { get {
return preferences.stringForKey(PreferenceKey.LastCheckInURLString) return preferences.stringForKey(PreferenceKey.NewCheckInURL)
} }
set(value) { set(value) {
preferences.setObject(value, forKey: PreferenceKey.LastCheckInURLString) preferences.setObject(value, forKey: PreferenceKey.NewCheckInURL)
preferences.synchronize() preferences.synchronize()
// Send notification
let notification = NSNotification(name: NotificationType.NewCheckInURLChanged, object: self)
NSNotificationQueue.defaultQueue().enqueueNotification(notification, postingStyle: NSPostingStyle.PostASAP)
} }
} }
// MARK: - AcceptedTerms // MARK: - TermsAccepted
class var acceptedTerms: Bool { class var termsAccepted: Bool {
get { get {
return preferences.boolForKey(PreferenceKey.AcceptedTerms) return preferences.boolForKey(PreferenceKey.TermsAccepted)
} }
set(value) { set(value) {
preferences.setBool(value, forKey:PreferenceKey.AcceptedTerms) preferences.setBool(value, forKey:PreferenceKey.TermsAccepted)
preferences.synchronize() preferences.synchronize()
} }
} }
@@ -1,8 +1,8 @@
// //
// CheckIn+CoreDataProperties.swift // Regatta+CoreDataProperties.swift
// SAPTracker // SAPTracker
// //
// Created by Raimund Wege on 01.07.16. // Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved. // Copyright © 2016 com.sap.sailing. All rights reserved.
// //
// Choose "Create NSManagedObject Subclass…" from the Core Data editor menu // Choose "Create NSManagedObject Subclass…" from the Core Data editor menu
@@ -12,19 +12,15 @@
import Foundation import Foundation
import CoreData import CoreData
extension CheckIn { extension Regatta {
@NSManaged var competitorID: String? @NSManaged var serverURL: String
@NSManaged var eventID: String?
@NSManaged var teamImageURL: String?
@NSManaged var lastSyncDate: NSTimeInterval
@NSManaged var leaderboardName: String?
@NSManaged var serverURL: String?
@NSManaged var teamImageData: NSData? @NSManaged var teamImageData: NSData?
@NSManaged var teamImageRetry: Bool @NSManaged var teamImageRetry: Bool
@NSManaged var competitor: Competitor? @NSManaged var teamImageURL: String?
@NSManaged var event: Event? @NSManaged var competitor: Competitor
@NSManaged var event: Event
@NSManaged var gpsFixes: NSSet? @NSManaged var gpsFixes: NSSet?
@NSManaged var leaderboard: Leaderboard? @NSManaged var leaderboard: Leaderboard
} }
@@ -0,0 +1,24 @@
//
// Regatta.swift
// SAPTracker
//
// Created by Raimund Wege on 04.07.16.
// Copyright © 2016 com.sap.sailing. All rights reserved.
//
import Foundation
import CoreData
@objc(Regatta)
class Regatta: NSManagedObject {
func eventURL() -> NSURL? {
return NSURL(string: "\(serverURL)/gwt/Home.html?navigationTab=Regattas#EventPlace:eventId=\(event.eventID)")
}
func leaderboardURL() -> NSURL? {
guard let name = leaderboard.nameWithQueryAllowedCharacters() else { return nil }
return NSURL(string: "\(serverURL)/gwt/Leaderboard.html?name=\(name)&showRaceDetails=false&embedded=true&hideToolbar=true")
}
}
@@ -37,17 +37,18 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate {
@IBOutlet weak var startTrackingButton: UIButton! @IBOutlet weak var startTrackingButton: UIButton!
@IBOutlet weak var announcementsLabel: UILabel! @IBOutlet weak var announcementsLabel: UILabel!
var checkIn: CheckIn! var regatta: Regatta!
var requestManager: RequestManager! var requestManager: RequestManager!
var countdownTimer: NSTimer? var countdownTimer: NSTimer?
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
requestManager = RequestManager(baseURLString: checkIn!.serverURL) requestManager = RequestManager(baseURLString: regatta.serverURL)
setupButtons() setupButtons()
setupCompetitor() setupCompetitor()
setupCountdownTimer() setupCountdownTimer()
setupNavigationBar()
setupImageSourceTypes() setupImageSourceTypes()
setupTeamImage() setupTeamImage()
} }
@@ -61,9 +62,9 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate {
} }
private func setupCompetitor() { private func setupCompetitor() {
competitorNameLabel.text = checkIn?.competitor?.name ?? "" competitorNameLabel.text = regatta.competitor.name
competitorFlagImageView.image = UIImage(named: checkIn?.competitor?.countryCode ?? "") competitorFlagImageView.image = UIImage(named: regatta.competitor.countryCode)
competitorSailLabel.text = checkIn?.competitor?.sailID ?? "" competitorSailLabel.text = regatta.competitor.sailID
} }
private func setupCountdownTimer() { private func setupCountdownTimer() {
@@ -87,11 +88,15 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate {
} }
} }
private func setupNavigationBar() {
navigationItem.title = regatta.leaderboard.name
}
private func setupTeamImage() { private func setupTeamImage() {
if checkIn.teamImageData != nil { if regatta.teamImageData != nil {
setupTeamImageWithImageData(checkIn.teamImageData) setupTeamImageWithImageData(regatta.teamImageData)
} else if checkIn.teamImageURL != nil { } else if regatta.teamImageURL != nil {
setupTeamImageWithURL(checkIn.teamImageURL) setupTeamImageWithURL(regatta.teamImageURL)
} else { } else {
setupTeamImageFinished() setupTeamImageFinished()
} }
@@ -115,20 +120,20 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate {
private func setupTeamImageWithURLSuccess(image: UIImage) { private func setupTeamImageWithURLSuccess(image: UIImage) {
teamImageView.image = image teamImageView.image = image
checkIn.teamImageData = UIImageJPEGRepresentation(image, 0.8) regatta.teamImageData = UIImageJPEGRepresentation(image, 0.8)
checkIn.teamImageRetry = false regatta.teamImageRetry = false
CoreDataManager.sharedManager.saveContext() CoreDataManager.sharedManager.saveContext()
setupTeamImageFinished() setupTeamImageFinished()
} }
private func setupTeamImageWithURLFailure() { private func setupTeamImageWithURLFailure() {
setupTeamImageFinished() setupTeamImageFinished()
} }
private func setupTeamImageFinished() { private func setupTeamImageFinished() {
if checkIn.teamImageData != nil { if regatta.teamImageData != nil {
teamImageAddButton.hidden = true teamImageAddButton.hidden = true
teamImageEditButton.hidden = checkIn.teamImageRetry teamImageEditButton.hidden = regatta.teamImageRetry
teamImageRetryButton.hidden = !teamImageEditButton.hidden teamImageRetryButton.hidden = !teamImageEditButton.hidden
} else { } else {
teamImageAddButton.hidden = false teamImageAddButton.hidden = false
@@ -140,23 +145,21 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate {
// MARK: - Refresh // MARK: - Refresh
func refreshCountdown() { func refreshCountdown() {
if let event = checkIn.event { if regatta.event.startDate - NSDate().timeIntervalSince1970 > 0 {
if event.startDate - NSDate().timeIntervalSince1970 > 0 { regattaStartLabel.text = NSLocalizedString("Regatta will start in", comment: "")
regattaStartLabel.text = NSLocalizedString("Regatta will start in", comment: "") let duration = regatta.event.startDate - NSDate().timeIntervalSince1970
let duration = event.startDate - NSDate().timeIntervalSince1970 let days = Int(duration / (60 * 60 * 24))
let days = Int(duration / (60 * 60 * 24)) let hours = Int(duration / (60 * 60)) - (days * 24)
let hours = Int(duration / (60 * 60)) - (days * 24) let minutes = Int(duration / 60) - (days * 24 * 60) - (hours * 60)
let minutes = Int(duration / 60) - (days * 24 * 60) - (hours * 60) countdownDaysLabel.text = String(format: "%02d", days)
countdownDaysLabel.text = String(format: "%02d", days) countdownHoursLabel.text = String(format: "%02d", hours)
countdownHoursLabel.text = String(format: "%02d", hours) countdownMinutesLabel.text = String(format: "%02d", minutes)
countdownMinutesLabel.text = String(format: "%02d", minutes) countdownView.hidden = false
countdownView.hidden = false countdownViewHeight.constant = 60
countdownViewHeight.constant = 60 } else {
} else { regattaStartLabel.text = NSLocalizedString("Regatta in progress", comment: "")
regattaStartLabel.text = NSLocalizedString("Regatta in progress", comment: "") countdownView.hidden = true
countdownView.hidden = true countdownViewHeight.constant = 0
countdownViewHeight.constant = 0
}
} }
} }
@@ -171,14 +174,12 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate {
} }
@IBAction func teamImageRetryButtonTapped(sender: AnyObject) { @IBAction func teamImageRetryButtonTapped(sender: AnyObject) {
postTeamImageData(checkIn.teamImageData) postTeamImageData(regatta.teamImageData)
} }
@IBAction func eventButtonTapped(sender: UIButton) { @IBAction func eventButtonTapped(sender: UIButton) {
let serverURL = checkIn.serverURL! // FIXME: - Alert?
let eventID = checkIn.eventID! guard let url = regatta.eventURL() else { return }
let urlString = "\(serverURL)/gwt/Home.html?navigationTab=Regattas#EventPlace:eventId=\(eventID)"
let url = NSURL(string: urlString)!
UIApplication.sharedApplication().openURL(url) UIApplication.sharedApplication().openURL(url)
} }
@@ -259,12 +260,12 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate {
} }
func preformCheckOut() { func preformCheckOut() {
requestManager.postCheckOut(checkIn.leaderboardName, requestManager.postCheckOut(regatta.leaderboard.name,
competitorId: checkIn.competitorID, competitorId: regatta.competitor.competitorID,
success: { (operation, responseObject) in }, success: { (operation, responseObject) in },
failure: { (operation, error) in failure: { (operation, error) in
}) })
CoreDataManager.sharedManager.deleteCheckIn(self.checkIn!) CoreDataManager.sharedManager.deleteRegatta(regatta!)
CoreDataManager.sharedManager.saveContext() CoreDataManager.sharedManager.saveContext()
navigationController!.popViewControllerAnimated(true) navigationController!.popViewControllerAnimated(true)
} }
@@ -275,7 +276,7 @@ class RegattaViewController : UIViewController, UINavigationControllerDelegate {
if (segue.identifier == "Tracking") { if (segue.identifier == "Tracking") {
let nc = segue.destinationViewController as! UINavigationController let nc = segue.destinationViewController as! UINavigationController
let vc = nc.viewControllers[0] as! TrackingViewController let vc = nc.viewControllers[0] as! TrackingViewController
vc.checkIn = checkIn vc.regatta = regatta
} }
} }
@@ -300,14 +301,14 @@ extension RegattaViewController: UIImagePickerControllerDelegate {
teamImageAddButton.hidden = true teamImageAddButton.hidden = true
teamImageEditButton.hidden = false teamImageEditButton.hidden = false
teamImageRetryButton.hidden = true teamImageRetryButton.hidden = true
checkIn.teamImageData = UIImageJPEGRepresentation(image, 0.8) regatta.teamImageData = UIImageJPEGRepresentation(image, 0.8)
CoreDataManager.sharedManager.saveContext() CoreDataManager.sharedManager.saveContext()
postTeamImageData(checkIn.teamImageData) postTeamImageData(regatta.teamImageData)
} }
private func postTeamImageData(imageData: NSData!) { private func postTeamImageData(imageData: NSData!) {
requestManager.postTeamImageData(imageData, requestManager.postTeamImageData(imageData,
competitorId: checkIn.competitorID, competitorId: regatta.competitor.competitorID,
success: { (responseObject) in self.postTeamImageSuccess(responseObject) }, success: { (responseObject) in self.postTeamImageSuccess(responseObject) },
failure: { (error) in self.postTeamImageFailure(error) }) failure: { (error) in self.postTeamImageFailure(error) })
} }
@@ -317,8 +318,8 @@ extension RegattaViewController: UIImagePickerControllerDelegate {
// Save image URL and upload success // Save image URL and upload success
let teamImageDictionary = responseObject as! [String: AnyObject] let teamImageDictionary = responseObject as! [String: AnyObject]
let teamImageURL = (teamImageDictionary[TeamImageKeys.TeamImageURL]) as! String let teamImageURL = (teamImageDictionary[TeamImageKeys.TeamImageURL]) as! String
checkIn.teamImageURL = teamImageURL regatta.teamImageURL = teamImageURL
checkIn.teamImageRetry = false regatta.teamImageRetry = false
CoreDataManager.sharedManager.saveContext() CoreDataManager.sharedManager.saveContext()
// Setup team image // Setup team image
@@ -328,7 +329,7 @@ extension RegattaViewController: UIImagePickerControllerDelegate {
private func postTeamImageFailure(error: AnyObject) { private func postTeamImageFailure(error: AnyObject) {
// Save image upload failure // Save image upload failure
checkIn.teamImageRetry = true regatta.teamImageRetry = true
CoreDataManager.sharedManager.saveContext() CoreDataManager.sharedManager.saveContext()
// Show alert // Show alert
@@ -36,11 +36,11 @@ class RequestManager: NSObject {
static let IOS = "iOS" static let IOS = "iOS"
} }
let baseURLString: String! let baseURLString: String
let manager: AFHTTPRequestOperationManager! let manager: AFHTTPRequestOperationManager
let sessionManager: AFURLSessionManager! let sessionManager: AFURLSessionManager
init(baseURLString: String!) { init(baseURLString: String = "") {
self.baseURLString = baseURLString self.baseURLString = baseURLString
manager = AFHTTPRequestOperationManager(baseURL: NSURL(string: baseURLString)) manager = AFHTTPRequestOperationManager(baseURL: NSURL(string: baseURLString))
manager.requestSerializer = AFJSONRequestSerializer() as AFHTTPRequestSerializer manager.requestSerializer = AFJSONRequestSerializer() as AFHTTPRequestSerializer
@@ -54,7 +54,8 @@ class RequestManager: NSObject {
func getEvent(eventID: String!, func getEvent(eventID: String!,
success: (AFHTTPRequestOperation!, AnyObject!) -> Void, success: (AFHTTPRequestOperation!, AnyObject!) -> Void,
failure: (AFHTTPRequestOperation!, AnyObject!) -> Void) { failure: (AFHTTPRequestOperation!, AnyObject!) -> Void)
{
let encodedEventID = eventID.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLPathAllowedCharacterSet()) ?? "" let encodedEventID = eventID.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLPathAllowedCharacterSet()) ?? ""
let urlString = "\(basePathString)/events/\(encodedEventID)" let urlString = "\(basePathString)/events/\(encodedEventID)"
manager.GET(urlString, parameters: nil, success: success, failure: failure) manager.GET(urlString, parameters: nil, success: success, failure: failure)
@@ -13,8 +13,8 @@ class ScanViewController: UIViewController {
@IBOutlet weak var previewView: UIView! @IBOutlet weak var previewView: UIView!
@IBOutlet weak var targetImageView: UIImageView! @IBOutlet weak var targetImageView: UIImageView!
private var checkInController: CheckInController? private let checkInController = CheckInController()
private var session: AVCaptureSession! private var session: AVCaptureSession!
private var output: AVCaptureMetadataOutput! private var output: AVCaptureMetadataOutput!
@@ -22,36 +22,41 @@ class ScanViewController: UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
self.setupSession() setupCheckInController()
setupSession()
} }
override func viewWillAppear(animated: Bool) { override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
self.startScanning() startScanning()
} }
// MARK: - Setups // MARK: - Setups
private func setupCheckInController() {
checkInController.delegate = self
}
private func setupSession() { private func setupSession() {
self.session = AVCaptureSession() session = AVCaptureSession()
self.output = AVCaptureMetadataOutput() output = AVCaptureMetadataOutput()
do { do {
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
let input = try AVCaptureDeviceInput(device: device); let input = try AVCaptureDeviceInput(device: device);
self.output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
self.session.canSetSessionPreset(AVCaptureSessionPresetHigh) session.canSetSessionPreset(AVCaptureSessionPresetHigh)
if session.canAddInput(input) { if session.canAddInput(input) {
session.addInput(input) session.addInput(input)
} }
if session.canAddOutput(output) { if session.canAddOutput(output) {
session.addOutput(output) session.addOutput(output)
} }
self.output.metadataObjectTypes = [AVMetadataObjectTypeQRCode] output.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
self.previewLayer = AVCaptureVideoPreviewLayer(session: self.session) previewLayer = AVCaptureVideoPreviewLayer(session: self.session)
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
self.previewLayer.frame = previewView.bounds previewLayer.frame = previewView.bounds
self.previewLayer.position = CGPointMake(CGRectGetMidX(previewView.bounds), CGRectGetMidY(previewView.bounds)) previewLayer.position = CGPointMake(CGRectGetMidX(previewView.bounds), CGRectGetMidY(previewView.bounds))
self.previewView.layer.addSublayer(previewLayer) previewView.layer.addSublayer(previewLayer)
} catch { } catch {
print(error) print(error)
} }
@@ -75,14 +80,14 @@ class ScanViewController: UIViewController {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.session.startRunning() self.session.startRunning()
}) })
self.targetImageView.image = UIImage(named: "scan_white") targetImageView.image = UIImage(named: "scan_white")
} }
private func stopScanning() { private func stopScanning() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.session.stopRunning() self.session.stopRunning()
}) })
self.targetImageView.image = UIImage(named: "scan_green") targetImageView.image = UIImage(named: "scan_green")
} }
} }
@@ -97,9 +102,9 @@ extension ScanViewController: CheckInControllerDelegate {
func checkInDidEnd(checkInController: CheckInController, withSuccess succeed: Bool) { func checkInDidEnd(checkInController: CheckInController, withSuccess succeed: Bool) {
if succeed { if succeed {
self.navigationController?.popViewControllerAnimated(true) navigationController?.popViewControllerAnimated(true)
} else { } else {
self.startScanning() startScanning()
} }
} }
@@ -116,9 +121,8 @@ extension ScanViewController: AVCaptureMetadataOutputObjectsDelegate {
if metadataObjects.count > 0 { if metadataObjects.count > 0 {
let metadataObject: AVMetadataMachineReadableCodeObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject let metadataObject: AVMetadataMachineReadableCodeObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
if let checkInData = CheckInData(urlString: metadataObject.stringValue) { if let checkInData = CheckInData(urlString: metadataObject.stringValue) {
self.stopScanning() stopScanning()
checkInController = CheckInController(checkInData: checkInData, delegate: self) checkInController.startCheckIn(checkInData)
checkInController!.startCheckIn()
} else { } else {
let alertTitle = NSLocalizedString("Incorrect QR Code", comment: "") let alertTitle = NSLocalizedString("Incorrect QR Code", comment: "")
let alertController = UIAlertController(title: alertTitle, message: "", preferredStyle: .Alert) let alertController = UIAlertController(title: alertTitle, message: "", preferredStyle: .Alert)
@@ -15,14 +15,14 @@ class SendGPSFixesController: NSObject {
static let BatterySaving: NSTimeInterval = 30 static let BatterySaving: NSTimeInterval = 30
} }
private let checkIn: CheckIn! private let regatta: Regatta!
private let requestManager: RequestManager! private let requestManager: RequestManager!
private var isRunning: Bool = false private var isRunning: Bool = false
init(checkIn: CheckIn) { init(regatta: Regatta) {
self.checkIn = checkIn self.regatta = regatta
requestManager = RequestManager(baseURLString: checkIn.serverURL) requestManager = RequestManager(baseURLString: regatta.serverURL)
super.init() super.init()
} }
@@ -47,7 +47,7 @@ class SendGPSFixesController: NSObject {
dispatch_async(dispatch_get_main_queue(), { dispatch_async(dispatch_get_main_queue(), {
if let userInfo = notification.userInfo { if let userInfo = notification.userInfo {
if userInfo[LocationManager.UserInfo.IsValid] as? Bool ?? false { if userInfo[LocationManager.UserInfo.IsValid] as? Bool ?? false {
let gpsFix = CoreDataManager.sharedManager.newGPSFix(self.checkIn) let gpsFix = CoreDataManager.sharedManager.newGPSFix(self.regatta)
gpsFix.course = userInfo[LocationManager.UserInfo.Course] as! Double gpsFix.course = userInfo[LocationManager.UserInfo.Course] as! Double
gpsFix.latitude = userInfo[LocationManager.UserInfo.Latitude] as! Double gpsFix.latitude = userInfo[LocationManager.UserInfo.Latitude] as! Double
gpsFix.longitude = userInfo[LocationManager.UserInfo.Longitude] as! Double gpsFix.longitude = userInfo[LocationManager.UserInfo.Longitude] as! Double
@@ -72,10 +72,8 @@ class SendGPSFixesController: NSObject {
func sendGPSFixes() { func sendGPSFixes() {
var gpsFixes = [GPSFix]() var gpsFixes = [GPSFix]()
if checkIn.gpsFixes != nil { if regatta.gpsFixes != nil {
checkIn.gpsFixes!.forEach { (gpsFix) in regatta.gpsFixes!.forEach { (gpsFix) in gpsFixes.append(gpsFix as! GPSFix) }
gpsFixes.append(gpsFix as! GPSFix)
}
} }
if gpsFixes.count > 0 { if gpsFixes.count > 0 {
log("\(gpsFixes.count) GPS fixes will be sent") log("\(gpsFixes.count) GPS fixes will be sent")
@@ -10,7 +10,7 @@ import Foundation
class TrackingViewController : UIViewController { class TrackingViewController : UIViewController {
var checkIn: CheckIn? var regatta: Regatta?
@IBOutlet weak var tableView: UITableView! @IBOutlet weak var tableView: UITableView!
@IBOutlet weak var tableViewHeight: NSLayoutConstraint! @IBOutlet weak var tableViewHeight: NSLayoutConstraint!
@@ -18,8 +18,7 @@ class TrackingViewController : UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
setupButtons() setups()
setupNavigationBarTitle()
} }
override func updateViewConstraints() { override func updateViewConstraints() {
@@ -29,12 +28,17 @@ class TrackingViewController : UIViewController {
// MARK: - Setups // MARK: - Setups
private func setups() {
setupButtons()
setupNavigationBar()
}
private func setupButtons() { private func setupButtons() {
stopTrackingButton.setBackgroundImage(Images.RedHighlighted, forState: .Highlighted) stopTrackingButton.setBackgroundImage(Images.RedHighlighted, forState: .Highlighted)
} }
private func setupNavigationBarTitle() { private func setupNavigationBar() {
navigationItem.title = checkIn?.leaderboardName navigationItem.title = regatta?.leaderboard.name
} }
// MARK: - Actions // MARK: - Actions
@@ -85,7 +89,7 @@ extension TrackingViewController: UITableViewDataSource {
let cell = tableView.dequeueReusableCellWithIdentifier(TrackingViewController.Rows[indexPath.row]) ?? UITableViewCell() let cell = tableView.dequeueReusableCellWithIdentifier(TrackingViewController.Rows[indexPath.row]) ?? UITableViewCell()
if (cell.isKindOfClass(CachedFixesTrackingTableViewCell)) { if (cell.isKindOfClass(CachedFixesTrackingTableViewCell)) {
let cachedFixesCell = cell as! CachedFixesTrackingTableViewCell let cachedFixesCell = cell as! CachedFixesTrackingTableViewCell
cachedFixesCell.checkIn = checkIn cachedFixesCell.regatta = regatta
} }
return cell return cell
} }