diff --git a/Time/Time/Base.lproj/LaunchScreen.xib b/Time/LaunchScreen.xib similarity index 57% rename from Time/Time/Base.lproj/LaunchScreen.xib rename to Time/LaunchScreen.xib index f9a54ff..d6289f3 100644 --- a/Time/Time/Base.lproj/LaunchScreen.xib +++ b/Time/LaunchScreen.xib @@ -1,7 +1,7 @@ - + - + @@ -11,26 +11,17 @@ - - + - - - diff --git a/Time/Main.storyboard b/Time/Main.storyboard new file mode 100644 index 0000000..961e8d8 --- /dev/null +++ b/Time/Main.storyboard @@ -0,0 +1,633 @@ + + + + + + + + + + DigitalReadoutExpUpright + DigitalReadoutExpUpright + DigitalReadoutExpUpright + + + Orbitron-Regular + Orbitron-Regular + Orbitron-Regular + Orbitron-Regular + Orbitron-Regular + Orbitron-Regular + Orbitron-Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Time/Time.xcodeproj/project.pbxproj b/Time/Time.xcodeproj/project.pbxproj index c8743f0..9889eff 100644 --- a/Time/Time.xcodeproj/project.pbxproj +++ b/Time/Time.xcodeproj/project.pbxproj @@ -7,13 +7,36 @@ objects = { /* Begin PBXBuildFile section */ + 3B1CB4F71B956659001E2475 /* PIDatePickerComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1CB4F61B956659001E2475 /* PIDatePickerComponents.swift */; }; + 3B1CB4F91B956664001E2475 /* PIDatePickerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1CB4F81B956664001E2475 /* PIDatePickerDelegate.swift */; }; + 3B1CB5051B95DC4C001E2475 /* PIDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1CB5041B95DC4C001E2475 /* PIDatePicker.swift */; }; + 3B6AD0911B8916510091587F /* Orbitron-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 3B6AD08D1B8916510091587F /* Orbitron-Black.ttf */; }; + 3B6AD0921B8916510091587F /* Orbitron-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 3B6AD08E1B8916510091587F /* Orbitron-Bold.ttf */; }; + 3B6AD0931B8916510091587F /* Orbitron-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 3B6AD08F1B8916510091587F /* Orbitron-Medium.ttf */; }; + 3B6AD0941B8916510091587F /* Orbitron-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 3B6AD0901B8916510091587F /* Orbitron-Regular.ttf */; }; + 3B6AD0971B891F7A0091587F /* TimerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6AD0961B891F7A0091587F /* TimerViewController.m */; }; + 3B6AD09A1B8A1CC40091587F /* PresetsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6AD0991B8A1CC40091587F /* PresetsTableViewController.m */; }; + 3B6AD0A01B8A22CB0091587F /* OrderedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6AD09F1B8A22CB0091587F /* OrderedDictionary.m */; }; + 3B6AD0A71B8A5A970091587F /* NewPresetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6AD0A61B8A5A970091587F /* NewPresetViewController.m */; }; + 3B6AD18B1B8D2F9F0091587F /* LapTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6AD18A1B8D2F9F0091587F /* LapTableViewController.m */; }; + 3B6AD1C21B8FD48A0091587F /* DateCountdownTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6AD1C11B8FD48A0091587F /* DateCountdownTableViewController.m */; }; + 3B6AD1C51B91FB7D0091587F /* NewEventViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6AD1C41B91FB7D0091587F /* NewEventViewController.m */; }; + 3B6AD2121B938E4F0091587F /* DataSingleton.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6AD2111B938E4F0091587F /* DataSingleton.m */; }; 8D05375E1B86687C00588318 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D05375D1B86687C00588318 /* main.m */; }; 8D0537611B86687C00588318 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D0537601B86687C00588318 /* AppDelegate.m */; }; - 8D0537641B86687C00588318 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D0537631B86687C00588318 /* ViewController.m */; }; - 8D0537671B86687C00588318 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D0537651B86687C00588318 /* Main.storyboard */; }; 8D0537691B86687C00588318 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8D0537681B86687C00588318 /* Images.xcassets */; }; - 8D05376C1B86687C00588318 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8D05376A1B86687C00588318 /* LaunchScreen.xib */; }; 8D0537781B86687C00588318 /* TimeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D0537771B86687C00588318 /* TimeTests.m */; }; + DC071E081B96154100798A0B /* LaunchScreen.xib in Sources */ = {isa = PBXBuildFile; fileRef = DC071E071B96154100798A0B /* LaunchScreen.xib */; }; + DC071E0A1B96157000798A0B /* Main.storyboard in Sources */ = {isa = PBXBuildFile; fileRef = DC071E091B96157000798A0B /* Main.storyboard */; }; + DC7C33FF1B88C2B40051C061 /* StopwatchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DC7C33FE1B88C2B40051C061 /* StopwatchViewController.m */; }; + DC7C34111B8905950051C061 /* Digir___.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DC7C34091B8905950051C061 /* Digir___.ttf */; }; + DC7C34121B8905950051C061 /* Digirc__.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DC7C340A1B8905950051C061 /* Digirc__.ttf */; }; + DC7C34131B8905950051C061 /* Digircu_.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DC7C340B1B8905950051C061 /* Digircu_.ttf */; }; + DC7C34141B8905950051C061 /* Digire__.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DC7C340C1B8905950051C061 /* Digire__.ttf */; }; + DC7C34151B8905950051C061 /* Digireu_.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DC7C340D1B8905950051C061 /* Digireu_.ttf */; }; + DC7C34161B8905950051C061 /* DIGIRT__.TTF in Resources */ = {isa = PBXBuildFile; fileRef = DC7C340E1B8905950051C061 /* DIGIRT__.TTF */; }; + DC7C34171B8905950051C061 /* Digirtu_.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DC7C340F1B8905950051C061 /* Digirtu_.ttf */; }; + DC7C34181B8905950051C061 /* DIGIRU__.TTF in Resources */ = {isa = PBXBuildFile; fileRef = DC7C34101B8905950051C061 /* DIGIRU__.TTF */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -27,19 +50,55 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 3B1CB4F31B95664F001E2475 /* Time-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Time-Bridging-Header.h"; sourceTree = ""; }; + 3B1CB4F61B956659001E2475 /* PIDatePickerComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PIDatePickerComponents.swift; sourceTree = ""; }; + 3B1CB4F81B956664001E2475 /* PIDatePickerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PIDatePickerDelegate.swift; sourceTree = ""; }; + 3B1CB5041B95DC4C001E2475 /* PIDatePicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PIDatePicker.swift; sourceTree = ""; }; + 3B6AD08D1B8916510091587F /* Orbitron-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Orbitron-Black.ttf"; sourceTree = ""; }; + 3B6AD08E1B8916510091587F /* Orbitron-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Orbitron-Bold.ttf"; sourceTree = ""; }; + 3B6AD08F1B8916510091587F /* Orbitron-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Orbitron-Medium.ttf"; sourceTree = ""; }; + 3B6AD0901B8916510091587F /* Orbitron-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Orbitron-Regular.ttf"; sourceTree = ""; }; + 3B6AD0951B891F7A0091587F /* TimerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimerViewController.h; sourceTree = ""; }; + 3B6AD0961B891F7A0091587F /* TimerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TimerViewController.m; sourceTree = ""; }; + 3B6AD0981B8A1CC40091587F /* PresetsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PresetsTableViewController.h; sourceTree = ""; }; + 3B6AD0991B8A1CC40091587F /* PresetsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PresetsTableViewController.m; sourceTree = ""; }; + 3B6AD09E1B8A22CB0091587F /* OrderedDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OrderedDictionary.h; sourceTree = ""; }; + 3B6AD09F1B8A22CB0091587F /* OrderedDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OrderedDictionary.m; sourceTree = ""; }; + 3B6AD0A11B8A43900091587F /* PresetsTableViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PresetsTableViewControllerDelegate.h; sourceTree = ""; }; + 3B6AD0A51B8A5A970091587F /* NewPresetViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewPresetViewController.h; sourceTree = ""; }; + 3B6AD0A61B8A5A970091587F /* NewPresetViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewPresetViewController.m; sourceTree = ""; }; + 3B6AD0A81B8A69670091587F /* NewPresetViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewPresetViewControllerDelegate.h; sourceTree = ""; }; + 3B6AD1891B8D2F9F0091587F /* LapTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LapTableViewController.h; sourceTree = ""; }; + 3B6AD18A1B8D2F9F0091587F /* LapTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LapTableViewController.m; sourceTree = ""; }; + 3B6AD1C01B8FD48A0091587F /* DateCountdownTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateCountdownTableViewController.h; sourceTree = ""; }; + 3B6AD1C11B8FD48A0091587F /* DateCountdownTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateCountdownTableViewController.m; sourceTree = ""; }; + 3B6AD1C31B91FB7D0091587F /* NewEventViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewEventViewController.h; sourceTree = ""; }; + 3B6AD1C41B91FB7D0091587F /* NewEventViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewEventViewController.m; sourceTree = ""; }; + 3B6AD1C61B920C6C0091587F /* NewEventViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewEventViewControllerDelegate.h; sourceTree = ""; }; + 3B6AD2101B938E4F0091587F /* DataSingleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataSingleton.h; sourceTree = ""; }; + 3B6AD2111B938E4F0091587F /* DataSingleton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataSingleton.m; sourceTree = ""; }; 8D0537581B86687B00588318 /* Time.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Time.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8D05375C1B86687B00588318 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D05375D1B86687C00588318 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 8D05375F1B86687C00588318 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 8D0537601B86687C00588318 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 8D0537621B86687C00588318 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; - 8D0537631B86687C00588318 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; - 8D0537661B86687C00588318 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 8D0537681B86687C00588318 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 8D05376B1B86687C00588318 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 8D0537711B86687C00588318 /* TimeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TimeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8D0537761B86687C00588318 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D0537771B86687C00588318 /* TimeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TimeTests.m; sourceTree = ""; }; + DC071E071B96154100798A0B /* LaunchScreen.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; + DC071E091B96157000798A0B /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; + DC256CD41B8EB50E00EC60C6 /* StopWatchViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StopWatchViewControllerDelegate.h; sourceTree = ""; }; + DC7C33FD1B88C2B40051C061 /* StopwatchViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StopwatchViewController.h; sourceTree = ""; }; + DC7C33FE1B88C2B40051C061 /* StopwatchViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StopwatchViewController.m; sourceTree = ""; }; + DC7C34091B8905950051C061 /* Digir___.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Digir___.ttf"; path = "../../../../../../../Downloads/digreadout/Digir___.ttf"; sourceTree = ""; }; + DC7C340A1B8905950051C061 /* Digirc__.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Digirc__.ttf; path = ../../../../../../../Downloads/digreadout/Digirc__.ttf; sourceTree = ""; }; + DC7C340B1B8905950051C061 /* Digircu_.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Digircu_.ttf; path = ../../../../../../../Downloads/digreadout/Digircu_.ttf; sourceTree = ""; }; + DC7C340C1B8905950051C061 /* Digire__.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Digire__.ttf; path = ../../../../../../../Downloads/digreadout/Digire__.ttf; sourceTree = ""; }; + DC7C340D1B8905950051C061 /* Digireu_.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Digireu_.ttf; path = ../../../../../../../Downloads/digreadout/Digireu_.ttf; sourceTree = ""; }; + DC7C340E1B8905950051C061 /* DIGIRT__.TTF */ = {isa = PBXFileReference; lastKnownFileType = file; name = DIGIRT__.TTF; path = ../../../../../../../Downloads/digreadout/DIGIRT__.TTF; sourceTree = ""; }; + DC7C340F1B8905950051C061 /* Digirtu_.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Digirtu_.ttf; path = ../../../../../../../Downloads/digreadout/Digirtu_.ttf; sourceTree = ""; }; + DC7C34101B8905950051C061 /* DIGIRU__.TTF */ = {isa = PBXFileReference; lastKnownFileType = file; name = DIGIRU__.TTF; path = ../../../../../../../Downloads/digreadout/DIGIRU__.TTF; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -60,9 +119,50 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 3B6AD1BC1B8D47A80091587F /* StopWatch */ = { + isa = PBXGroup; + children = ( + DC7C33FD1B88C2B40051C061 /* StopwatchViewController.h */, + DC7C33FE1B88C2B40051C061 /* StopwatchViewController.m */, + DC256CD41B8EB50E00EC60C6 /* StopWatchViewControllerDelegate.h */, + 3B6AD1891B8D2F9F0091587F /* LapTableViewController.h */, + 3B6AD18A1B8D2F9F0091587F /* LapTableViewController.m */, + ); + name = StopWatch; + sourceTree = ""; + }; + 3B6AD1BE1B8D47ED0091587F /* Timer */ = { + isa = PBXGroup; + children = ( + 3B6AD0951B891F7A0091587F /* TimerViewController.h */, + 3B6AD0961B891F7A0091587F /* TimerViewController.m */, + 3B6AD0981B8A1CC40091587F /* PresetsTableViewController.h */, + 3B6AD0991B8A1CC40091587F /* PresetsTableViewController.m */, + 3B6AD0A11B8A43900091587F /* PresetsTableViewControllerDelegate.h */, + 3B6AD0A51B8A5A970091587F /* NewPresetViewController.h */, + 3B6AD0A61B8A5A970091587F /* NewPresetViewController.m */, + 3B6AD0A81B8A69670091587F /* NewPresetViewControllerDelegate.h */, + ); + name = Timer; + sourceTree = ""; + }; + 3B6AD1BF1B8D52BC0091587F /* DateCountdown */ = { + isa = PBXGroup; + children = ( + 3B6AD1C01B8FD48A0091587F /* DateCountdownTableViewController.h */, + 3B6AD1C11B8FD48A0091587F /* DateCountdownTableViewController.m */, + 3B6AD1C31B91FB7D0091587F /* NewEventViewController.h */, + 3B6AD1C41B91FB7D0091587F /* NewEventViewController.m */, + 3B6AD1C61B920C6C0091587F /* NewEventViewControllerDelegate.h */, + ); + name = DateCountdown; + sourceTree = ""; + }; 8D05374F1B86687B00588318 = { isa = PBXGroup; children = ( + DC071E091B96157000798A0B /* Main.storyboard */, + DC071E071B96154100798A0B /* LaunchScreen.xib */, 8D05375A1B86687B00588318 /* Time */, 8D0537741B86687C00588318 /* TimeTests */, 8D0537591B86687B00588318 /* Products */, @@ -83,12 +183,20 @@ children = ( 8D05375F1B86687C00588318 /* AppDelegate.h */, 8D0537601B86687C00588318 /* AppDelegate.m */, - 8D0537621B86687C00588318 /* ViewController.h */, - 8D0537631B86687C00588318 /* ViewController.m */, - 8D0537651B86687C00588318 /* Main.storyboard */, + 3B6AD09E1B8A22CB0091587F /* OrderedDictionary.h */, + 3B6AD09F1B8A22CB0091587F /* OrderedDictionary.m */, + 3B1CB5041B95DC4C001E2475 /* PIDatePicker.swift */, + 3B1CB4F81B956664001E2475 /* PIDatePickerDelegate.swift */, + 3B1CB4F61B956659001E2475 /* PIDatePickerComponents.swift */, + 3B6AD2101B938E4F0091587F /* DataSingleton.h */, + 3B6AD2111B938E4F0091587F /* DataSingleton.m */, + 3B6AD1BF1B8D52BC0091587F /* DateCountdown */, + 3B6AD1BC1B8D47A80091587F /* StopWatch */, + 3B6AD1BE1B8D47ED0091587F /* Timer */, + DC7C34001B8904400051C061 /* Fonts */, 8D0537681B86687C00588318 /* Images.xcassets */, - 8D05376A1B86687C00588318 /* LaunchScreen.xib */, 8D05375B1B86687B00588318 /* Supporting Files */, + 3B1CB4F31B95664F001E2475 /* Time-Bridging-Header.h */, ); path = Time; sourceTree = ""; @@ -119,6 +227,25 @@ name = "Supporting Files"; sourceTree = ""; }; + DC7C34001B8904400051C061 /* Fonts */ = { + isa = PBXGroup; + children = ( + DC7C34091B8905950051C061 /* Digir___.ttf */, + DC7C340A1B8905950051C061 /* Digirc__.ttf */, + DC7C340B1B8905950051C061 /* Digircu_.ttf */, + DC7C340C1B8905950051C061 /* Digire__.ttf */, + DC7C340D1B8905950051C061 /* Digireu_.ttf */, + DC7C340E1B8905950051C061 /* DIGIRT__.TTF */, + DC7C340F1B8905950051C061 /* Digirtu_.ttf */, + DC7C34101B8905950051C061 /* DIGIRU__.TTF */, + 3B6AD08D1B8916510091587F /* Orbitron-Black.ttf */, + 3B6AD08E1B8916510091587F /* Orbitron-Bold.ttf */, + 3B6AD08F1B8916510091587F /* Orbitron-Medium.ttf */, + 3B6AD0901B8916510091587F /* Orbitron-Regular.ttf */, + ); + name = Fonts; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -168,6 +295,7 @@ TargetAttributes = { 8D0537571B86687B00588318 = { CreatedOnToolsVersion = 6.4; + DevelopmentTeam = BULEKXRKSR; }; 8D0537701B86687C00588318 = { CreatedOnToolsVersion = 6.4; @@ -199,8 +327,18 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8D0537671B86687C00588318 /* Main.storyboard in Resources */, - 8D05376C1B86687C00588318 /* LaunchScreen.xib in Resources */, + DC7C34151B8905950051C061 /* Digireu_.ttf in Resources */, + DC7C34141B8905950051C061 /* Digire__.ttf in Resources */, + DC7C34171B8905950051C061 /* Digirtu_.ttf in Resources */, + 3B6AD0911B8916510091587F /* Orbitron-Black.ttf in Resources */, + DC7C34161B8905950051C061 /* DIGIRT__.TTF in Resources */, + DC7C34121B8905950051C061 /* Digirc__.ttf in Resources */, + DC7C34111B8905950051C061 /* Digir___.ttf in Resources */, + DC7C34131B8905950051C061 /* Digircu_.ttf in Resources */, + DC7C34181B8905950051C061 /* DIGIRU__.TTF in Resources */, + 3B6AD0921B8916510091587F /* Orbitron-Bold.ttf in Resources */, + 3B6AD0941B8916510091587F /* Orbitron-Regular.ttf in Resources */, + 3B6AD0931B8916510091587F /* Orbitron-Medium.ttf in Resources */, 8D0537691B86687C00588318 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -219,9 +357,22 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8D0537641B86687C00588318 /* ViewController.m in Sources */, + 3B1CB5051B95DC4C001E2475 /* PIDatePicker.swift in Sources */, + 3B6AD0971B891F7A0091587F /* TimerViewController.m in Sources */, + 3B6AD2121B938E4F0091587F /* DataSingleton.m in Sources */, + 3B6AD1C21B8FD48A0091587F /* DateCountdownTableViewController.m in Sources */, 8D0537611B86687C00588318 /* AppDelegate.m in Sources */, 8D05375E1B86687C00588318 /* main.m in Sources */, + 3B6AD0A01B8A22CB0091587F /* OrderedDictionary.m in Sources */, + DC7C33FF1B88C2B40051C061 /* StopwatchViewController.m in Sources */, + 3B6AD1C51B91FB7D0091587F /* NewEventViewController.m in Sources */, + 3B1CB4F71B956659001E2475 /* PIDatePickerComponents.swift in Sources */, + DC071E0A1B96157000798A0B /* Main.storyboard in Sources */, + 3B6AD0A71B8A5A970091587F /* NewPresetViewController.m in Sources */, + 3B1CB4F91B956664001E2475 /* PIDatePickerDelegate.swift in Sources */, + DC071E081B96154100798A0B /* LaunchScreen.xib in Sources */, + 3B6AD09A1B8A1CC40091587F /* PresetsTableViewController.m in Sources */, + 3B6AD18B1B8D2F9F0091587F /* LapTableViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -243,25 +394,6 @@ }; /* End PBXTargetDependency section */ -/* Begin PBXVariantGroup section */ - 8D0537651B86687C00588318 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 8D0537661B86687C00588318 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 8D05376A1B86687C00588318 /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 8D05376B1B86687C00588318 /* Base */, - ); - name = LaunchScreen.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ 8D0537791B86687C00588318 /* Debug */ = { isa = XCBuildConfiguration; @@ -349,9 +481,16 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = Time/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Time/Time-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; @@ -359,9 +498,15 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = Time/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Time/Time-Bridging-Header.h"; }; name = Release; }; @@ -418,6 +563,7 @@ 8D05377D1B86687C00588318 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 8D05377E1B86687C00588318 /* Build configuration list for PBXNativeTarget "TimeTests" */ = { isa = XCConfigurationList; @@ -426,6 +572,7 @@ 8D0537801B86687C00588318 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Time/Time/AppDelegate.m b/Time/Time/AppDelegate.m index d59e7a8..ac31792 100644 --- a/Time/Time/AppDelegate.m +++ b/Time/Time/AppDelegate.m @@ -17,6 +17,10 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. + [[UITabBar appearance] setTintColor:[UIColor colorWithRed:255.0/255 green:128.0/255 blue:169.0/255 alpha:1]]; + //[[UITabBar appearance] setAlpha:1]; + [[UITabBar appearance] setBarTintColor:[UIColor colorWithRed:48.0/255 green:66.0/255 blue:154.0/255 alpha:1]]; + sleep(2); return YES; } diff --git a/Time/Time/Base.lproj/Main.storyboard b/Time/Time/Base.lproj/Main.storyboard deleted file mode 100644 index f56d2f3..0000000 --- a/Time/Time/Base.lproj/Main.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Time/Time/DataSingleton.h b/Time/Time/DataSingleton.h new file mode 100644 index 0000000..900bcc5 --- /dev/null +++ b/Time/Time/DataSingleton.h @@ -0,0 +1,17 @@ +// +// DataSingleton.h +// Time +// +// Created by Elber Carneiro on 8/30/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "OrderedDictionary.h" + +@interface DataSingleton : NSObject +@property (nonatomic) OrderedDictionary *presetTimers; +@property (nonatomic) NSMutableArray *alphabeticalKeys; ++ (id)sharedDataSingleton; +- (void)setTimer:(NSArray *)time withName:(NSString *)name; +@end diff --git a/Time/Time/DataSingleton.m b/Time/Time/DataSingleton.m new file mode 100644 index 0000000..87bd66c --- /dev/null +++ b/Time/Time/DataSingleton.m @@ -0,0 +1,68 @@ +// +// DataSingleton.m +// Time +// +// Created by Elber Carneiro on 8/30/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "DataSingleton.h" + +@implementation DataSingleton + ++ (id)sharedDataSingleton { + static DataSingleton *sharedDataSingleton = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedDataSingleton = [[self alloc] init]; + }); + + return sharedDataSingleton; +} + +- (id)init { + if (self = [super init]) { + [self setupDefaultPresets]; + } + return self; +} + +- (void)setupDefaultPresets { + self.presetTimers = [[OrderedDictionary alloc] init]; + + NSArray *keys = @[@"Commercials", @"Dryer", @"Morning Meditation", + @"Popcorn", @"Quick Jog", @"Washing Machine"]; + + NSArray *values = @[@[@"00", @"01", @"00"], + @[@"00", @"45", @"00"], + @[@"00", @"05", @"00"], + @[@"00", @"03", @"30"], + @[@"00", @"25", @"00"], + @[@"00", @"35", @"00"]]; + + for (int i = 0; i < [keys count]; i++) { + [self.presetTimers setObject:values[i] forKey:keys[i]]; + } + + self.alphabeticalKeys = [NSMutableArray arrayWithArray:[self.presetTimers allKeys]]; +} + +- (void)setTimer:(NSArray *)time withName:(NSString *)name { + [self.presetTimers setObject:time forKey:name]; + + self.alphabeticalKeys = [NSMutableArray arrayWithArray:[self.presetTimers allKeys]]; + NSLog(@"Alpha Keys %@", self.alphabeticalKeys); + NSArray* sortedArray = [self.alphabeticalKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + self.alphabeticalKeys = [NSMutableArray arrayWithArray:sortedArray]; + + NSMutableArray *temp = [[NSMutableArray alloc] init]; + for (NSString *key in self.alphabeticalKeys) { + [temp addObject:[self.presetTimers objectForKey:key]]; + } + + self.presetTimers = [OrderedDictionary dictionaryWithObjects:temp forKeys:self.alphabeticalKeys]; + NSLog(@"Preset Timers: %@", self.presetTimers); +} + +@end diff --git a/Time/Time/DateCountdownTableViewController.h b/Time/Time/DateCountdownTableViewController.h new file mode 100644 index 0000000..42a5312 --- /dev/null +++ b/Time/Time/DateCountdownTableViewController.h @@ -0,0 +1,13 @@ +// +// DateCountdownTableViewController.h +// Time +// +// Created by Elber Carneiro on 8/27/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "NewEventViewControllerDelegate.h" + +@interface DateCountdownTableViewController : UITableViewController +@end diff --git a/Time/Time/DateCountdownTableViewController.m b/Time/Time/DateCountdownTableViewController.m new file mode 100644 index 0000000..b00114b --- /dev/null +++ b/Time/Time/DateCountdownTableViewController.m @@ -0,0 +1,169 @@ +// +// DateCountdownTableViewController.m +// Time +// +// Created by Elber Carneiro on 8/27/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "DateCountdownTableViewController.h" +#import "OrderedDictionary.h" +#import "NewEventViewController.h" + +@interface DateCountdownTableViewController () +@property (nonatomic) OrderedDictionary *eventDates; +@property (nonatomic) NSMutableArray *chronologicalKeys; +@property (nonatomic) NSDateFormatter *dateFormatter; +@property (nonatomic) UIColor *pink; +@end + +@implementation DateCountdownTableViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + [self setupDefaultPresets]; + + [[self.navigationController navigationBar] setBarTintColor:[UIColor colorWithRed:63.0/255 green:81.0/255 blue:181.0/255 alpha:1.0]]; + + [self.navigationController.navigationBar + setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]}]; + + // This is here just in case the screen stays active on the user's phone for a bit. + // Refreshes every 5 minutes. + [NSTimer scheduledTimerWithTimeInterval:300.0 + target:self + selector:@selector(reloadCountdown) + userInfo:nil + repeats:YES]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.tableView reloadData]; +} + +- (void)reloadCountdown { + [self.tableView reloadData]; +} + +- (void)setupDefaultPresets { + self.eventDates = [[OrderedDictionary alloc] init]; + + NSArray *description = @[@"CD Player Day", + @"International Day for Failure", + @"Push-Button Phone Day", + @"International Shareware Day", + @"International Programmer's Day", + @"Macintosh Computer Day"]; + + NSArray *keys = @[@"2015 10 01", + @"2015 10 13", + @"2015 11 18", + @"2015 12 13", + @"2016 01 07", + @"2016 01 24"]; + + [self.eventDates setDictionary:[NSDictionary dictionaryWithObjects:description forKeys:keys]]; + + self.dateFormatter = [[NSDateFormatter alloc] init]; + [self.dateFormatter setDateFormat:@"yyyy MM dd"]; + + self.chronologicalKeys = [NSMutableArray arrayWithArray:[self.eventDates allKeys]]; + NSLog(@"Chrono Keys %@", self.chronologicalKeys); + + self.pink = [UIColor colorWithRed:255.0/255 green:128.0/255 blue:169.0/255 alpha:1.0]; +} + +- (NSDate *)convertToNSDate:(NSString *)date { + NSDate *event = [self.dateFormatter dateFromString:date]; + return event; +} + +- (NSString *)timeToEvent:(NSDate *)event { + NSDate *now = [NSDate new]; + + // These next two lines are just for debugging and can be deleted before submission + NSTimeInterval timeLeft = [event timeIntervalSinceDate:now]; + NSLog(@"%f", timeLeft); + + // Get our computer's local calendar + NSCalendar *sysCalendar = [NSCalendar currentCalendar]; + + // Create the calendar unit flags we want to use (minutes are included for debugging, to + // check that the timer is firing every 5 minutes). + NSCalendarUnit unitFlags = NSCalendarUnitMinute | NSCalendarUnitHour | NSCalendarUnitDay | NSCalendarUnitMonth; + + // Create the date components using our unit flags, the difference between the two dates, + // and the local calendar which will automatically compensate for any time difference from + // GMT. + NSDateComponents *breakdownInfo = [sysCalendar components:unitFlags fromDate:now toDate:event options:0]; + NSLog(@"Break down: %lu minutes : %lu hours : %lu days : %lu months", [breakdownInfo minute], [breakdownInfo hour], [breakdownInfo day], [breakdownInfo month]); + + NSString *timeToEvent = [NSString stringWithFormat:@"%02lumo %02lud %02luh", [breakdownInfo month], [breakdownInfo day], [breakdownInfo hour]]; + + return timeToEvent; +} + +- (IBAction)newEventButtonPressed:(id)sender { + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; + NewEventViewController *newEventVC = [storyboard instantiateViewControllerWithIdentifier:@"newEventVC"]; + newEventVC.delegate = self; + + [self presentViewController:newEventVC animated:YES completion:nil]; +} + +#pragma mark - Table view data source +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [self.eventDates count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"dateIdentifier" forIndexPath:indexPath]; + + NSString *key = self.chronologicalKeys[indexPath.row]; + NSDate *eventDate = [self convertToNSDate:key]; + NSString *countdown = [self timeToEvent:eventDate]; + + UIView *selectionColor = [[UIView alloc] init]; + selectionColor.backgroundColor = [UIColor colorWithRed:198.0/255 green:230.0/255 blue:204.0/255 alpha:1.0]; + cell.selectedBackgroundView = selectionColor; + + cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping; + cell.textLabel.numberOfLines = 0; + cell.textLabel.text = [NSString stringWithFormat:@"%@", [self.eventDates objectForKey:key]]; + cell.detailTextLabel.text = countdown; + + return cell; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ + return 80.0; +} + +-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { + cell.backgroundColor = [UIColor whiteColor]; + cell.textLabel.textColor = [UIColor colorWithRed:115.0/255 green:115.0/255 blue:115.0/255 alpha:1]; + cell.textLabel.highlightedTextColor = [UIColor colorWithRed:66.0/255 green:66.0/255 blue:66.0/255 alpha:1]; + cell.detailTextLabel.textColor = self.pink; + + [cell.textLabel setFont:[UIFont fontWithName:@"Orbitron-Regular" size:17]]; + [cell.detailTextLabel setFont:[UIFont fontWithName:@"Orbitron-Regular" size:13]]; +} + +#pragma mark - delegate Implementation +- (void)presetCreated:(NSDate *)eventDate withName:(NSString *)eventName { + NSString *date = [self.dateFormatter stringFromDate:eventDate]; + NSString *capitalizedEventName = [eventName capitalizedString]; + [self.eventDates setObject:capitalizedEventName forKey:date]; + + self.chronologicalKeys = [NSMutableArray arrayWithArray:[self.eventDates allKeys]]; + NSArray* sortedArray = [self.chronologicalKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + self.chronologicalKeys = [NSMutableArray arrayWithArray:sortedArray]; +} + +@end diff --git a/Time/Time/Images.xcassets/StopwatchOrange.imageset/Contents.json b/Time/Time/Images.xcassets/StopwatchOrange.imageset/Contents.json new file mode 100644 index 0000000..3bc1e19 --- /dev/null +++ b/Time/Time/Images.xcassets/StopwatchOrange.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "StopwatchOrange.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Time/Time/Images.xcassets/StopwatchOrange.imageset/StopwatchOrange.png b/Time/Time/Images.xcassets/StopwatchOrange.imageset/StopwatchOrange.png new file mode 100644 index 0000000..d37c952 Binary files /dev/null and b/Time/Time/Images.xcassets/StopwatchOrange.imageset/StopwatchOrange.png differ diff --git a/Time/Time/Images.xcassets/TimerOrange.imageset/Contents.json b/Time/Time/Images.xcassets/TimerOrange.imageset/Contents.json new file mode 100644 index 0000000..39e85ba --- /dev/null +++ b/Time/Time/Images.xcassets/TimerOrange.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "TimerOrange.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Time/Time/Images.xcassets/TimerOrange.imageset/TimerOrange.png b/Time/Time/Images.xcassets/TimerOrange.imageset/TimerOrange.png new file mode 100644 index 0000000..f11c2ca Binary files /dev/null and b/Time/Time/Images.xcassets/TimerOrange.imageset/TimerOrange.png differ diff --git a/Time/Time/Images.xcassets/calendarOrange.imageset/Contents.json b/Time/Time/Images.xcassets/calendarOrange.imageset/Contents.json new file mode 100644 index 0000000..c18a4d5 --- /dev/null +++ b/Time/Time/Images.xcassets/calendarOrange.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "calendarOrange.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Time/Time/Images.xcassets/calendarOrange.imageset/calendarOrange.png b/Time/Time/Images.xcassets/calendarOrange.imageset/calendarOrange.png new file mode 100644 index 0000000..c4d2fea Binary files /dev/null and b/Time/Time/Images.xcassets/calendarOrange.imageset/calendarOrange.png differ diff --git a/Time/Time/Images.xcassets/event_countdown.imageset/Contents.json b/Time/Time/Images.xcassets/event_countdown.imageset/Contents.json new file mode 100644 index 0000000..988524f --- /dev/null +++ b/Time/Time/Images.xcassets/event_countdown.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "event_countdown.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Time/Time/Images.xcassets/event_countdown.imageset/event_countdown.png b/Time/Time/Images.xcassets/event_countdown.imageset/event_countdown.png new file mode 100644 index 0000000..85bed64 Binary files /dev/null and b/Time/Time/Images.xcassets/event_countdown.imageset/event_countdown.png differ diff --git a/Time/Time/Images.xcassets/stopwatch.imageset/Contents.json b/Time/Time/Images.xcassets/stopwatch.imageset/Contents.json new file mode 100644 index 0000000..3f6210a --- /dev/null +++ b/Time/Time/Images.xcassets/stopwatch.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "stopwatch.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Time/Time/Images.xcassets/stopwatch.imageset/stopwatch.png b/Time/Time/Images.xcassets/stopwatch.imageset/stopwatch.png new file mode 100644 index 0000000..4f4766a Binary files /dev/null and b/Time/Time/Images.xcassets/stopwatch.imageset/stopwatch.png differ diff --git a/Time/Time/Images.xcassets/timer.imageset/Contents.json b/Time/Time/Images.xcassets/timer.imageset/Contents.json new file mode 100644 index 0000000..2d6a540 --- /dev/null +++ b/Time/Time/Images.xcassets/timer.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "timer.png" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Time/Time/Images.xcassets/timer.imageset/timer.png b/Time/Time/Images.xcassets/timer.imageset/timer.png new file mode 100644 index 0000000..8ac43cf Binary files /dev/null and b/Time/Time/Images.xcassets/timer.imageset/timer.png differ diff --git a/Time/Time/Info.plist b/Time/Time/Info.plist index 62e151f..314f4ad 100644 --- a/Time/Time/Info.plist +++ b/Time/Time/Info.plist @@ -2,6 +2,10 @@ + UIViewControllerBasedStatusBarAppearance + + UIStatusBarStyle + UIStatusBarStyleBlackOpaque CFBundleDevelopmentRegion en CFBundleExecutable @@ -36,6 +40,17 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIAppFonts + + Orbitron-Black.ttf + Orbitron-Bold.ttf + Orbitron-Medium.ttf + Orbitron-Regular.ttf + Digir___.ttf + + + + UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait diff --git a/Time/Time/LapTableViewController.h b/Time/Time/LapTableViewController.h new file mode 100644 index 0000000..eee1ab5 --- /dev/null +++ b/Time/Time/LapTableViewController.h @@ -0,0 +1,14 @@ +// +// LapTableViewController.h +// Time +// +// Created by Elber Carneiro on 8/25/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "StopWatchViewControllerDelegate.h" + +@interface LapTableViewController : UITableViewController +@property (nonatomic) NSMutableArray *lapTimes; +@end diff --git a/Time/Time/LapTableViewController.m b/Time/Time/LapTableViewController.m new file mode 100644 index 0000000..11f595c --- /dev/null +++ b/Time/Time/LapTableViewController.m @@ -0,0 +1,79 @@ +// +// LapTableViewController.m +// Time +// +// Created by Elber Carneiro on 8/25/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "LapTableViewController.h" + +@interface LapTableViewController () +@property (nonatomic) UIColor *pink; +@property (nonatomic) UIColor *green; +@end + +@implementation LapTableViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.lapTimes = [[NSMutableArray alloc]init]; + self.pink = [UIColor colorWithRed:255.0/255 green:128.0/255 blue:169.0/255 alpha:1.0]; + self.green = [UIColor colorWithRed:198.0/255 green:230.0/255 blue:204.0/255 alpha:1.0]; + self.tableView.backgroundColor = [UIColor whiteColor]; + self.tableView.allowsSelection = NO; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} +#pragma mark - StopWatchViewControllerDelegate implementation +- (NSString *)currentLapTime:(NSString *)lapTime { + [self.lapTimes addObject:lapTime]; + [self.tableView reloadData]; + NSLog(@"%@",self.lapTimes); + return lapTime; +} + +#pragma mark - Table view data source +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.lapTimes.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"lapIdentifier"]; + + if (cell == nil) { + cell = + [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 + reuseIdentifier:@"lapIdentifier"]; + } + + cell.textLabel.text = [NSString stringWithFormat:@"Lap %ld",[self.lapTimes count] - indexPath.row]; + cell.detailTextLabel.text = self.lapTimes[[self.lapTimes count] - 1 - indexPath.row]; + + return cell; +} + +-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { + + if (indexPath.row % 2 == 0) { + cell.backgroundColor = self.green; + } else { + cell.backgroundColor = [UIColor whiteColor]; + } + + cell.textLabel.textColor = self.pink; + cell.textLabel.highlightedTextColor = self.pink; + cell.detailTextLabel.textColor = self.pink; + + [cell.textLabel setFont:[UIFont fontWithName:@"Orbitron-Regular" size:20]]; + [cell.detailTextLabel setFont:[UIFont fontWithName:@"DigitalReadoutExpUpright" size:20]]; +} + +@end diff --git a/Time/Time/NewEventViewController.h b/Time/Time/NewEventViewController.h new file mode 100644 index 0000000..d13826f --- /dev/null +++ b/Time/Time/NewEventViewController.h @@ -0,0 +1,14 @@ +// +// NewEventViewController.h +// Time +// +// Created by Elber Carneiro on 8/29/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "NewEventViewControllerDelegate.h" + +@interface NewEventViewController : UIViewController +@property (nonatomic) id delegate; +@end diff --git a/Time/Time/NewEventViewController.m b/Time/Time/NewEventViewController.m new file mode 100644 index 0000000..a5e80c7 --- /dev/null +++ b/Time/Time/NewEventViewController.m @@ -0,0 +1,78 @@ +// +// NewEventViewController.m +// Time +// +// Created by Elber Carneiro on 8/29/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "NewEventViewController.h" +#import "Time-Swift.h" + +@interface NewEventViewController () +@property (weak, nonatomic) IBOutlet UITextField *eventTextField; +@property (weak, nonatomic) IBOutlet UIButton *doneButton; +@property (weak, nonatomic) IBOutlet PIDatePicker *eventPicker; + +@end + +@implementation NewEventViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + [self setupDatePicker]; + [self.eventTextField setPlaceholder:@"Event Name"]; + self.doneButton.enabled = YES; + self.eventTextField.delegate = self; +} + +- (void)setupDatePicker { + //[self.eventDatePicker setDatePickerMode:UIDatePickerModeDate]; + NSCalendar *sysCalendar = [NSCalendar currentCalendar]; + NSDate *currentDate = [NSDate date]; + NSDateComponents *comps = [[NSDateComponents alloc] init]; + //[comps setDay: + 1]; + NSDate *minDate = [sysCalendar dateByAddingComponents:comps toDate:currentDate options:0]; + [comps setYear: + 85]; + NSDate *maxDate = [sysCalendar dateByAddingComponents:comps toDate:currentDate options:0]; + [comps setYear: + 0]; + [comps setDay: + 1]; + NSDate *initialDisplayDate = [sysCalendar dateByAddingComponents:comps toDate:currentDate options:0]; + + self.eventPicker.minimumDate = minDate; + self.eventPicker.maximumDate = maxDate; + [self.eventPicker setDate:initialDisplayDate animated:YES]; + self.eventPicker.font = [UIFont fontWithName:@"DigitalReadoutExpUpright" size:24]; + self.eventPicker.textColor = [UIColor colorWithRed:255.0/255 green:62.0/255 blue:127.0/255 alpha:1.0]; + self.eventPicker.cellColor = [UIColor colorWithRed:206.0/255 green:230.0/255 blue:213.0/255 alpha:1]; + self.eventPicker.cellHeight = 50.0; + [self.eventPicker reloadAllComponents]; + NSLog(@"DEFAULT ROW HEIGHT: %@", NSStringFromCGSize([self.eventPicker.pickerView rowSizeForComponent:0])); + +} + +- (IBAction)doneButtonTapped:(id)sender { + if(self.eventTextField.text.length == 0){ + + UIAlertController * alert= [UIAlertController + alertControllerWithTitle:@"Error" + message:@"Either the timer name or the actual value is missing, Please fill out those fields before progressing." + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* ok = [UIAlertAction + actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) + { + [alert dismissViewControllerAnimated:YES completion:nil]; + }]; + [alert addAction:ok]; + [self presentViewController:alert animated:YES completion:nil]; + } + else{ + [self.delegate presetCreated:self.eventPicker.date withName:self.eventTextField.text]; + [self dismissViewControllerAnimated:YES completion:nil]; + } +} + +@end diff --git a/Time/Time/NewEventViewControllerDelegate.h b/Time/Time/NewEventViewControllerDelegate.h new file mode 100644 index 0000000..a7765c8 --- /dev/null +++ b/Time/Time/NewEventViewControllerDelegate.h @@ -0,0 +1,13 @@ +// +// NewEventViewControllerDelegate.h +// Time +// +// Created by Elber Carneiro on 8/29/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import + +@protocol NewEventViewControllerDelegate +- (void)presetCreated:(NSDate *)eventDate withName:(NSString *)eventName; +@end diff --git a/Time/Time/NewPresetViewController.h b/Time/Time/NewPresetViewController.h new file mode 100644 index 0000000..96b2940 --- /dev/null +++ b/Time/Time/NewPresetViewController.h @@ -0,0 +1,14 @@ +// +// NewPresetViewController.h +// Time +// +// Created by Elber Carneiro on 8/23/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "NewPresetViewControllerDelegate.h" + +@interface NewPresetViewController : UIViewController +@property (nonatomic) id delegate; +@end diff --git a/Time/Time/NewPresetViewController.m b/Time/Time/NewPresetViewController.m new file mode 100644 index 0000000..5c242ce --- /dev/null +++ b/Time/Time/NewPresetViewController.m @@ -0,0 +1,150 @@ +// +// NewPresetViewController.m +// Time +// +// Created by Elber Carneiro on 8/23/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "NewPresetViewController.h" +#import "NewPresetViewControllerDelegate.h" + +@interface NewPresetViewController () +@property (nonatomic) NSMutableArray *hours; +@property (nonatomic) NSMutableArray *minutes; +@property (nonatomic) NSMutableArray *seconds; +@property (nonatomic) NSMutableArray *pickerViewNumbers; +@property (weak, nonatomic) IBOutlet UIPickerView *timerPickerView; +@property (weak, nonatomic) IBOutlet UITextField *timerNameTextField; +@property (weak, nonatomic) IBOutlet UIButton *doneButton; +@end + +@implementation NewPresetViewController + +#pragma mark - Initial Setup +- (void)viewDidLoad { + [super viewDidLoad]; + [self setupPickerViewNumbers]; + self.timerPickerView.delegate = self; + self.timerPickerView.dataSource = self; +} + +- (void)setupHours { + self.hours = [[NSMutableArray alloc] init]; + + for (int i = 0; i <= 12; i++) { + NSString *s = [NSString stringWithFormat:@"%02d", i]; + [self.hours addObject:s]; + } +} + +- (void)setupMinutes { + self.minutes = [[NSMutableArray alloc] init]; + + for (int i = 0; i < 60; i++) { + NSString *s = [NSString stringWithFormat:@"%02d", i]; + [self.minutes addObject:s]; + } +} + +- (void)setupSeconds { + self.seconds = [[NSMutableArray alloc] init]; + + for (int i = 0; i < 60; i++) { + NSString *s = [NSString stringWithFormat:@"%02d", i]; + [self.seconds addObject:s]; + } +} + +- (void)setupPickerViewNumbers { + [self setupHours]; + [self setupMinutes]; + [self setupSeconds]; + + self.pickerViewNumbers = [[NSMutableArray alloc] initWithObjects:self.hours, + self.minutes, self.seconds, nil]; +} + +#pragma mark - UIPickerView delegate and data source implementation +- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { + return [self.pickerViewNumbers[component] count]; +} + +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { + return [self.pickerViewNumbers count]; +} + +- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { + return self.pickerViewNumbers[component][row]; +} + +#pragma mark - New Data +- (IBAction)doneButtonTapped:(id)sender { + + if(self.timerNameTextField.text.length == 0 || + ([self.timerPickerView selectedRowInComponent:0] == 00 && + [self.timerPickerView selectedRowInComponent:1] == 00 && + [self.timerPickerView selectedRowInComponent:2] == 00)){ + + UIAlertController * alert= [UIAlertController + alertControllerWithTitle:@"Error" + message:@"Either the timer name or the actual value is missing, Please fill out those fields before progressing." + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* ok = [UIAlertAction + actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) + { + [alert dismissViewControllerAnimated:YES completion:nil]; + }]; + [alert addAction:ok]; + [self presentViewController:alert animated:YES completion:nil]; + }else{ + + NSArray *countdownTime = @[ + self.pickerViewNumbers[0][[self.timerPickerView selectedRowInComponent:0]], + self.pickerViewNumbers[1][[self.timerPickerView selectedRowInComponent:1]], + self.pickerViewNumbers[2][[self.timerPickerView selectedRowInComponent:2]] + ]; + NSLog(@"%@", countdownTime); + + NSString *timerName = self.timerNameTextField.text; + NSLog(@"%@", timerName); + + [self.delegate presetCreated:countdownTime withName:timerName]; + [self dismissViewControllerAnimated:YES completion:^{}]; + } + +} + +- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view { + + UILabel *viewAsLabel = (UILabel *)view; + + if(!viewAsLabel) { + viewAsLabel = [[UILabel alloc] init]; + [viewAsLabel setFont:[UIFont fontWithName:@"DigitalReadoutExpUpright" size:50]]; + [viewAsLabel setTextAlignment:NSTextAlignmentCenter]; + [viewAsLabel setBackgroundColor:[UIColor colorWithRed:206.0/255 green:230.0/255 blue:213.0/255 alpha:1]]; + [viewAsLabel setTextColor:[UIColor colorWithRed:255/255 green:62.0/255 blue:127.0/255 alpha:1.0]]; + } + + if (component == 0) { + viewAsLabel.text = [self.hours objectAtIndex:row]; + } else if (component == 1) { + viewAsLabel.text = [self.minutes objectAtIndex:row]; + } else { + viewAsLabel.text = [self.seconds objectAtIndex:row]; + } + + return viewAsLabel; +} + + +- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component { + return 80; +} + + +@end diff --git a/Time/Time/NewPresetViewControllerDelegate.h b/Time/Time/NewPresetViewControllerDelegate.h new file mode 100644 index 0000000..7fd44f4 --- /dev/null +++ b/Time/Time/NewPresetViewControllerDelegate.h @@ -0,0 +1,13 @@ +// +// NewPresetViewControllerDelegate.h +// Time +// +// Created by Elber Carneiro on 8/23/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import + +@protocol NewPresetViewControllerDelegate +- (void)presetCreated:(NSArray *)countdownTime withName:(NSString *)timerName; +@end diff --git a/Time/Time/Orbitron-Black.ttf b/Time/Time/Orbitron-Black.ttf new file mode 100755 index 0000000..2a721fd Binary files /dev/null and b/Time/Time/Orbitron-Black.ttf differ diff --git a/Time/Time/Orbitron-Bold.ttf b/Time/Time/Orbitron-Bold.ttf new file mode 100755 index 0000000..679e79a Binary files /dev/null and b/Time/Time/Orbitron-Bold.ttf differ diff --git a/Time/Time/Orbitron-Medium.ttf b/Time/Time/Orbitron-Medium.ttf new file mode 100755 index 0000000..53cc94c Binary files /dev/null and b/Time/Time/Orbitron-Medium.ttf differ diff --git a/Time/Time/Orbitron-Regular.ttf b/Time/Time/Orbitron-Regular.ttf new file mode 100755 index 0000000..f1e4a7c Binary files /dev/null and b/Time/Time/Orbitron-Regular.ttf differ diff --git a/Time/Time/OrderedDictionary.h b/Time/Time/OrderedDictionary.h new file mode 100644 index 0000000..988ed7a --- /dev/null +++ b/Time/Time/OrderedDictionary.h @@ -0,0 +1,21 @@ +// +// OrderedDictionary.h +// Time +// +// Created by Elber Carneiro on 8/23/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import + +@interface OrderedDictionary : NSMutableDictionary { + NSMutableDictionary *dictionary; + NSMutableArray *array; +} + +- (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex; +- (id)keyAtIndex:(NSUInteger)anIndex; +- (NSEnumerator *)reverseKeyEnumerator; +-(NSString *)getKeyForObject:(id)anObject; + +@end diff --git a/Time/Time/OrderedDictionary.m b/Time/Time/OrderedDictionary.m new file mode 100644 index 0000000..b493d40 --- /dev/null +++ b/Time/Time/OrderedDictionary.m @@ -0,0 +1,115 @@ +// +// OrderedDictionary.m +// Time +// +// Created by Elber Carneiro on 8/23/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "OrderedDictionary.h" + +NSString *DescriptionForObject(NSObject *object, id locale, NSUInteger indent) { + NSString *objectString; +// if ([object isKindOfClass:[NSString class]]) { +// objectString = (NSString *)[[object retain] autorelease]; +// } else + if ([object respondsToSelector:@selector(descriptionWithLocale:indent:)]) { + objectString = [(NSDictionary *)object descriptionWithLocale:locale indent:indent]; + } else if ([object respondsToSelector:@selector(descriptionWithLocale:)]) { + objectString = [(NSSet *)object descriptionWithLocale:locale]; + } else { + objectString = [object description]; + } + return objectString; +} + +@implementation OrderedDictionary + +- (id)init { + self = [super init]; + if (self != nil) { + dictionary = [[NSMutableDictionary alloc] initWithCapacity:0]; + array = [[NSMutableArray alloc] initWithCapacity:0]; + } + return self; +} + +- (id)initWithCapacity:(NSUInteger)capacity { + self = [super init]; + if (self != nil) { + dictionary = [[NSMutableDictionary alloc] initWithCapacity:capacity]; + array = [[NSMutableArray alloc] initWithCapacity:capacity]; + } + return self; +} + +- (id)copy { + return [self mutableCopy]; +} + +- (void)setObject:(id)anObject forKey:(id)aKey { + if (![dictionary objectForKey:aKey]) { + [array addObject:aKey]; + } + [dictionary setObject:anObject forKey:aKey]; +} + +-(NSString *)getKeyForObject:(id)anObject{ + NSArray *keysArray = [dictionary allKeysForObject:anObject]; + NSString *key = keysArray[0]; + return key; +} + +- (void)removeObjectForKey:(id)aKey { + [dictionary removeObjectForKey:aKey]; + [array removeObject:aKey]; +} + +- (NSUInteger)count { + return [dictionary count]; +} + +- (id)objectForKey:(id)aKey { + return [dictionary objectForKey:aKey]; +} + +- (NSEnumerator *)keyEnumerator { + return [array objectEnumerator]; +} + +- (NSEnumerator *)reverseKeyEnumerator { + return [array reverseObjectEnumerator]; +} + +- (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex { + if ([dictionary objectForKey:aKey]) { + [self removeObjectForKey:aKey]; + } + [array insertObject:aKey atIndex:anIndex]; + [dictionary setObject:anObject forKey:aKey]; +} + +- (id)keyAtIndex:(NSUInteger)anIndex { + return [array objectAtIndex:anIndex]; +} + +- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level { + NSMutableString *indentString = [NSMutableString string]; + NSUInteger i, count = level; + for (i = 0; i < count; i++) { + [indentString appendFormat:@" "]; + } + + NSMutableString *description = [NSMutableString string]; + [description appendFormat:@"%@{\n", indentString]; + for (NSObject *key in self) { + [description appendFormat:@"%@ %@ = %@;\n", + indentString, + DescriptionForObject(key, locale, level), + DescriptionForObject([self objectForKey:key], locale, level)]; + } + [description appendFormat:@"%@}\n", indentString]; + return description; +} + +@end diff --git a/Time/Time/PIDatePicker.swift b/Time/Time/PIDatePicker.swift new file mode 100755 index 0000000..1ad0be2 --- /dev/null +++ b/Time/Time/PIDatePicker.swift @@ -0,0 +1,556 @@ +// +// PIDatePicker.swift +// Pods +// +// Created by Christopher Jones on 3/30/15. +// +// + +import UIKit + +public class PIDatePicker: UIControl, UIPickerViewDataSource, UIPickerViewDelegate { + + // MARK: - + // MARK: Public Properties + public var delegate: PIDatePickerDelegate? + + /// The font for the date picker. + public var font = UIFont.systemFontOfSize(15.0) + + /// The text color for the date picker components. + public var textColor = UIColor.blackColor() + + /// Background color + public var cellColor = UIColor.whiteColor() + + /// Cell height + public var cellHeight: CGFloat = 34.0 + + /// The minimum date to show for the date picker. Set to NSDate.distantPast() by default + public var minimumDate = NSDate.distantPast() as! NSDate { + didSet { + self.validateMinimumAndMaximumDate() + } + } + + /// The maximum date to show for the date picker. Set to NSDate.distantFuture() by default + public var maximumDate = NSDate.distantFuture() as! NSDate { + didSet { + self.validateMinimumAndMaximumDate() + } + } + + /// The current locale to use for formatting the date picker. By default, set to the device's current locale + public var locale : NSLocale = NSLocale.currentLocale() { + didSet { + self.calendar.locale = self.locale + } + } + + /// The current date value of the date picker. + public private(set) var date = NSDate() + + /// The internal picker view used for laying out the date components. + public var pickerView = UIPickerView() + + // MARK: - + // MARK: Private Variables + + private let maximumNumberOfRows = Int(INT16_MAX) + + /// The calendar used for formatting dates. + private var calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! + + /// Calculates the current calendar components for the current date. + private var currentCalendarComponents : NSDateComponents { + get { + return self.calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: self.date) + } + } + + /// Gets the text color to be used for the label in a disabled state + private var disabledTextColor : UIColor { + get { + var r : CGFloat = 0 + var g : CGFloat = 0 + var b : CGFloat = 0 + + self.textColor.getRed(&r, green: &g, blue: &b, alpha: nil) + + return UIColor(red: r, green: g, blue: b, alpha: 0.35) + } + } + + /// The order in which each component should be ordered in. + private var datePickerComponentOrdering = [PIDatePickerComponents]() + + // MARK: - + // MARK: LifeCycle + + required public init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.commonInit() + } + + override public init(frame: CGRect) { + super.init(frame: frame) + self.commonInit() + } + + /** + Handles the common initialization amongst all init() + */ + func commonInit() { + self.pickerView.dataSource = self + self.pickerView.delegate = self + + self.pickerView.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); + self.addSubview(self.pickerView) + } + + // MARK: - + // MARK: Override + public override func intrinsicContentSize() -> CGSize { + return self.pickerView.intrinsicContentSize() + } + + public override func willMoveToSuperview(newSuperview: UIView?) { + super.willMoveToSuperview(newSuperview) + self.reloadAllComponents() + + self.setDate(self.date) + } + + // MARK: - + // MARK: Public + + /** + Reloads all of the components in the date picker. + */ + public func reloadAllComponents() { + self.refreshComponentOrdering() + self.pickerView.reloadAllComponents() + } + + /** + Sets the current date value for the date picker. + + :param: date The date to set the picker to. + :param: animated True if the date picker should changed with an animation; otherwise false, + */ + public func setDate(date : NSDate, animated : Bool) { + self.date = date + self.updatePickerViewComponentValuesAnimated(animated) + } + + // MARK: - + // MARK: Private + + /** + Sets the current date with no animation. + + :param: date The date to be set. + */ + private func setDate(date : NSDate) { + self.setDate(date, animated: false) + } + + /** + Creates a new date formatter with the locale and calendar + + :returns: A new instance of NSDateFormatter + */ + private func dateFormatter() -> NSDateFormatter { + let dateFormatter = NSDateFormatter() + dateFormatter.calendar = self.calendar + dateFormatter.locale = self.locale + + return dateFormatter + } + + /** + Refreshes the ordering of components based on the current locale. Calling this function will not refresh the picker view. + */ + private func refreshComponentOrdering() { + var componentOrdering = NSDateFormatter.dateFormatFromTemplate("yMMMMd", options: 0, locale: self.locale)! + + let firstComponentOrderingString = componentOrdering[advance(componentOrdering.startIndex, 0)] + let lastComponentOrderingString = componentOrdering[advance(componentOrdering.startIndex, count(componentOrdering) - 1)] + + let characterSet = NSCharacterSet(charactersInString: String(firstComponentOrderingString) + String(lastComponentOrderingString)) + componentOrdering = componentOrdering.stringByTrimmingCharactersInSet(characterSet).stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + + let remainingValue = componentOrdering[advance(componentOrdering.startIndex, 0)] + + let firstComponent = PIDatePickerComponents(rawValue: firstComponentOrderingString)! + let secondComponent = PIDatePickerComponents(rawValue: remainingValue)! + let lastComponent = PIDatePickerComponents(rawValue: lastComponentOrderingString)! + + self.datePickerComponentOrdering = [firstComponent, secondComponent, lastComponent] + } + + /** + Validates that the set minimum and maximum dates are valid. + */ + private func validateMinimumAndMaximumDate() { + let ordering = self.minimumDate.compare(self.maximumDate) + if (ordering != .OrderedAscending ){ + fatalError("Cannot set a maximum date that is equal or less than the minimum date.") + } + } + + /** + Gets the value of the current component at the specified row. + + :param: row The row index whose value is required + :param: componentIndex The component index for the row. + + :returns: A string containing the value of the current row at the component index. + */ + private func titleForRow(row : Int, inComponentIndex componentIndex: Int) -> String { + let dateComponent = self.componentAtIndex(componentIndex) + + let value = self.rawValueForRow(row, inComponent: dateComponent) + + if dateComponent == PIDatePickerComponents.Month { + let dateFormatter = self.dateFormatter() + return dateFormatter.monthSymbols[value - 1] as! String + } else { + return String(value) + } + } + + /** + Gets the value of the input component using the current date. + + :param: component The component whose value is needed. + + :returns: The value of the component. + */ + private func valueForDateComponent(component : PIDatePickerComponents) -> Int{ + if component == .Year { + return self.currentCalendarComponents.year + } else if component == .Day { + return self.currentCalendarComponents.day + } else { + return self.currentCalendarComponents.month + } + } + + /** + Gets the maximum range for the specified date picker component. + + :param: component The component to get the range for. + + :returns: The maximum date range for that component. + */ + private func maximumRangeForComponent(component : PIDatePickerComponents) -> NSRange { + var calendarUnit : NSCalendarUnit + if component == .Year { + calendarUnit = .CalendarUnitYear + } else if component == .Day { + calendarUnit = .CalendarUnitDay + } else { + calendarUnit = .CalendarUnitMonth + } + + return self.calendar.maximumRangeOfUnit(calendarUnit) + } + + /** + Calculates the raw value of the row at the current index. + + :param: row The row to get. + :param: component The component which the row belongs to. + + :returns: The raw value of the row, in integer. Use NSDateComponents to convert to a usable date object. + */ + private func rawValueForRow(row : Int, inComponent component : PIDatePickerComponents) -> Int { + let calendarUnitRange = self.maximumRangeForComponent(component) + return calendarUnitRange.location + (row % calendarUnitRange.length) + } + + /** + Checks if the specified row should be enabled or not. + + :param: row The row to check. + :param: component The component to check the row in. + + :returns: YES if the row should be enabled; otherwise NO. + */ + private func isRowEnabled(row: Int, forComponent component : PIDatePickerComponents) -> Bool { + + let rawValue = self.rawValueForRow(row, inComponent: component) + NSLog("Row: %d, Raw Value: %d", row, rawValue) + + let components = NSDateComponents() + components.year = self.currentCalendarComponents.year + components.month = self.currentCalendarComponents.month + components.day = self.currentCalendarComponents.day + + if component == .Year { + components.year = rawValue + } else if component == .Day { + components.day = rawValue + } else if component == .Month { + components.month = rawValue + } + + let dateForRow = self.calendar.dateFromComponents(components)! + NSLog("Date for Row: %@", dateForRow) + + return self.dateIsInRange(dateForRow) + } + + /** + Checks if the input date falls within the date picker's minimum and maximum date ranges. + + :param: date The date to be checked. + + :returns: True if the input date is within range of the minimum and maximum; otherwise false. + */ + private func dateIsInRange(date : NSDate) -> Bool { + return self.minimumDate.compare(date) != NSComparisonResult.OrderedDescending && + self.maximumDate.compare(date) != NSComparisonResult.OrderedAscending + } + + /** + Updates all of the date picker components to the value of the current date. + + :param: animated True if the update should be animated; otherwise false. + */ + private func updatePickerViewComponentValuesAnimated(animated : Bool) { + for (index, dateComponent) in enumerate(self.datePickerComponentOrdering) { + self.setIndexOfComponent(dateComponent, animated: animated) + } + } + + /** + Updates the index of the specified component to its relevant value in the current date. + + :param: component The component to be updated. + :param: animated True if the update should be animated; otherwise false. + */ + private func setIndexOfComponent(component : PIDatePickerComponents, animated: Bool) { + self.setIndexOfComponent(component, toValue: self.valueForDateComponent(component), animated: animated) + } + + /** + Updates the index of the specified component to the input value. + + :param: component The component to be updated. + :param: value The value the component should be updated ot. + :param: animated True if the update should be animated; otherwise false. + */ + private func setIndexOfComponent(component : PIDatePickerComponents, toValue value : Int, animated: Bool) { + let componentRange = self.maximumRangeForComponent(component) + + let idx = (value - componentRange.location) + let middleIndex = (self.maximumNumberOfRows / 2) - (maximumNumberOfRows / 2) % componentRange.length + idx + + var componentIndex = 0 + + for (index, dateComponent) in enumerate(self.datePickerComponentOrdering) { + if (dateComponent == component) { + componentIndex = index + } + } + + self.pickerView.selectRow(middleIndex, inComponent: componentIndex, animated: animated) + } + + /** + Gets the component type at the current component index. + + :param: index The component index + + :returns: The date picker component type at the index. + */ + private func componentAtIndex(index: Int) -> PIDatePickerComponents { + return self.datePickerComponentOrdering[index] + } + + /** + Gets the number of days of the specified month in the specified year. + + :param: month The month whose maximum date value is requested. + :param: year The year for which the maximum date value is required. + + :returns: The number of days in the month. + */ + private func numberOfDaysForMonth(month : Int, inYear year : Int) -> Int { + let components = NSDateComponents() + components.month = month + components.day = 1 + components.year = year + + let calendarRange = self.calendar.rangeOfUnit(.CalendarUnitDay, inUnit: .CalendarUnitMonth, forDate: self.calendar.dateFromComponents(components)!) + let numberOfDaysInMonth = calendarRange.length + + return numberOfDaysInMonth + } + + /** + Determines if updating the specified component to the input value would evaluate to a valid date using the current date values. + + :param: value The value to be updated to. + :param: component The component whose value should be updated. + + :returns: True if updating the component to the specified value would result in a valid date; otherwise false. + */ + private func isValidValue(value : Int, forComponent component: PIDatePickerComponents) -> Bool { + if (component == .Year) { + let numberOfDaysInMonth = self.numberOfDaysForMonth(self.currentCalendarComponents.month, inYear: value) + return self.currentCalendarComponents.day <= numberOfDaysInMonth + } else if (component == .Day) { + let numberOfDaysInMonth = self.numberOfDaysForMonth(self.currentCalendarComponents.month, inYear: self.currentCalendarComponents.year) + return value <= numberOfDaysInMonth + } else if (component == .Month) { + let numberOfDaysInMonth = self.numberOfDaysForMonth(value, inYear: self.currentCalendarComponents.year) + return self.currentCalendarComponents.day <= numberOfDaysInMonth + } + + return true + } + + /** + Creates date components by updating the specified component to the input value. This does not do any date validation. + + :param: component The component to be updated. + :param: value The value the component should be updated to. + + :returns: The components by updating the current date's components to the specified value. + */ + private func currentCalendarComponentsByUpdatingComponent(component : PIDatePickerComponents, toValue value : Int) -> NSDateComponents { + let components = self.currentCalendarComponents + + if (component == .Month) { + components.month = value + } else if (component == .Day) { + components.day = value + } else { + components.year = value + } + + return components + } + + /** + Creates date components by updating the specified component to the input value. If the resulting value is not a valid date object, the components will be updated to the closest best value. + + :param: component The component to be updated. + :param: value The value the component should be updated to. + + :returns: The components by updating the specified value; the components will be a valid date object. + */ + private func validDateValueByUpdatingComponent(component : PIDatePickerComponents, toValue value : Int) -> NSDateComponents { + let components = self.currentCalendarComponentsByUpdatingComponent(component, toValue: value) + + if (!self.isValidValue(value, forComponent: component)) { + if (component == .Month) { + components.day = self.numberOfDaysForMonth(value, inYear: components.year) + } else if (component == .Day) { + components.day = self.numberOfDaysForMonth(components.month, inYear:components.year) + } else { + components.day = self.numberOfDaysForMonth(components.month, inYear: value) + } + } + + return components + } + + // MARK: - + // MARK: Protocols + // MARK: UIPickerViewDelegate + + public func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + let datePickerComponent = self.componentAtIndex(component) + let value = self.rawValueForRow(row, inComponent: datePickerComponent) + + // Create the newest valid date components. + let components = self.validDateValueByUpdatingComponent(datePickerComponent, toValue: value) + + // If the resulting components are not in the date range ... + if (!self.dateIsInRange(self.calendar.dateFromComponents(components)!)) { + // ... go back to original date + self.setDate(self.date, animated: true) + } else { + // Get the components that would result by just force-updating the current components. + let rawComponents = self.currentCalendarComponentsByUpdatingComponent(datePickerComponent, toValue: value) + + if (rawComponents.day != components.day) { + // Only animate the change if the day value is not a valid date. + self.setIndexOfComponent(.Day, toValue: components.day, animated: self.isValidValue(components.day, forComponent: .Day)) + } + + if (rawComponents.month != components.month) { + self.setIndexOfComponent(.Month, toValue: components.day, animated: datePickerComponent != .Month) + } + + if (rawComponents.year != components.year) { + self.setIndexOfComponent(.Year, toValue: components.day, animated: datePickerComponent != .Year) + } + + self.date = self.calendar.dateFromComponents(components)! + self.sendActionsForControlEvents(.ValueChanged) + } + + self.delegate?.pickerView(self, didSelectRow: row, inComponent: component) + } + + public func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView { + var label = view as? UILabel == nil ? UILabel() : view as! UILabel + + label.font = self.font + label.textColor = self.textColor + label.backgroundColor = self.cellColor + label.text = self.titleForRow(row, inComponentIndex: component) + label.textAlignment = NSTextAlignment.Center + //label.textAlignment = self.componentAtIndex(component) == .Month ? NSTextAlignment.Left : NSTextAlignment.Right + label.textColor = self.isRowEnabled(row, forComponent: self.componentAtIndex(component)) ? self.textColor : self.disabledTextColor + + return label + } + + public func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat { + let widthBuffer = 25.0 + + let calendarComponent = self.componentAtIndex(component) + let stringSizingAttributes = [NSFontAttributeName : self.font] + var size = 0.01 + + if calendarComponent == .Month { + let dateFormatter = self.dateFormatter() + + // Get the length of the longest month string and set the size to it. + for symbol in dateFormatter.monthSymbols as! [String] { + let monthSize = NSString(string: symbol).sizeWithAttributes(stringSizingAttributes) + size = max(size, Double(monthSize.width)) + } + } else if calendarComponent == .Day{ + // Pad the day string to two digits + let dayComponentSizingString = NSString(string: "00") + size = Double(dayComponentSizingString.sizeWithAttributes(stringSizingAttributes).width) + } else if calendarComponent == .Year { + // Pad the year string to four digits. + let yearComponentSizingString = NSString(string: "0000") + size = Double(yearComponentSizingString.sizeWithAttributes(stringSizingAttributes).width) + } + + // Add the width buffer in order to allow the picker components not to run up against the edges + return CGFloat(size + widthBuffer) + } + + public func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { + return self.cellHeight + } + + // MARK: UIPickerViewDataSource + public func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return self.maximumNumberOfRows + } + + public func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { + return 3 + } +} diff --git a/Time/Time/PIDatePickerComponents.swift b/Time/Time/PIDatePickerComponents.swift new file mode 100755 index 0000000..bc30fcc --- /dev/null +++ b/Time/Time/PIDatePickerComponents.swift @@ -0,0 +1,14 @@ +// +// PIDatePickerComponents.swift +// Pods +// +// Created by Christopher Jones on 3/30/15. +// +// + +enum PIDatePickerComponents : Character { + case Invalid = "!", + Year = "y", + Month = "M", + Day = "d" +} diff --git a/Time/Time/PIDatePickerDelegate.swift b/Time/Time/PIDatePickerDelegate.swift new file mode 100755 index 0000000..b0e9093 --- /dev/null +++ b/Time/Time/PIDatePickerDelegate.swift @@ -0,0 +1,13 @@ +// +// PIDatePickerDelegate.swift +// Pods +// +// Created by Matt Luedke on 5/8/15. +// +// + +import Foundation + +public protocol PIDatePickerDelegate { + func pickerView(pickerView: PIDatePicker, didSelectRow row: Int, inComponent component: Int) +} diff --git a/Time/Time/PresetsTableViewController.h b/Time/Time/PresetsTableViewController.h new file mode 100644 index 0000000..e5d5fc4 --- /dev/null +++ b/Time/Time/PresetsTableViewController.h @@ -0,0 +1,15 @@ +// +// PresetsTableViewController.h +// Time +// +// Created by Elber Carneiro on 8/23/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "PresetsTableViewControllerDelegate.h" +#import "NewPresetViewControllerDelegate.h" + +@interface PresetsTableViewController : UITableViewController +@property (nonatomic) id delegate; +@end diff --git a/Time/Time/PresetsTableViewController.m b/Time/Time/PresetsTableViewController.m new file mode 100644 index 0000000..ceed018 --- /dev/null +++ b/Time/Time/PresetsTableViewController.m @@ -0,0 +1,117 @@ +// +// PresetsTableViewController.m +// Time +// +// Created by Elber Carneiro on 8/23/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "PresetsTableViewController.h" +#import "NewPresetViewController.h" +#import "OrderedDictionary.h" +#import "DataSingleton.h" + +@interface PresetsTableViewController () +@property (nonatomic) DataSingleton *sharedSingleton; +@property (nonatomic) NSArray *selectedPreset; +@property (nonatomic) NSUInteger chosenIndex; +@property (nonatomic) UIColor *pink; +@end + +@implementation PresetsTableViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.sharedSingleton = [DataSingleton sharedDataSingleton]; + + self.pink = [UIColor colorWithRed:255.0/255 green:128.0/255 blue:169.0/255 alpha:1.0]; + [self.navigationItem setTitle:@"Select Presets"]; + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] + initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(didSelectTimer)]; + self.navigationItem.leftBarButtonItem.tintColor = [UIColor whiteColor]; + [self.navigationItem.leftBarButtonItem setEnabled:NO]; + + self.tableView.backgroundColor = [UIColor whiteColor]; + + [[self.navigationController navigationBar] setBarTintColor:[UIColor colorWithRed:63.0/255 green:81.0/255 blue:181.0/255 alpha:1.0]]; + + [self.navigationController.navigationBar + setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]}]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.tableView reloadData]; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + if (self.navigationItem.leftBarButtonItem.enabled == NO) { + [self.navigationItem.leftBarButtonItem setEnabled:YES]; + } + self.selectedPreset = [self.sharedSingleton.presetTimers objectForKey:[self.sharedSingleton.presetTimers keyAtIndex:indexPath.row]]; +} + +- (void)didSelectTimer { + + NSString *key = [self.sharedSingleton.presetTimers getKeyForObject:self.selectedPreset]; + + [self.delegate presetTime:self.selectedPreset withName:key]; + [self dismissViewControllerAnimated:YES completion:^{}]; +} + +- (IBAction)newPresetButtonPressed:(id)sender { + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; + NewPresetViewController *newPresetVC = [storyboard instantiateViewControllerWithIdentifier:@"newPresetVC"]; + newPresetVC.delegate = self; + + [self presentViewController:newPresetVC animated:YES completion:nil]; +} + +#pragma mark - Table view data source +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [self.sharedSingleton.presetTimers count]; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ + return 60.0; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"presetIdentifier"]; + + if (cell == nil) { + cell = + [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 + reuseIdentifier:@"presetIdentifier"]; + } + UIView *selectionColor = [[UIView alloc] init]; + selectionColor.backgroundColor = [UIColor colorWithRed:198.0/255 green:230.0/255 blue:204.0/255 alpha:1.0]; + cell.selectedBackgroundView = selectionColor; + + cell.backgroundColor = [UIColor whiteColor]; + cell.textLabel.textColor = self.pink; + cell.textLabel.highlightedTextColor = self.pink; + cell.detailTextLabel.textColor = self.pink; + + [cell.textLabel setFont:[UIFont fontWithName:@"Orbitron-Regular" size:20]]; + [cell.detailTextLabel setFont:[UIFont fontWithName:@"DigitalReadoutExpUpright" size:20]]; + + cell.textLabel.text = [NSString stringWithFormat:@"%@", self.sharedSingleton.alphabeticalKeys[indexPath.row]]; + NSArray *presetTime = [self.sharedSingleton.presetTimers objectForKey:self.sharedSingleton.alphabeticalKeys[indexPath.row]]; + cell.detailTextLabel.text = [NSString stringWithFormat:@"%@:%@:%@", presetTime[0], presetTime[1], presetTime[2]]; + + return cell; +} + +#pragma mark - NewPresetViewControllerDelegate implementation +-(void)presetCreated:(NSArray *)countdownTime withName:(NSString *)timerName { + [self.sharedSingleton setTimer:countdownTime withName:timerName]; +} + +@end diff --git a/Time/Time/PresetsTableViewControllerDelegate.h b/Time/Time/PresetsTableViewControllerDelegate.h new file mode 100644 index 0000000..6a1d66c --- /dev/null +++ b/Time/Time/PresetsTableViewControllerDelegate.h @@ -0,0 +1,13 @@ +// +// PresetsTableViewControllerDelegate.h +// Time +// +// Created by Elber Carneiro on 8/23/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import + +@protocol PresetsTableViewControllerDelegate +- (void)presetTime:(NSArray *)presetTime withName:(NSString *)name; +@end diff --git a/Time/Time/StopWatchViewControllerDelegate.h b/Time/Time/StopWatchViewControllerDelegate.h new file mode 100644 index 0000000..7d3c8a2 --- /dev/null +++ b/Time/Time/StopWatchViewControllerDelegate.h @@ -0,0 +1,14 @@ +// +// StopWatchViewControllerDelegate.h +// Time +// +// Created by Mesfin Bekele Mekonnen on 8/26/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import + + +@protocol StopWatchViewControllerDelegate +- (NSString *)currentLapTime:(NSString *)lapTime; +@end diff --git a/Time/Time/StopwatchViewController.h b/Time/Time/StopwatchViewController.h new file mode 100644 index 0000000..25b0609 --- /dev/null +++ b/Time/Time/StopwatchViewController.h @@ -0,0 +1,14 @@ +// +// StopwatchViewController.h +// Time +// +// Created by Mesfin Bekele Mekonnen on 8/22/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "StopWatchViewControllerDelegate.h" + +@interface StopwatchViewController : UIViewController +@property (nonatomic) id delegate; +@end diff --git a/Time/Time/StopwatchViewController.m b/Time/Time/StopwatchViewController.m new file mode 100644 index 0000000..cecc8fc --- /dev/null +++ b/Time/Time/StopwatchViewController.m @@ -0,0 +1,106 @@ +// +// StopwatchViewController.m +// Time +// +// Created by Mesfin Bekele Mekonnen on 8/22/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "StopwatchViewController.h" +#import "LapTableViewController.h" + +@interface StopwatchViewController () +@property (weak, nonatomic) IBOutlet UIView *timerView; +@property (weak, nonatomic) IBOutlet UIButton *startButton; +@property (weak, nonatomic) IBOutlet UIButton *lapButton; +@property (weak, nonatomic) IBOutlet UILabel *timerLabel; +@property (weak, nonatomic) IBOutlet UILabel *lapLabel; +@property (nonatomic) CFTimeInterval initialTime; +@property (nonatomic) CFTimeInterval lapInitialTime; +@property (nonatomic) CADisplayLink *stopwatchTimer; +@property (nonatomic) NSMutableArray *lapTimes; +@property (weak, nonatomic) IBOutlet UITableView *lapTableView; + +@property (nonatomic) LapTableViewController *ltvc; +@property (nonatomic) NSString *currentLapTime; + +@end + +@implementation StopwatchViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + [UIView setAnimationsEnabled:NO]; + + self.lapTimes = [NSMutableArray new]; + self.stopwatchTimer = [CADisplayLink displayLinkWithTarget:self + selector:@selector(refreshTimerLabel)]; + [self.stopwatchTimer setPaused:YES]; + [self.stopwatchTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + + [self embedTableView]; +} + +- (void)embedTableView { + self.ltvc = [[LapTableViewController alloc]init]; + + [self addChildViewController:self.ltvc]; + + self.ltvc.view.frame = self.lapTableView.bounds;// _view.bounds; + [self.lapTableView addSubview:self.ltvc.view]; + + [self.ltvc willMoveToParentViewController:self]; +} + +- (NSString *)formatTimeString:(CFTimeInterval)timeInterval{ + CFTimeInterval currentTime = CACurrentMediaTime(); + CFTimeInterval difference = currentTime - timeInterval; + + NSString *string = [NSString stringWithFormat:@"%02li:%02li.%03li", + // lround(floor(difference / 3600.)) % 100, + lround(floor(difference / 60.)) % 60, + lround(floor(difference)) % 60, + lround(floor(difference * 1000)) % 1000]; + return string; +} + +- (void)refreshTimerLabel{ + self.timerLabel.text = [self formatTimeString:self.initialTime]; + self.lapLabel.text = [self formatTimeString:self.lapInitialTime]; +} + +- (IBAction)startButtonTapped:(UIButton *)sender { + if ([self.startButton.titleLabel.text isEqualToString:@"Start"]) { + [self.stopwatchTimer setPaused:NO]; + if([self.timerLabel.text isEqualToString:@"00:00.000"]){ + self.initialTime = CACurrentMediaTime(); + self.lapInitialTime = self.initialTime; + } + [self.startButton setTitle:@"Pause" forState:UIControlStateNormal]; + [self.lapButton setTitle:@"Lap" forState:UIControlStateNormal]; + } else { + [self.stopwatchTimer setPaused:YES]; + [self.startButton setTitle:@"Start" forState:UIControlStateNormal]; + [self.lapButton setTitle:@"Reset" forState:UIControlStateNormal]; + } +} + +- (IBAction)lapButtonTapped:(UIButton *)sender { + if([self.lapButton.titleLabel.text isEqualToString:@"Lap"]){ + self.lapInitialTime = CACurrentMediaTime(); + + [self.lapTimes addObject:self.lapLabel.text]; + NSLog(@"%@",self.lapTimes); + self.currentLapTime = self.lapLabel.text; + NSLog(@"%@",self.currentLapTime); + [self.ltvc currentLapTime:self.currentLapTime]; + + } else { + [self.ltvc.lapTimes removeAllObjects]; + [self.ltvc.tableView reloadData]; + self.lapLabel.text = @"00:00.000"; + self.timerLabel.text = @"00:00.000"; + } +} + +@end diff --git a/Time/Time/StopwatchViewController.m.orig b/Time/Time/StopwatchViewController.m.orig new file mode 100644 index 0000000..1e6b4ef --- /dev/null +++ b/Time/Time/StopwatchViewController.m.orig @@ -0,0 +1,86 @@ +// +// StopwatchViewController.m +// Time +// +// Created by Mesfin Bekele Mekonnen on 8/22/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "StopwatchViewController.h" +//@import QuartzCore; + +@interface StopwatchViewController () +@property (weak, nonatomic) IBOutlet UIView *timerView; +@property (weak, nonatomic) IBOutlet UIButton *startButton; +@property (weak, nonatomic) IBOutlet UIButton *lapButton; +@property (weak, nonatomic) IBOutlet UILabel *timerLabel; +@property (nonatomic) CFTimeInterval initialTime; + +@property (nonatomic) CADisplayLink *stopwatchTimer; + +@end + +@implementation StopwatchViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.stopwatchTimer = [CADisplayLink displayLinkWithTarget:self + selector:@selector(refreshTimerLabel)]; + [self.stopwatchTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; +} + +-(void)refreshTimerLabel{ + CFTimeInterval currentTime = CACurrentMediaTime(); + CFTimeInterval difference = currentTime - self.initialTime; + + NSString *string = [NSString stringWithFormat:@"%02li:%02li:%02li.%03li", + lround(floor(difference / 3600.)) % 100, + lround(floor(difference / 60.)) % 60, + lround(floor(difference)) % 60, + lround(floor(difference * 1000)) % 1000]; + + self.timerLabel.text = string; + +} + +- (IBAction)startButtonTapped:(UIButton *)sender { + [self.stopwatchTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + self.initialTime = CACurrentMediaTime(); + + + if ([self.startButton.titleLabel.text isEqualToString:@"Start"]) { + [self.stopwatchTimer setPaused:NO]; + self.initialTime = CACurrentMediaTime(); + [self.startButton setTitle:@"Pause" forState:UIControlStateNormal]; + NSLog(@"%@", self.startButton.titleLabel.text); + } else { + [self.stopwatchTimer setPaused:YES]; + [self.startButton setTitle:@"Start" forState:UIControlStateNormal]; + } + +} + +- (IBAction)stopButtonTapped:(UIButton *)sender { + +} + +- (IBAction)lapButtonTapped:(UIButton *)sender { +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/Time/Time/Time-Bridging-Header.h b/Time/Time/Time-Bridging-Header.h new file mode 100644 index 0000000..1b2cb5d --- /dev/null +++ b/Time/Time/Time-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/Time/Time/TimerViewController.h b/Time/Time/TimerViewController.h new file mode 100644 index 0000000..13bc095 --- /dev/null +++ b/Time/Time/TimerViewController.h @@ -0,0 +1,13 @@ +// +// TimerViewController.h +// Time +// +// Created by Elber Carneiro on 8/22/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "PresetsTableViewControllerDelegate.h" + +@interface TimerViewController : UIViewController +@end diff --git a/Time/Time/TimerViewController.m b/Time/Time/TimerViewController.m new file mode 100644 index 0000000..75e64eb --- /dev/null +++ b/Time/Time/TimerViewController.m @@ -0,0 +1,303 @@ +// +// TimerViewController.m +// Time +// +// Created by Elber Carneiro on 8/22/15. +// Copyright (c) 2015 Mike Kavouras. All rights reserved. +// + +#import "TimerViewController.h" +#import "PresetsTableViewController.h" + +@interface TimerViewController () +@property (weak, nonatomic) IBOutlet UIPickerView *timerPickerView; +@property (nonatomic) NSMutableArray *hours; +@property (nonatomic) NSMutableArray *minutes; +@property (nonatomic) NSMutableArray *seconds; +@property (nonatomic) NSMutableArray *pickerViewNumbers; +@property (weak, nonatomic) IBOutlet UIButton *startButton; +@property (weak, nonatomic) IBOutlet UIButton *resetButton; +@property (weak, nonatomic) IBOutlet UILabel *timerName; + +//For use with UIPickerView +@property (nonatomic) NSTimer *timer; +@property (nonatomic) CFTimeInterval initialTime; +@property (nonatomic) CFTimeInterval lapInitialTime; +@property (nonatomic) NSArray *presetTime; + +@property (nonatomic) NSInteger component; +@property (nonatomic) NSInteger row; + +@property (nonatomic) BOOL isStarted; +@property (nonatomic) BOOL isInitial; + +@end + +@implementation TimerViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + [self setupPickerViewNumbers]; + + self.timerPickerView.delegate = self; + self.timerPickerView.dataSource = self; + self.timerName.text = @" "; + + self.isStarted = NO; + self.isInitial = YES; + //self.isPaused = NO; + //self.isPreset = NO; +} + +-(void)viewWillAppear:(BOOL)animated{ + [super viewWillAppear:animated]; + if (!self.isInitial) { + if (self.isStarted) { + [self.startButton setTitle:@"Pause" forState:UIControlStateNormal]; + } else { + [self.startButton setTitle:@"Start" forState:UIControlStateNormal]; + } + + NSInteger hourIndex = [self.timerPickerView selectedRowInComponent:0]; + NSInteger minuteIndex = [self.timerPickerView selectedRowInComponent:1]; + NSInteger secondIndex = [self.timerPickerView selectedRowInComponent:2]; + if(hourIndex ==0 && minuteIndex == 0 && secondIndex == 0 ){ + [self.startButton setTitle:@"Start" forState:UIControlStateNormal]; + [self.timerPickerView setUserInteractionEnabled:YES]; + } + } +} + +- (void)setupHours { + self.hours = [[NSMutableArray alloc] init]; + + for (int i = 0; i <= 12; i++) { + NSString *s = [NSString stringWithFormat:@"%02d", i]; + [self.hours addObject:s]; + } +} + +- (void)setupMinutes { + self.minutes = [[NSMutableArray alloc] init]; + int j = 0; + int i = 0; + while(true){ + if(i == 60){ + i=0; + } + if(j==3600){ + break; + } + NSString *s = [NSString stringWithFormat:@"%02d", i]; + [self.minutes addObject:s]; + i++; + j++; + } +} + +- (void)setupSeconds { + self.seconds = [[NSMutableArray alloc] init]; + + int j = 0; + int i = 0; + while(true){ + if(i == 60){ + i=0; + } + if(j==3600){ + break; + } + NSString *s = [NSString stringWithFormat:@"%02d", i]; + [self.seconds addObject:s]; + i++; + j++; + } +} + + +- (void)setupPickerViewNumbers { + [self setupHours]; + [self setupMinutes]; + [self setupSeconds]; + + self.pickerViewNumbers = [[NSMutableArray alloc] initWithObjects:self.hours, + self.minutes, self.seconds, nil]; +} + +- (IBAction)startButtonTapped:(UIButton *)sender { + if (!self.isStarted) { + for (int i = 0; i < 3; i++) { + if ([self.timerPickerView selectedRowInComponent:i] != 00){ + NSLog(@"Started timer"); + self.isStarted = YES; + self.isInitial = NO; + [self.startButton setTitle:@"Pause" forState:UIControlStateNormal]; + [self.timerPickerView setUserInteractionEnabled:NO]; + self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(animate) userInfo:nil repeats:YES]; + [[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes]; + + break; + } + } + } else { + NSLog(@"Paused timer"); + [self freeze]; + //self.isPaused = YES; + [self.startButton setTitle:@"Start" forState:UIControlStateNormal]; + } + +} + +- (void)freeze { + self.isStarted = NO; + [self.timer invalidate]; + self.timer = nil; + self.isInitial = NO; +} + +- (void)animate { + + NSInteger hourIndex = [self.timerPickerView selectedRowInComponent:0]; + NSInteger minuteIndex = [self.timerPickerView selectedRowInComponent:1]; + NSInteger secondIndex = [self.timerPickerView selectedRowInComponent:2]; + + if ( (hourIndex == 00) && (minuteIndex % 60 == 00) && (secondIndex % 60 == 00) ) { + [self.timer invalidate]; + self.timer = nil; + } else { + if (secondIndex % 60 == 00) { + + self.row = secondIndex + 59; + [self.timerPickerView selectRow:self.row inComponent:2 animated:YES]; + + if (minuteIndex != 00) { + self.row = minuteIndex -1; + [self.timerPickerView selectRow:self.row inComponent:1 animated:YES]; + + } else if (hourIndex != 00) { + + //hour + self.row = hourIndex - 1; + [self.timerPickerView selectRow:self.row inComponent:0 animated:YES]; + + //minute + if (minuteIndex % 60 == 00) { + self.row = minuteIndex + 59; + [self.timerPickerView selectRow:self.row inComponent:1 animated:YES]; + + } else { + self.row = minuteIndex - 1; + [self.timerPickerView selectRow:self.row inComponent:1 animated:YES]; + } + + //second + if (secondIndex % 60 == 00) { + self.row = secondIndex +59; + [self.timerPickerView selectRow:self.row inComponent:2 animated:YES]; + } else { + self.row = secondIndex - 1; + [self.timerPickerView selectRow:self.row inComponent:2 animated:YES]; + } + } + } else { + self.row = secondIndex - 1; + [self.timerPickerView selectRow:self.row inComponent:2 animated:YES]; + } + } +} + +- (void)reloadComponent:(NSInteger)component{ + [self.timerPickerView selectRow:self.row inComponent:self.component animated:YES]; +} + +- (IBAction)resetButtonTapped:(UIButton *)sender { + self.timerName.text = @" "; + self.isStarted = NO; + if(![self.startButton.titleLabel.text isEqualToString:@"Start"]){ + [self.startButton setTitle:@"Start" forState:UIControlStateNormal]; + } + [self.timerPickerView setUserInteractionEnabled:YES]; + self.startButton.enabled = YES; + [self.timerPickerView reloadAllComponents]; + for(int i=0;i<3 ;i++){ + [self.timerPickerView selectRow:0 inComponent:i animated:YES]; + } + [self.timer invalidate]; + self.timer = nil; +} + +- (IBAction)presetButtonTapped:(id)sender { + self.isInitial = NO; + [self.timer invalidate]; + self.timer = nil; + //self.isPreset = YES; + self.isStarted = NO; + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; + UINavigationController *presetsNC = [storyboard instantiateViewControllerWithIdentifier:@"presetsNavigationController"]; + NSArray *viewControllers = [presetsNC viewControllers]; + PresetsTableViewController *presetsViewController = viewControllers[0]; + [presetsViewController setDelegate:self]; + + [self presentViewController:presetsNC animated:YES completion:nil]; +} + +- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { + self.component = component; + self.row = row; +} + + +#pragma mark - data source and delegate for PickerView +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { + return [self.pickerViewNumbers count]; +} + +- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { + return [self.pickerViewNumbers[component] count]; +} + +- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { + return self.pickerViewNumbers[component][row]; +} + +- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view { + + UILabel *viewAsLabel = (UILabel *)view; + + if(!viewAsLabel) { + viewAsLabel = [[UILabel alloc] init]; + [viewAsLabel setFont:[UIFont fontWithName:@"DigitalReadoutExpUpright" size:50]]; + [viewAsLabel setTextAlignment:NSTextAlignmentCenter]; +// [viewAsLabel setBackgroundColor:[UIColor colorWithRed:206.0/255 green:230.0/255 blue:213.0/255 alpha:1]]; + [viewAsLabel setBackgroundColor:[UIColor colorWithRed:198.0/255 green:230.0/255 blue:204.0/255 alpha:1.0]]; + [viewAsLabel setTextColor:[UIColor colorWithRed:255/255 green:62.0/255 blue:127.0/255 alpha:1.0]]; + } + + if (component == 0) { + viewAsLabel.text = [self.hours objectAtIndex:row]; + } else if (component == 1) { + viewAsLabel.text = [self.minutes objectAtIndex:row]; + } else { + viewAsLabel.text = [self.seconds objectAtIndex:row]; + } + + return viewAsLabel; +} + + +- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component { + return 80; +} + +#pragma mark - PresetsTableViewControllerDelegate implementation +- (void)presetTime:(NSArray *)presetTime withName:(NSString *)name { + self.presetTime = presetTime; + self.timerName.text = name; + + [self.timerPickerView selectRow:[self.presetTime[0] intValue] inComponent:0 animated:YES]; + [self.timerPickerView selectRow:[self.presetTime[1] intValue] inComponent:1 animated:YES]; + [self.timerPickerView selectRow:[self.presetTime[2] intValue] inComponent:2 animated:YES]; + NSLog(@"Timer name: %@ and value: %@",self.timerName.text, self.presetTime); +} + +@end diff --git a/Time/Time/ViewController.h b/Time/Time/ViewController.h deleted file mode 100644 index 9d0e38f..0000000 --- a/Time/Time/ViewController.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// ViewController.h -// Time -// -// Created by Michael Kavouras on 8/20/15. -// Copyright (c) 2015 Mike Kavouras. All rights reserved. -// - -#import - -@interface ViewController : UIViewController - - -@end - diff --git a/Time/Time/ViewController.m b/Time/Time/ViewController.m deleted file mode 100644 index 194fe5f..0000000 --- a/Time/Time/ViewController.m +++ /dev/null @@ -1,27 +0,0 @@ -// -// ViewController.m -// Time -// -// Created by Michael Kavouras on 8/20/15. -// Copyright (c) 2015 Mike Kavouras. All rights reserved. -// - -#import "ViewController.h" - -@interface ViewController () - -@end - -@implementation ViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - // Do any additional setup after loading the view, typically from a nib. -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -@end