154 Commits

Author SHA1 Message Date
Hykilpikonna 441dae5caf Merge branch 'main' into account 2021-01-23 23:26:03 -05:00
Hykilpikonna 74870197f9 [F] Fix testing alarm 2021-01-23 23:19:54 -05:00
Dallon Archibald b71a2463c9 Linked Reference 2021-01-23 20:30:10 -05:00
Dallon Archibald 1cd6e73ac4 Finished Everything - fix time display and hiding buttons 2021-01-23 20:26:33 -05:00
Dallon Archibald e18edd26d2 Updated Display Time to be More Appealing 2021-01-23 19:49:34 -05:00
Dallon Archibald e0c0e24188 Configured Basic Functionalities and Updated Table Functions 2021-01-23 19:18:50 -05:00
Dallon Archibald 26c2b2832e Testing/Displaying Count 2021-01-23 18:50:10 -05:00
Dallon Archibald 4ff0455afd Edited table view display 2021-01-23 18:44:16 -05:00
Dallon Archibald 34cc04cd63 Table Cell Prototype 2021-01-23 18:41:31 -05:00
Dallon Archibald 74c2c76af9 Implemented and linked UI elements 2021-01-23 17:58:27 -05:00
Dallon Archibald e6817bd795 Created Stopwatch controller and adjusted/linked tab bar 2021-01-23 17:34:28 -05:00
Aaron 148a104a4c Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-23 17:09:39 -05:00
Aaron 2a9cb8e677 Theoretical RPS WVM completed 2021-01-23 17:09:31 -05:00
Dallon Archibald ff22e44140 Corrected error 2021-01-23 16:54:34 -05:00
Aaron 5b576a7912 Fixed storyboard 2021-01-23 16:49:05 -05:00
Aaron 5a6534b1f1 Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-23 16:47:38 -05:00
Aaron 219de54856 Adjusted RPS related actions 2021-01-23 16:47:31 -05:00
Dallon Archibald 5800cd9774 RPS UI Design 2021-01-23 16:47:17 -05:00
Aaron e461dae024 Redesigned RPS class 2021-01-23 16:30:33 -05:00
Hykilpikonna f8cac67055 [+] Deploy server 2021-01-22 22:10:08 -05:00
Hykilpikonna 72b0cc92b6 [+] Merge Account Branch: Implement Register, Login, Logout, Delete
[+] Merge Account Branch: Implement Register, Login, Logout, Delete
2021-01-22 18:16:26 -05:00
Hykilpikonna 7435c04348 [+] Implement delete button 2021-01-22 18:13:36 -05:00
Hykilpikonna a774446a30 [+] Link deleteAccount button 2021-01-22 18:10:27 -05:00
Hykilpikonna 16046f7375 [U] Update usage to call encapsulated method 2021-01-22 18:10:03 -05:00
Hykilpikonna 39dd83f287 [+] Encapsulate http requests inside view controllers 2021-01-22 18:09:42 -05:00
Hykilpikonna 3e601e474e [+] Add error message for username doesn't exist 2021-01-22 17:59:30 -05:00
Hykilpikonna 6695f264ae [+] Add error message for incorrect username/password 2021-01-22 17:59:06 -05:00
Hykilpikonna 9054f13af7 [F] Fix "Strong password" bug 2021-01-22 17:57:38 -05:00
Hykilpikonna 3ceeac07bc [+] Add error message for account exists 2021-01-22 17:52:06 -05:00
Hykilpikonna e1ff034115 [O] Encapsulate ui{} inside alarm.dismiss{} 2021-01-22 17:46:04 -05:00
Hykilpikonna aa602051d1 [+] Add comments 2021-01-22 17:44:52 -05:00
Hykilpikonna 5835006985 [F] Fix "Main thread only" errors 2021-01-22 17:44:46 -05:00
Hykilpikonna e9196bb249 [-] Remove backup features and add default avatar 2021-01-22 17:44:19 -05:00
Hykilpikonna e32b3a4db9 [+] Implement logout and display 2021-01-22 17:26:27 -05:00
Hykilpikonna a505a8e553 [+] Create display function in ManageVC that displays account info after login 2021-01-22 17:24:36 -05:00
Hykilpikonna 5ee0ee4f4e [+] Create logout function 2021-01-22 17:24:02 -05:00
Hykilpikonna 4e4ea76d7e [+] Allow insecure http access for localhost 2021-01-22 17:02:39 -05:00
Hykilpikonna b3053d2673 [F] Fix localStorage login detection 2021-01-22 17:00:55 -05:00
Hykilpikonna 9bb4d0ccf1 [+] Automatically check login status on start 2021-01-22 16:54:20 -05:00
Hykilpikonna b1e11b8bc2 [+] Switch isHidden on login 2021-01-22 16:54:06 -05:00
Hykilpikonna 520d4bb6a3 [+] Specify input type to username and password 2021-01-22 16:53:40 -05:00
Hykilpikonna 325792ff13 [F] Fix forgot to pass in params 2021-01-22 16:51:36 -05:00
Hykilpikonna 746d3ff229 [+] Create AccountViewController.this.login() to show account view after login 2021-01-22 16:45:15 -05:00
Hykilpikonna 33d3739005 [+] Combine user login and registration into one function 2021-01-22 16:43:43 -05:00
Hykilpikonna 4a635aadce [+] Encapsulate UserDefaults subscript 2021-01-22 16:34:40 -05:00
Hykilpikonna e53cc408e2 [+] Encapsulate UI update closure 2021-01-22 16:27:34 -05:00
Hykilpikonna 45cf2b768e [O] Cleanup http request encapsulations 2021-01-22 16:18:05 -05:00
Hykilpikonna 6cb4b75f82 [F] Fix trying to parse string values as jsons 2021-01-22 16:14:02 -05:00
Hykilpikonna 1aeb6fb666 [F] Use POST request + headers 2021-01-22 16:13:44 -05:00
Hykilpikonna 2ced920106 [+] Add login API 2021-01-22 15:42:39 -05:00
Hykilpikonna 021368d7bb [+] Display request errors 2021-01-22 15:38:33 -05:00
Hykilpikonna 306d4bfaf1 [+] Dismiss alert after receiving the response 2021-01-22 15:37:13 -05:00
Hykilpikonna f37a12c963 [O] Return the alert so that it can be dismissed programmatically 2021-01-22 15:23:55 -05:00
Hykilpikonna e790bca040 [+] Send registration request 2021-01-22 15:19:20 -05:00
Hykilpikonna 8f829217c1 [+] Add parameter "okayable" to alert function 2021-01-22 15:18:49 -05:00
Hykilpikonna facf8eaeec [F] Fix optional in password text unwrapping 2021-01-22 15:08:02 -05:00
Hykilpikonna a375f16947 [+] Verify username and password for register 2021-01-22 15:07:09 -05:00
Hykilpikonna 788eb4973a [+] Encapsulate Regex matching stuff 2021-01-22 15:02:05 -05:00
Hykilpikonna 9ee1132d7d [+] Encapsulate sending an alert 2021-01-22 14:54:00 -05:00
Hykilpikonna a3dfff1e38 [+] Encapsulate SHA256 hashing 2021-01-22 14:45:59 -05:00
Hykilpikonna 6f76ff90cd [+] Create Login view controller 2021-01-22 14:05:02 -05:00
Hykilpikonna cd6d81c3b3 [O] Give credit to https://stackoverflow.com/a/43132311/7346633 for MathExpression 2021-01-22 14:04:41 -05:00
Aaron 6d0aa461c3 Redesigned RPS class. 2021-01-22 13:18:00 -05:00
Aaron bf7e746aff Changed Puzzle WVM to Factor 2021-01-22 13:06:44 -05:00
Aaron 1223e42c46 Added endAlarm function. 2021-01-22 13:00:20 -05:00
Aaron 083b5a05e0 Fixed optional unwrapping 2021-01-22 12:56:52 -05:00
Hykilpikonna 259137170d [F] Fix MathExpressions.swift indentation and add comments 2021-01-22 10:35:17 -05:00
Hykilpikonna e165beb3aa [-] Remove accelerometer test 2021-01-22 10:19:30 -05:00
Hykilpikonna e255f8811e [O] Optimize Andrew's setData 2021-01-22 10:11:22 -05:00
Andrew 2cbfa70658 Credit internet for MathExpressions and now display 12-hour clock instead of 24 hour 2021-01-21 17:15:52 -05:00
Dallon Archibald c187403e29 Updated the delete button for alarms 2021-01-21 14:54:38 -05:00
Aaron f8b78cfbc4 Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-21 14:37:08 -05:00
Aaron 386e3f988e PuzzleAlarm functions (No UI) 2021-01-21 14:36:52 -05:00
Dallon Archibald 1bc2f95749 Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-21 14:34:55 -05:00
Dallon Archibald da46725420 Added rock, paper, scissors class. Need to connect outlets/actions and implement condition to leave (its repeating rn) 2021-01-21 14:34:41 -05:00
Aaron 751c92fe14 Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-21 14:31:34 -05:00
Aaron e41c0ea067 Revert "Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main"
This reverts commit ecd15bb30a, reversing
changes made to acfcdbed24.
2021-01-21 14:29:56 -05:00
Aaron ecd15bb30a Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-21 14:29:30 -05:00
Andrew 431650c366 Sorry! Again 2021-01-21 14:27:31 -05:00
Aaron acfcdbed24 Integrating PuzzleWakeMethod (1/2) 2021-01-21 14:27:27 -05:00
Andrew d200984eaf Simpler Quadratic Problems with a-value of 1 2021-01-21 14:26:56 -05:00
Hykilpikonna d999944dfa [F] Forgot to commit the storyboard 2021-01-21 13:58:28 -05:00
Hykilpikonna 634ad5aaf8 [+] Add a button to stop an alarm 2021-01-21 13:57:37 -05:00
Aaron 2eeb560fbb Started noticiation logic. 2021-01-21 13:46:08 -05:00
Aaron 9312184177 Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-21 09:33:05 -05:00
Aaron 17b300e74c Update AlarmActivationViewController.swift 2021-01-21 09:32:56 -05:00
Hykilpikonna 996a1b343b [PR][F] Vanilla - Fix date index out of range error.
[F] Fix date index out of range error.
2021-01-20 23:51:33 -05:00
VergeDX 03e52c7cb4 [F] Fix date index out of range error. 2021-01-21 10:37:54 +08:00
Hykilpikonna d9a1fe4649 Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-20 15:31:04 -05:00
Hykilpikonna 950e86302c [+] Write comments for Dallon's Code 2021-01-20 15:30:24 -05:00
Andrew b987823a8e Three Simple Math Problems Added
Two simple Algebra Problem (one with two expressions and one with three expressions) and a quadratic problem
2021-01-20 15:18:43 -05:00
Dallon Archibald 5a64dab670 Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-20 11:34:46 -05:00
Dallon Archibald ef72aa8b91 Added alarm name in storyboard and started implementation of adding alarms 2021-01-20 11:34:33 -05:00
Andrew e9d0500132 Math Expression Class to generate math problems 2021-01-20 11:24:53 -05:00
Aaron d5cfddb3fb Merge branch 'main' of github.com:hykilpikonna/ProjectClock into main 2021-01-20 11:24:00 -05:00
Aaron 84e4358fbc Added WakeMethod differentiation 2021-01-20 11:23:50 -05:00
Dallon Archibald f9c1af7fd8 Corrected outlets 2021-01-20 11:10:10 -05:00
Dallon Archibald 54dad7f1d4 Implemented basic outlets 2021-01-20 11:03:36 -05:00
Andrew 56fb9b6a3d setData function
Terrible code, but it works...

With Love,
Andrew Vittiglio
2021-01-19 11:44:05 -05:00
Aaron e0fd1e758d Merge branch 'experimental' into main 2021-01-19 08:31:06 -05:00
Hykilpikonna 26752f607e [F] Refresh table when alarms are changed 2021-01-17 17:10:58 -05:00
Hykilpikonna a57ab9c2f8 [F] Add debug alarm with lastActivate one minutes prior 2021-01-17 16:38:51 -05:00
Hykilpikonna 2c5f28c97b [O] Implement obj.apply {} like Kotlin 2021-01-17 16:34:20 -05:00
Hykilpikonna 7e4dc51da8 [O] Move default values to alarm constructor 2021-01-17 16:30:18 -05:00
Hykilpikonna 2cd464c890 [+] Add button to delete all alarms 2021-01-17 16:27:51 -05:00
Hykilpikonna d01d56b6ef [O] Loop alarm sound + vibration 2021-01-17 16:18:56 -05:00
Hykilpikonna 788d43e333 [F] Fix alarm detection in the same minute 2021-01-17 16:18:28 -05:00
Hykilpikonna a493bfe6e8 [+] Disable alarm after activating 2021-01-17 16:00:56 -05:00
Hykilpikonna c54e18ad64 [O] Make Alarm a class 2021-01-17 15:59:25 -05:00
Hykilpikonna ce9cbd7127 [F] Fix no segue with identifier 'activate-alarmactivate-alarm'' 2021-01-17 15:48:23 -05:00
Hykilpikonna 33c6173785 [+] Play sound when alarm is activated 2021-01-17 15:48:07 -05:00
Hykilpikonna cb80b2925d [+] Create add alarm debug button 2021-01-17 15:47:20 -05:00
Hykilpikonna 06d639c912 [-] Remove unlinked outlets 2021-01-17 15:14:55 -05:00
Hykilpikonna d90c792436 [+] Allow AlarmActivator to segue to the alarm activating view 2021-01-17 15:13:11 -05:00
Hykilpikonna f88c48b9ad [+] Get alarms to activate in AlarmActivator 2021-01-17 15:04:17 -05:00
Hykilpikonna ce758633b0 [F] Use lastActivate as the base for nextActivate rather than current date 2021-01-17 14:58:28 -05:00
Hykilpikonna d0ab0ba81d [+] Authorize badge and sound for alerts too 2021-01-17 14:57:01 -05:00
Hykilpikonna a4de8274d4 [M] Rearrange files 2021-01-17 14:56:10 -05:00
Hykilpikonna 31afd97850 [+] Set alarm table cell's going off text 2021-01-17 14:50:13 -05:00
Hykilpikonna a3252603fb [+] Create toString for TimeInterval 2021-01-17 14:48:58 -05:00
Hykilpikonna e0b6eb41fd [+] Create function to get alarms activating now 2021-01-17 14:31:29 -05:00
Hykilpikonna ba50233bd2 [+] Allow one-time alarms to bypass repeating date check 2021-01-17 14:27:36 -05:00
Hykilpikonna 79202c71f3 [+] Make sure it repeats on that day 2021-01-17 14:26:17 -05:00
Hykilpikonna 7e17405858 [+] Create computed field nextActivate to calculate the next activation date for an alarm 2021-01-17 14:25:35 -05:00
Hykilpikonna c3c2142418 [+] Add autoDisable field to alarm 2021-01-17 14:25:03 -05:00
Hykilpikonna 251b281a04 [+] Add repeats field to alarm 2021-01-17 14:24:43 -05:00
Hykilpikonna ce9cf95e47 [O] Use hour + minute instead of Date when storing alarm time 2021-01-17 14:24:26 -05:00
Hykilpikonna 3cc0672d26 [+] Create function date.added() to modify the date 2021-01-17 14:23:28 -05:00
Hykilpikonna fd332ad9f4 [+] Create function date.get() to get any date components from a date 2021-01-17 14:23:12 -05:00
Hykilpikonna c1e49ed66f [+] Create function to get hour, minute, second from date 2021-01-17 13:51:21 -05:00
Hykilpikonna bf37dd657c [+] Create function to create date from year, month, day, hour, min 2021-01-17 13:48:36 -05:00
Hykilpikonna 395a7ecdec [+] Create function to get year, month, day from date 2021-01-17 13:48:17 -05:00
Hykilpikonna 650c48ade9 [U] Update alarm instantiation 2021-01-17 13:26:47 -05:00
Hykilpikonna 6b89b930fc [+] Add toString to Date 2021-01-17 13:25:04 -05:00
Hykilpikonna c30f78efbb [+] Create enabled field in Alarm 2021-01-17 13:17:19 -05:00
Hykilpikonna c3fc3e827f [U] Update function calls 2021-01-17 13:14:19 -05:00
Hykilpikonna 02d8b40831 [+] Create Alarms object and save and read functions 2021-01-17 13:12:13 -05:00
Hykilpikonna 0571645df7 [+] Display local alarms in Alarm table 2021-01-17 13:01:17 -05:00
Hykilpikonna bbd1520f5d [+] Create function to get local alarms 2021-01-17 13:00:52 -05:00
Hykilpikonna 04b4798ac3 [+] Write default alarm on app start 2021-01-17 13:00:38 -05:00
Hykilpikonna 8a90bf21bf [O] Make models json-encodable 2021-01-17 12:55:38 -05:00
Hykilpikonna f33c1d8d1c [+] Create JSON class 2021-01-17 12:55:05 -05:00
Hykilpikonna 1284b4ec36 [O] Make debug view look better 2021-01-17 10:40:01 -05:00
Hykilpikonna 19388c2db0 [+] Write down the observed behavior of Timer 2021-01-17 10:34:53 -05:00
Hykilpikonna 879689a10a [+] Start alarm detector on app start 2021-01-17 10:33:29 -05:00
Hykilpikonna 30756d32aa [+] Create AlarmDetector 2021-01-17 10:32:23 -05:00
Hykilpikonna cb5515e54a [F] Fix Alarms view constraints 2021-01-17 09:36:17 -05:00
Hykilpikonna 27184eff9d [M] Move WVM class to Models.swift 2021-01-17 09:11:46 -05:00
Hykilpikonna 702f4135a6 [M] Move Alarm class to Models.swift 2021-01-14 11:58:23 -05:00
Hykilpikonna 7be4b6ab97 [+] Create familyJoin and familyLeave endpoints 2021-01-14 11:16:47 -05:00
Hykilpikonna a1d149b1ee [+] Create endpoint to change family pin 2021-01-14 11:13:49 -05:00
Hykilpikonna f6d2fb66ed [+] Add log out button 2021-01-14 11:11:35 -05:00
Hykilpikonna fc2792ec37 [+] Create familyCreate and familyDelete endpoint vars 2021-01-14 11:10:17 -05:00
Hykilpikonna bd663772fb [+] Create family model 2021-01-14 11:08:25 -05:00
19 changed files with 1925 additions and 404 deletions
+26 -18
View File
@@ -9,11 +9,12 @@
/* Begin PBXBuildFile section */
4F509BD225AE22D100726227 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F509BD125AE22D100726227 /* Models.swift */; };
4F8A607125A9160400D88DC3 /* AddAlarmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F8A607025A9160400D88DC3 /* AddAlarmViewController.swift */; };
4F8A607525A919E600D88DC3 /* Logic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F8A607425A919E600D88DC3 /* Logic.swift */; };
4F98955225A9260400F51321 /* Net.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F98955125A9260400F51321 /* Net.swift */; };
4FA419AF25AF93EC004CE0FC /* AlarmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA419AE25AF93EC004CE0FC /* AlarmViewController.swift */; };
4FD642D325B48C380069171E /* AlarmActivator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD642D225B48C380069171E /* AlarmActivator.swift */; };
4FD642DB25B4B7F60069171E /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD642DA25B4B7F60069171E /* Utils.swift */; };
4FD642E025B4D5F30069171E /* AlarmActivationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FD642DF25B4D5F30069171E /* AlarmActivationViewController.swift */; };
4FF0683F25A5F18700304E6B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FF0683E25A5F18700304E6B /* AppDelegate.swift */; };
4FF0684125A5F18700304E6B /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FF0684025A5F18700304E6B /* SceneDelegate.swift */; };
4FF0684325A5F18700304E6B /* AccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FF0684225A5F18700304E6B /* AccountViewController.swift */; };
4FF0684625A5F18700304E6B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4FF0684425A5F18700304E6B /* Main.storyboard */; };
4FF0684825A5F18800304E6B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4FF0684725A5F18800304E6B /* Assets.xcassets */; };
@@ -21,18 +22,20 @@
7C5DAE9C25AF812200E44C52 /* clock.png in Resources */ = {isa = PBXBuildFile; fileRef = 7C5DAE9B25AF812200E44C52 /* clock.png */; };
7C83963625AF375B0027A94C /* NotificationLogic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C83963525AF375B0027A94C /* NotificationLogic.swift */; };
7C83963925AF68980027A94C /* TestingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C83963825AF68980027A94C /* TestingViewController.swift */; };
7C83963C25AF6B6B0027A94C /* Alarm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C83963B25AF6B6B0027A94C /* Alarm.swift */; };
C7E638E825B88F8B00799512 /* MathExpressions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7E638E725B88F8B00799512 /* MathExpressions.swift */; };
F0DF7C0725BCD9FC0064A26B /* StopwatchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0DF7C0625BCD9FC0064A26B /* StopwatchViewController.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
4F509BD125AE22D100726227 /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = "<group>"; };
4F8A607025A9160400D88DC3 /* AddAlarmViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAlarmViewController.swift; sourceTree = "<group>"; };
4F8A607425A919E600D88DC3 /* Logic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logic.swift; sourceTree = "<group>"; };
4F98955125A9260400F51321 /* Net.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Net.swift; sourceTree = "<group>"; };
4FA419AE25AF93EC004CE0FC /* AlarmViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmViewController.swift; sourceTree = "<group>"; };
4FD642D225B48C380069171E /* AlarmActivator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmActivator.swift; sourceTree = "<group>"; };
4FD642DA25B4B7F60069171E /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
4FD642DF25B4D5F30069171E /* AlarmActivationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmActivationViewController.swift; sourceTree = "<group>"; };
4FF0683B25A5F18700304E6B /* ProjectClock.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ProjectClock.app; sourceTree = BUILT_PRODUCTS_DIR; };
4FF0683E25A5F18700304E6B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
4FF0684025A5F18700304E6B /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
4FF0684225A5F18700304E6B /* AccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountViewController.swift; sourceTree = "<group>"; };
4FF0684525A5F18700304E6B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
4FF0684725A5F18800304E6B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -43,7 +46,8 @@
7C83962F25AF34F10027A94C /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; };
7C83963525AF375B0027A94C /* NotificationLogic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationLogic.swift; sourceTree = "<group>"; };
7C83963825AF68980027A94C /* TestingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingViewController.swift; sourceTree = "<group>"; };
7C83963B25AF6B6B0027A94C /* Alarm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alarm.swift; sourceTree = "<group>"; };
C7E638E725B88F8B00799512 /* MathExpressions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MathExpressions.swift; sourceTree = "<group>"; };
F0DF7C0625BCD9FC0064A26B /* StopwatchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StopwatchViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -77,23 +81,25 @@
4FF0683D25A5F18700304E6B /* ProjectClock */ = {
isa = PBXGroup;
children = (
4FF0683E25A5F18700304E6B /* AppDelegate.swift */,
4FF0684025A5F18700304E6B /* SceneDelegate.swift */,
7C5DAE9B25AF812200E44C52 /* clock.png */,
4FF0684C25A5F18800304E6B /* Info.plist */,
7C83962D25AF34F00027A94C /* ProjectClock.entitlements */,
4FF0684925A5F18800304E6B /* LaunchScreen.storyboard */,
4FF0684725A5F18800304E6B /* Assets.xcassets */,
4FF0683E25A5F18700304E6B /* AppDelegate.swift */,
4FF0684225A5F18700304E6B /* AccountViewController.swift */,
4FA419AE25AF93EC004CE0FC /* AlarmViewController.swift */,
4F8A607025A9160400D88DC3 /* AddAlarmViewController.swift */,
7C83963825AF68980027A94C /* TestingViewController.swift */,
4FD642DF25B4D5F30069171E /* AlarmActivationViewController.swift */,
4FD642D225B48C380069171E /* AlarmActivator.swift */,
4FF0684425A5F18700304E6B /* Main.storyboard */,
4FF0684725A5F18800304E6B /* Assets.xcassets */,
4FF0684925A5F18800304E6B /* LaunchScreen.storyboard */,
4FF0684C25A5F18800304E6B /* Info.plist */,
4F8A607425A919E600D88DC3 /* Logic.swift */,
F0DF7C0625BCD9FC0064A26B /* StopwatchViewController.swift */,
7C83963525AF375B0027A94C /* NotificationLogic.swift */,
4F98955125A9260400F51321 /* Net.swift */,
7C5DAE9B25AF812200E44C52 /* clock.png */,
4F509BD125AE22D100726227 /* Models.swift */,
7C83963825AF68980027A94C /* TestingViewController.swift */,
7C83963B25AF6B6B0027A94C /* Alarm.swift */,
C7E638E725B88F8B00799512 /* MathExpressions.swift */,
4FD642DA25B4B7F60069171E /* Utils.swift */,
);
path = ProjectClock;
sourceTree = "<group>";
@@ -182,15 +188,17 @@
files = (
4F8A607125A9160400D88DC3 /* AddAlarmViewController.swift in Sources */,
4F98955225A9260400F51321 /* Net.swift in Sources */,
4F8A607525A919E600D88DC3 /* Logic.swift in Sources */,
7C83963925AF68980027A94C /* TestingViewController.swift in Sources */,
4FF0684325A5F18700304E6B /* AccountViewController.swift in Sources */,
F0DF7C0725BCD9FC0064A26B /* StopwatchViewController.swift in Sources */,
4FF0683F25A5F18700304E6B /* AppDelegate.swift in Sources */,
4FF0684125A5F18700304E6B /* SceneDelegate.swift in Sources */,
4FD642D325B48C380069171E /* AlarmActivator.swift in Sources */,
4FD642DB25B4B7F60069171E /* Utils.swift in Sources */,
4FA419AF25AF93EC004CE0FC /* AlarmViewController.swift in Sources */,
7C83963C25AF6B6B0027A94C /* Alarm.swift in Sources */,
4F509BD225AE22D100726227 /* Models.swift in Sources */,
C7E638E825B88F8B00799512 /* MathExpressions.swift in Sources */,
7C83963625AF375B0027A94C /* NotificationLogic.swift in Sources */,
4FD642E025B4D5F30069171E /* AlarmActivationViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+163
View File
@@ -7,10 +7,173 @@
import UIKit
/**
Account view controller controlling the two separate view controllers
*/
class AccountViewController: UIViewController
{
@IBOutlet var vLogin: UIView!
@IBOutlet var vManage: UIView!
// For instance references
static var this: AccountViewController!
/**
Called when the user switch to this tab
*/
override func viewDidLoad()
{
// Static instance reference
AccountViewController.this = self
// Check if already registered/logged in
if localStorage.string(forKey: "id") != nil { login() }
super.viewDidLoad()
}
/**
Login from the account page
*/
func login()
{
vLogin.isHidden = true
vManage.isHidden = false
ManageVC.this.display()
}
/**
Logout
*/
func logout()
{
// Remove login info
["id", "user", "pass"].forEach { localStorage.removeObject(forKey: $0) }
// Switch UI
vLogin.isHidden = false
vManage.isHidden = true
}
}
/**
View controller for registration and login
*/
class LoginVC: UIViewController
{
@IBOutlet weak var username: UITextField!
@IBOutlet weak var password: UITextField!
/**
Send user login/registration request
- Parameter login: True: Login, False: Register
*/
func userRequest(login: Bool)
{
// Verify username and password
guard let name = username.text, name ~= "[A-Za-z0-9_-]{3,16}" else
{
msg("Username Invalid", "Username must be 3 to 16 characters long, and must only contain a-z, 0-9, underscore, and minus signs (-).")
return
}
guard let pass = password.text, pass.count >= 8 else
{
msg("Password Invalid", "Password must be more than or equal to 8 characters long")
return
}
// Error messages
let errors = ["409 - [\"A0111\"]": "Account already exists, please login instead.",
"401 -": "Incorrect username/password",
"404 -": "Username does not exist in the database",
"406 - [\"A0101\"]": "Username invalid."
]
// Send register request
sendReq(login ? APIs.login : APIs.register,
title: login ? "Logging in..." : "Registering...", errors: errors,
params: ["username": name, "password": pass.sha256])
{
// Store username and password
localStorage["name"] = name
localStorage["pass"] = pass.sha256
localStorage["id"] = $0
// Send feedback
if login { self.msg("Login success!", "Now you can use account features, yay!") }
else { self.msg("Registration success!", "Now you have an account, yay!") }
// Hide registration and show account detail view
AccountViewController.this.login()
}
}
/**
Called when the user clicks register
*/
@IBAction func register(_ sender: Any)
{
userRequest(login: false)
}
/**
Called when the user clicks login
*/
@IBAction func login(_ sender: Any)
{
userRequest(login: true)
}
}
/**
Account manage view controller
*/
class ManageVC: UIViewController
{
static var this: ManageVC!
@IBOutlet weak var lUsername: UILabel!
@IBOutlet weak var lJoinDate: UILabel!
/**
Called when the user switched to the account tab (whether the view container is hidden or not)
*/
override func viewDidLoad()
{
// Static reference
ManageVC.this = self
super.viewDidLoad()
}
/**
Display account info
*/
func display()
{
lUsername.text = localStorage.string(forKey: "name")
// TODO: Correct join date
lJoinDate.text = localStorage.string(forKey: "id")
}
/**
Called when the user clicks the logout button
*/
@IBAction func logout(_ sender: Any)
{
AccountViewController.this.logout()
}
/**
Called when the user clicks the delete account button
*/
@IBAction func deleteAccount(_ sender: Any)
{
sendReq(APIs.delete, title: "Deleting...")
{
print("Deleted! \($0)")
self.msg("Deleted!", "You are erased from our database, you no longer exist.")
self.logout(sender)
}
}
}
+44 -3
View File
@@ -17,14 +17,55 @@ class AddAlarmViewController: UIViewController
scrollView.addSubview(scrollViewInner)
scrollView.contentSize = scrollViewInner.frame.size
}
// Pickers
@IBOutlet weak var timePicker: UIDatePicker!
@IBOutlet weak var wvmPicker: UIPickerView!
override func viewDidLoad()
// UI Elements
@IBOutlet weak var repeatWeekdaysSwitch: UISwitch!
@IBOutlet weak var repeatWeekendsSwitch: UISwitch!
@IBOutlet weak var alarmNameTextField: UITextField!
@IBAction func defaultRingtonesButton(_ sender: Any)
{
super.viewDidLoad()
}
@IBAction func soundLibraryButton(_ sender: Any)
{
}
/**
Called when the user clicks the remove button and brings them back to the home page
*/
@IBAction func cancelAlarmButton(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
//might need to reset all UI elements
}
/**
Called when the user clicks Add Alarm
*/
@IBAction func addAlarmButton(_ sender: Any) {
let (h, m, _) = timePicker.date.getHMS()
// Create the alarm
let alarm = Alarm(hour: h, minute: m,
text: alarmNameTextField.text ?? "Alarm",
wakeMethod: wvms[wvmPicker.selectedRow(inComponent: 0)],
lastActivate: Date())
// TODO: Set alarm.repeats to correspond with what the user selects
// Add the alarm to the list and save the list
Alarms.fromLocal().apply { $0.list.append(alarm) }.localSave();
// Dismiss this view
self.dismiss(animated: true, completion: nil)
}
}
-22
View File
@@ -1,22 +0,0 @@
//
// Alarm.swift
// ProjectClock
//
// Created by Aaron Saporito on 1/13/21.
//
import Foundation
class Alarm {
var alarmTime: Date
var text: String
var wakeMethod: WVM
init(alarmTime: Date, text: String, wakeMethod: WVM) {
self.alarmTime = alarmTime
self.text = text
self.wakeMethod = wakeMethod
}
}
@@ -0,0 +1,122 @@
//
// AlarmActivationViewController.swift
// ProjectClock
//
// Created by Hykilpikonna on 1/17/21.
//
import UIKit
import AVFoundation
class AlarmActivationViewController: UIViewController
{
var timer: Timer?
var currentAlarm: Alarm?
//Puzzle outlets
@IBOutlet weak var puzzleView: UIView!
@IBOutlet weak var puzzleQuestionLabel: UILabel!
@IBOutlet weak var puzzleAnswerInput: UITextField!
var puzzleAnswers: [Int] = []
//RPS Outlets
@IBOutlet weak var rpsView: UIView!
@IBOutlet weak var rpsResult: UILabel!
init?(coder: NSCoder, currentAlarm: Alarm)
{
self.currentAlarm = currentAlarm
//print(currentAlarm.wakeMethod)
super.init(coder: coder)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad()
{
super.viewDidLoad()
//Hide all inactive wakemethods
puzzleView.isHidden = true
rpsView.isHidden = true
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(AlarmActivationViewController.playSound), userInfo: nil, repeats: true)
setAlarmType()
//print(MathExpression.random())
}
@objc func playSound()
{
AudioServicesPlayAlertSound(SystemSoundID(1005))
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate)
}
func setAlarmType()
{
if let alarm = currentAlarm
{
switch alarm.wakeMethod.name {
case "Walk":
walkAction()
case "Jump":
jumpAction()
case "Factor":
self.puzzleAnswers = factorAction(puzzleQuestionLabel: puzzleQuestionLabel)
puzzleView.isHidden = false
case "Smash":
print("")
case "RPS":
rpsView.isHidden = false
//Get Choice here
//rpsAction(choice: choice)
default:
print("Invalid alarm type")
}
}
}
//Verfies and ends factoring WVM
@IBAction func checkBinomialSolution(_ sender: Any) {
if let input = puzzleAnswerInput.text {
if let numericalInput = Int(input) {
if puzzleAnswers.contains(numericalInput) {
endAlarm()
}
}
}
}
//Gets RPS choice
@IBAction func rockChoice(_ sender: Any) {
if rpsAction(choice: .rock)! {
endAlarm()
} else {
rpsResult.text = "Paper: You lost, try again"
}
}
@IBAction func paperChoice(_ sender: Any) {
if rpsAction(choice: .paper)! {
endAlarm()
} else {
rpsResult.text = "Scissors: You lost, try again"
}
}
@IBAction func scissorChoice(_ sender: Any) {
if rpsAction(choice: .scissors)! {
endAlarm()
} else {
rpsResult.text = "Rock: You lost, try again"
}
}
//Standard way to turn off and close the alarm
func endAlarm() {
timer?.invalidate()
print("Alarm solved")
dismiss(animated: true, completion: nil)
}
}
+76
View File
@@ -0,0 +1,76 @@
//
// AlarmActivator.swift
// ProjectClock
//
// Created by Hykilpikonna on 1/17/21.
//
import Foundation
import UIKit
/**
Class to activate alarms when the user is inside the app
Note: This will not run when app is switched to the background or when the display is turned off, but it will run right after the user switched back to the app.
*/
class AlarmActivator: UITabBarController
{
/// Interval in seconds
static var interval = 2.0
/// Timer for scheduled calls
var timer: Timer?
var alarm: Alarm?
override func viewDidLoad()
{
start()
}
/**
Start detecting alarms
*/
func start()
{
if timer != nil { return }
timer = Timer.scheduledTimer(timeInterval: AlarmActivator.interval, target: self, selector: #selector(AlarmActivator.check), userInfo: nil, repeats: true)
}
/**
Stop detecting alarms
*/
func stop()
{
timer?.invalidate()
timer = nil
}
/**
Check alarm
*/
@objc func check()
{
//NSLog("Check")
// Get the alarm to activate
let alarms = Alarms.fromLocal()
guard let alarm = alarms.listActivating.first else { return }
// Update alarm info
alarm.apply {
$0.lastActivate = Date()
if $0.oneTime { $0.enabled = false }
}
alarms.localSave()
self.alarm = alarm
// Segue
//NSLog(JSON.stringify(alarm)!)
performSegue(withIdentifier: "activate-alarm", sender: alarm)
}
@IBSegueAction func sendAlarm(_ coder: NSCoder) -> AlarmActivationViewController? {
return AlarmActivationViewController(coder: coder, currentAlarm: alarm!)
}
}
+29 -5
View File
@@ -3,15 +3,14 @@ import UIKit
class AlarmViewController: UIViewController
{
@IBOutlet weak var table: UITableView!
// TODO: Remove example and use localStorage
var data: [Alarm] = [Alarm(alarmTime: Date(), text: "Wake up lol", wakeMethod: wvms[0])]
static var staticTable: UITableView?
override func viewDidLoad()
{
super.viewDidLoad()
// Assign table delegate and data source
AlarmViewController.staticTable = table
table.delegate = self
table.dataSource = self
}
@@ -26,7 +25,7 @@ extension AlarmViewController: UITableViewDelegate, UITableViewDataSource
func numberOfSections(in: UITableView) -> Int { return 1 }
/// How many rows are there
func tableView(_ v: UITableView, numberOfRowsInSection s: Int) -> Int { return data.count }
func tableView(_ v: UITableView, numberOfRowsInSection s: Int) -> Int { return Alarms.fromLocal().list.count }
/// Configure each cell
func tableView(_ v: UITableView, cellForRowAt i: IndexPath) -> UITableViewCell
@@ -34,7 +33,7 @@ extension AlarmViewController: UITableViewDelegate, UITableViewDataSource
// Get the cell and item at index i
let rawCell = v.dequeueReusableCell(withIdentifier: "alarm", for: i)
guard let cell = rawCell as? AlarmTableCell else { return rawCell }
let item = data[i.row]
let item = Alarms.fromLocal().list[i.row]
// Set the content of the cell to the content of the item.
cell.setData(item)
@@ -62,8 +61,33 @@ class AlarmTableCell: UITableViewCell
@IBOutlet weak var goingOffText: UILabel!
/// Update information on the cell to information in the alarm object
//WARNING:Terrible code lies ahead! You WILL be dissapointed! But it works, and that is all that matters.
func setData(_ alarm: Alarm)
{
descriptionText.text = "- " + alarm.text
// Display Hour, Minute, and AM or PM
ampm.text = alarm.hour < 12 || alarm.hour == 24 ? "AM" : "PM"
let hour = alarm.hour <= 12 ? alarm.hour : alarm.hour - 12
time.text = alarm.minute < 10 ? "\(hour):0\(alarm.minute)" : "\(hour):\(alarm.minute)"
// displays the specific days alarm is activated
let daysDict = ["Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"]
var daysActive : [String] = []
if alarm.oneTime {repeatText.text = "No Repeat"}
else {
for (index, element) in alarm.repeats.enumerated() {
if element {
daysActive.append(daysDict[index])
}
}
repeatText.text = daysActive.joined(separator: ", ")
}
// Show next activation date
if alarm.enabled, let n = alarm.nextActivate {
goingOffText.text = "(Going off in \(n.timeIntervalSince(Date()).str()))"
}
}
}
+60 -13
View File
@@ -8,29 +8,76 @@
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
class AppDelegate: UIResponder, UIApplicationDelegate
{
/// Override point for customization after application launch.
func application(_ app: UIApplication, didFinishLaunchingWithOptions op: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
// Init default settings
localStorage.register(defaults: [
"alarms": JSON.stringify([Alarm(hour: 7, minute: 20, text: "Wake up lol", wakeMethod: wvms[0])])!
])
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
func application(_ app: UIApplication, configurationForConnecting session: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration
{
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
return UISceneConfiguration(name: "Default Configuration", sessionRole: session.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
func application(_ app: UIApplication, didDiscardSceneSessions sessions: Set<UISceneSession>)
{
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate
{
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
{
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene)
{
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene)
{
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene)
{
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene)
{
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene)
{
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
+582 -206
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="s8U-C8-W2S">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="s8U-C8-W2S">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
@@ -18,7 +18,7 @@
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="VaN-9W-uoG">
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="VaN-9W-uoG">
<rect key="frame" x="0.0" y="98" width="414" height="798"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<button key="tableFooterView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" id="DQJ-kT-79q">
@@ -26,7 +26,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Add Alarm"/>
<connections>
<segue destination="Mki-dC-5Kc" kind="presentation" id="Qim-4Q-43N"/>
<segue destination="Mki-dC-5Kc" kind="presentation" identifier="alarm-edit" id="Qim-4Q-43N"/>
</connections>
</button>
<prototypes>
@@ -61,22 +61,24 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="| Going off in 23 hr 22 m" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EPJ-eL-Kek">
<rect key="frame" x="179" y="70" width="215" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yra-wA-O7B">
<rect key="frame" x="345" y="26" width="51" height="31"/>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="(Going off in 23 hr 22 m)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EPJ-eL-Kek">
<rect key="frame" x="179" y="74.5" width="215" height="14.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yra-wA-O7B">
<rect key="frame" x="345" y="26" width="49" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</switch>
</subviews>
<constraints>
<constraint firstItem="dWq-jh-9Ue" firstAttribute="baseline" secondItem="4hj-fb-FF3" secondAttribute="baseline" id="4H2-o6-GfV"/>
<constraint firstItem="YhV-X3-y1v" firstAttribute="leading" secondItem="Wl6-IQ-lVM" secondAttribute="leadingMargin" constant="10" id="Hur-MO-GTA"/>
<constraint firstItem="yra-wA-O7B" firstAttribute="top" secondItem="Wl6-IQ-lVM" secondAttribute="topMargin" constant="15" id="Jvt-p2-9cx"/>
<constraint firstAttribute="trailingMargin" secondItem="EPJ-eL-Kek" secondAttribute="trailing" id="LhS-n6-zst"/>
<constraint firstAttribute="trailingMargin" secondItem="yra-wA-O7B" secondAttribute="trailing" id="R9H-AC-mf6"/>
<constraint firstItem="mjO-SX-f31" firstAttribute="leading" secondItem="Wl6-IQ-lVM" secondAttribute="leadingMargin" constant="10" id="VOR-Go-oCw"/>
<constraint firstItem="EPJ-eL-Kek" firstAttribute="top" secondItem="4hj-fb-FF3" secondAttribute="bottom" constant="13" id="je6-UM-5Kc"/>
<constraint firstItem="EPJ-eL-Kek" firstAttribute="baseline" secondItem="YhV-X3-y1v" secondAttribute="firstBaseline" id="ilR-ei-lE6"/>
<constraint firstItem="dWq-jh-9Ue" firstAttribute="leading" secondItem="mjO-SX-f31" secondAttribute="trailing" constant="8" symbolic="YES" id="ocx-bN-3M8"/>
<constraint firstItem="EPJ-eL-Kek" firstAttribute="leading" secondItem="YhV-X3-y1v" secondAttribute="trailing" constant="8" symbolic="YES" id="po7-2V-fZ6"/>
<constraint firstItem="4hj-fb-FF3" firstAttribute="top" secondItem="Wl6-IQ-lVM" secondAttribute="topMargin" constant="25" id="r6f-mB-n9x"/>
@@ -133,7 +135,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="LKF-bm-JFg" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-494" y="869"/>
<point key="canvasLocation" x="-494.20289855072468" y="868.52678571428567"/>
</scene>
<!--Account-->
<scene sceneID="tne-QT-ifu">
@@ -149,194 +151,57 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="sXr-25-joh">
<rect key="frame" x="20" y="336" width="374" height="224"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Account" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Yoz-zy-c7V">
<rect key="frame" x="0.0" y="0.0" width="374" height="41"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle0"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="xzo-A1-wgr">
<rect key="frame" x="0.0" y="61" width="374" height="41"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lPF-ex-duz">
<rect key="frame" x="0.0" y="0.0" width="78.5" height="41"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="hbK-Dt-9tn">
<rect key="frame" x="98.5" y="0.0" width="275.5" height="41"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="yvB-Yi-jqQ">
<rect key="frame" x="0.0" y="122" width="374" height="41"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Password" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="twj-MC-8je">
<rect key="frame" x="0.0" y="0.0" width="73.5" height="41"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="97S-CL-8Wq">
<rect key="frame" x="93.5" y="0.0" width="280.5" height="41"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" secureTextEntry="YES"/>
</textField>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="htn-tb-R70">
<rect key="frame" x="0.0" y="183" width="374" height="41"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WK1-Pr-EyJ">
<rect key="frame" x="0.0" y="0.0" width="177" height="41"/>
<state key="normal" title="Register"/>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Exj-c9-ucM">
<rect key="frame" x="197" y="0.0" width="177" height="41"/>
<state key="normal" title="Login"/>
</button>
</subviews>
</stackView>
</subviews>
</stackView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eS2-n9-bE3" userLabel="Divider Line">
<rect key="frame" x="20" y="92" width="374" height="1"/>
<color key="backgroundColor" systemColor="labelColor"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="Da5-Yc-aYa"/>
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="hkW-EE-XPg">
<rect key="frame" x="20" y="109" width="374" height="321"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3Wi-Rg-PJy">
<rect key="frame" x="0.0" y="0.0" width="374" height="170"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ZOn-IP-cwj">
<rect key="frame" x="132" y="0.0" width="110" height="110"/>
<constraints>
<constraint firstAttribute="width" constant="110" id="6IV-Ay-C4i"/>
<constraint firstAttribute="height" constant="110" id="xCo-yb-dyX"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username 233" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0xm-Sd-S80">
<rect key="frame" x="20" y="118" width="334" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Joined on Jan 8, 2021" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yeb-TX-Edr">
<rect key="frame" x="20" y="138.5" width="334" height="14.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="yeb-TX-Edr" secondAttribute="trailing" constant="20" id="E18-zy-QnK"/>
<constraint firstItem="0xm-Sd-S80" firstAttribute="leading" secondItem="3Wi-Rg-PJy" secondAttribute="leading" constant="20" id="KTh-5Z-Icc"/>
<constraint firstItem="ZOn-IP-cwj" firstAttribute="top" secondItem="3Wi-Rg-PJy" secondAttribute="top" id="aUR-fX-A3S"/>
<constraint firstItem="ZOn-IP-cwj" firstAttribute="centerX" secondItem="3Wi-Rg-PJy" secondAttribute="centerX" id="awM-Rr-agJ"/>
<constraint firstAttribute="height" constant="170" id="e42-Ry-PNW"/>
<constraint firstAttribute="trailing" secondItem="0xm-Sd-S80" secondAttribute="trailing" constant="20" id="hXl-GG-yik"/>
<constraint firstItem="0xm-Sd-S80" firstAttribute="top" secondItem="ZOn-IP-cwj" secondAttribute="bottom" constant="8" symbolic="YES" id="lkR-sx-rEQ"/>
<constraint firstItem="yeb-TX-Edr" firstAttribute="leading" secondItem="3Wi-Rg-PJy" secondAttribute="leading" constant="20" id="nH7-Kg-HzV"/>
<constraint firstItem="yeb-TX-Edr" firstAttribute="top" secondItem="0xm-Sd-S80" secondAttribute="bottom" id="pUg-uh-chQ"/>
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="3aB-bs-ULc">
<rect key="frame" x="0.0" y="190" width="374" height="31"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Auto Backup" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Syv-4b-ZfJ">
<rect key="frame" x="0.0" y="0.0" width="305" height="31"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ebp-xK-if6">
<rect key="frame" x="325" y="0.0" width="51" height="31"/>
</switch>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="q7T-mb-6ax">
<rect key="frame" x="0.0" y="241" width="374" height="30"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5a1-FL-1KK">
<rect key="frame" x="0.0" y="0.0" width="187" height="30"/>
<color key="backgroundColor" red="0.9137254901960784" green="0.95294117647058818" blue="0.99607843137254903" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" title="Backup Config"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="5"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="layer.borderColor">
<color key="value" name="AccentColor"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1on-v1-fQc">
<rect key="frame" x="187" y="0.0" width="187" height="30"/>
<state key="normal" title="Restore Backup"/>
</button>
</subviews>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="l9d-j4-iaa">
<rect key="frame" x="0.0" y="291" width="374" height="30"/>
<state key="normal" title="Delete Account">
<color key="titleColor" systemColor="systemRedColor"/>
</state>
</button>
</subviews>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Manage Account and Settings" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cPO-q9-S2N">
<rect key="frame" x="20" y="74.5" width="374" height="14.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uu6-RV-xw3">
<rect key="frame" x="0.0" y="109" width="414" height="200"/>
<constraints>
<constraint firstAttribute="height" constant="200" id="Kko-qD-93X"/>
</constraints>
<connections>
<segue destination="ZAC-hn-zGl" kind="embed" id="foq-Zo-2nt"/>
</connections>
</containerView>
<containerView hidden="YES" opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RSY-ha-JUW">
<rect key="frame" x="0.0" y="109" width="414" height="704"/>
<connections>
<segue destination="3gV-kF-UbK" kind="embed" id="dNK-l6-bgo"/>
</connections>
</containerView>
</subviews>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="hkW-EE-XPg" firstAttribute="top" secondItem="cPO-q9-S2N" secondAttribute="bottom" constant="20" id="6om-ac-MMy"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="eS2-n9-bE3" secondAttribute="trailing" constant="20" id="7G3-4D-wJh"/>
<constraint firstItem="sXr-25-joh" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="20" id="Jul-zo-yqj"/>
<constraint firstItem="sXr-25-joh" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="WM6-BP-vb6"/>
<constraint firstItem="RSY-ha-JUW" firstAttribute="top" secondItem="cPO-q9-S2N" secondAttribute="bottom" constant="20" id="40e-vU-3lH"/>
<constraint firstItem="RSY-ha-JUW" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="FTb-v0-N63"/>
<constraint firstItem="cPO-q9-S2N" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="20" id="Wio-lA-v4A"/>
<constraint firstItem="uu6-RV-xw3" firstAttribute="top" secondItem="cPO-q9-S2N" secondAttribute="bottom" constant="20" id="b4k-8J-XlA"/>
<constraint firstItem="RSY-ha-JUW" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="bap-y2-ZtA"/>
<constraint firstItem="cPO-q9-S2N" firstAttribute="top" secondItem="xUt-DT-D6S" secondAttribute="bottom" id="d6f-SJ-atD"/>
<constraint firstItem="uu6-RV-xw3" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="e63-Mb-cxd"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="xUt-DT-D6S" secondAttribute="trailing" constant="20" id="h0T-oL-Nsj"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="cPO-q9-S2N" secondAttribute="trailing" constant="20" id="mC6-HG-Sid"/>
<constraint firstItem="eS2-n9-bE3" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="20" id="mgE-TM-WQ6"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="hkW-EE-XPg" secondAttribute="trailing" constant="20" id="olr-Sd-MDD"/>
<constraint firstItem="hkW-EE-XPg" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="20" id="pm5-wU-KhI"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="sXr-25-joh" secondAttribute="trailing" constant="20" id="qEv-DD-dGy"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="uu6-RV-xw3" secondAttribute="trailing" id="nQR-3Z-BvQ"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="RSY-ha-JUW" secondAttribute="bottom" id="oyr-RU-84k"/>
<constraint firstItem="xUt-DT-D6S" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="10" id="vI0-ip-gSt"/>
<constraint firstItem="xUt-DT-D6S" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="20" id="yqR-Rd-3o7"/>
</constraints>
<variation key="default">
<mask key="subviews">
<exclude reference="sXr-25-joh"/>
<exclude reference="eS2-n9-bE3"/>
</mask>
</variation>
</view>
<tabBarItem key="tabBarItem" title="Account" image="person.crop.circle" catalog="system" selectedImage="person.crop.circle" id="pml-pe-eBz"/>
<connections>
<outlet property="vLogin" destination="uu6-RV-xw3" id="HDR-hN-k2a"/>
<outlet property="vManage" destination="RSY-ha-JUW" id="gYK-lZ-5iB"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="242" y="869"/>
<point key="canvasLocation" x="897" y="869"/>
</scene>
<!--Item-->
<!--Debug-->
<scene sceneID="x23-kV-b5u">
<objects>
<viewController id="r8W-6e-Hn2" customClass="TestingViewController" customModule="ProjectClock" customModuleProvider="target" sceneMemberID="viewController">
@@ -344,33 +209,204 @@
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GhB-GA-PWg">
<rect key="frame" x="93" y="128" width="229" height="40"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="23"/>
<state key="normal" title="Send Accel. to Console"/>
<connections>
<action selector="getAccel:" destination="r8W-6e-Hn2" eventType="touchUpInside" id="hDu-Hj-vnU"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8o4-jF-mCC">
<rect key="frame" x="154" y="232" width="110" height="41"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="24"/>
<state key="normal" title="Send Notif"/>
<connections>
<action selector="sendNotification:" destination="r8W-6e-Hn2" eventType="touchUpInside" id="ry0-VK-YRb"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Debug" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="w0P-Jb-Y3X">
<rect key="frame" x="20" y="54" width="374" height="20.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="What is this?" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tcW-ZW-HgZ">
<rect key="frame" x="20" y="74.5" width="374" height="14.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="oTa-Ok-U9h">
<rect key="frame" x="20" y="109" width="374" height="128"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8o4-jF-mCC">
<rect key="frame" x="0.0" y="0.0" width="374" height="36"/>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<state key="normal" title="Send Notification"/>
<connections>
<action selector="sendNotification:" destination="r8W-6e-Hn2" eventType="touchUpInside" id="ry0-VK-YRb"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oK7-CW-NUv">
<rect key="frame" x="0.0" y="46" width="374" height="36"/>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<state key="normal" title="Add an alarm activating one minute later"/>
<connections>
<action selector="addAlarm:" destination="r8W-6e-Hn2" eventType="touchUpInside" id="Ctz-XA-1z2"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="VdA-Ax-Nzf">
<rect key="frame" x="0.0" y="92" width="374" height="36"/>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<state key="normal" title="Delete All Alarms"/>
<connections>
<action selector="deleteAlarm:" destination="r8W-6e-Hn2" eventType="touchUpInside" id="gqI-7A-W9C"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="hX1-uy-i87"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="w0P-Jb-Y3X" firstAttribute="top" secondItem="hX1-uy-i87" secondAttribute="top" constant="10" id="42B-VU-jVH"/>
<constraint firstItem="hX1-uy-i87" firstAttribute="trailing" secondItem="oTa-Ok-U9h" secondAttribute="trailing" constant="20" id="BZf-0X-jDK"/>
<constraint firstItem="oTa-Ok-U9h" firstAttribute="leading" secondItem="hX1-uy-i87" secondAttribute="leading" constant="20" id="DjJ-yy-Jc0"/>
<constraint firstItem="tcW-ZW-HgZ" firstAttribute="leading" secondItem="hX1-uy-i87" secondAttribute="leading" constant="20" id="MMc-9X-wep"/>
<constraint firstItem="hX1-uy-i87" firstAttribute="trailing" secondItem="tcW-ZW-HgZ" secondAttribute="trailing" constant="20" id="TuV-bF-NqF"/>
<constraint firstItem="oTa-Ok-U9h" firstAttribute="top" secondItem="tcW-ZW-HgZ" secondAttribute="bottom" constant="20" id="Xiz-02-dUA"/>
<constraint firstItem="tcW-ZW-HgZ" firstAttribute="top" secondItem="w0P-Jb-Y3X" secondAttribute="bottom" id="i43-E7-hoY"/>
<constraint firstItem="w0P-Jb-Y3X" firstAttribute="leading" secondItem="hX1-uy-i87" secondAttribute="leading" constant="20" id="mKZ-sC-tZt"/>
<constraint firstItem="hX1-uy-i87" firstAttribute="trailing" secondItem="w0P-Jb-Y3X" secondAttribute="trailing" constant="20" id="zYy-da-HnI"/>
</constraints>
</view>
<tabBarItem key="tabBarItem" title="Item" id="QZ2-fJ-hLg"/>
<tabBarItem key="tabBarItem" title="Debug" image="hammer.fill" catalog="system" selectedImage="hammer.fill" id="QZ2-fJ-hLg"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="mZu-oh-Lmb" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="952" y="869"/>
<point key="canvasLocation" x="1652" y="869"/>
</scene>
<!--Stopwatch-->
<scene sceneID="HUO-7o-NzS">
<objects>
<viewController id="PYt-Lf-JNp" customClass="StopwatchViewController" customModule="ProjectClock" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="wac-VZ-OTJ">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="51" translatesAutoresizingMaskIntoConstraints="NO" id="Apb-MM-jue">
<rect key="frame" x="20" y="89" width="374" height="714"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="34" translatesAutoresizingMaskIntoConstraints="NO" id="Lnz-vd-hkl">
<rect key="frame" x="0.0" y="0.0" width="374" height="60"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="54s-5X-INP">
<rect key="frame" x="0.0" y="0.0" width="100" height="60"/>
<fontDescription key="fontDescription" type="system" weight="ultraLight" pointSize="50"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=":" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="W12-19-4Jh">
<rect key="frame" x="134" y="0.0" width="10.5" height="60"/>
<fontDescription key="fontDescription" type="system" weight="ultraLight" pointSize="50"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rpt-j6-UiB">
<rect key="frame" x="178.5" y="0.0" width="58.5" height="60"/>
<fontDescription key="fontDescription" type="system" weight="ultraLight" pointSize="50"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=":" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rGI-kH-dgk">
<rect key="frame" x="271" y="0.0" width="10.5" height="60"/>
<fontDescription key="fontDescription" type="system" weight="ultraLight" pointSize="50"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SdB-cz-eTv">
<rect key="frame" x="315.5" y="0.0" width="58.5" height="60"/>
<fontDescription key="fontDescription" type="system" weight="ultraLight" pointSize="50"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillProportionally" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="4j4-zF-LWF">
<rect key="frame" x="0.0" y="111" width="374" height="150"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Jse-AL-cOs">
<rect key="frame" x="0.0" y="0.0" width="374" height="30"/>
<color key="backgroundColor" name="AccentColor"/>
<state key="normal" title="Start">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="start:" destination="PYt-Lf-JNp" eventType="touchUpInside" id="ucf-fN-SgP"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="O4A-eq-kEz">
<rect key="frame" x="0.0" y="40" width="374" height="30"/>
<color key="backgroundColor" name="AccentColor"/>
<state key="normal" title="Stop">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="stop:" destination="PYt-Lf-JNp" eventType="touchUpInside" id="ncg-GB-bAj"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q7i-3U-NbI">
<rect key="frame" x="0.0" y="80" width="374" height="30"/>
<color key="backgroundColor" name="AccentColor"/>
<state key="normal" title="Reset">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="reset:" destination="PYt-Lf-JNp" eventType="touchUpInside" id="3ff-of-rJl"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="794-VN-m96">
<rect key="frame" x="0.0" y="120" width="374" height="30"/>
<color key="backgroundColor" name="AccentColor"/>
<state key="normal" title="Lap">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="lap:" destination="PYt-Lf-JNp" eventType="touchUpInside" id="UT9-pP-BWA"/>
</connections>
</button>
</subviews>
</stackView>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="O7B-Tj-vT0">
<rect key="frame" x="0.0" y="312" width="374" height="402"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="lapCell" id="2Je-Lw-ZAb">
<rect key="frame" x="0.0" y="28" width="374" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="2Je-Lw-ZAb" id="HNi-3j-MIV">
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="PYt-Lf-JNp" id="HRZ-MF-SqM"/>
<outlet property="delegate" destination="PYt-Lf-JNp" id="uCp-Op-uuX"/>
</connections>
</tableView>
</subviews>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="0Lp-Fy-R0s"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="0Lp-Fy-R0s" firstAttribute="bottom" secondItem="Apb-MM-jue" secondAttribute="bottom" constant="10" id="4Rv-Vr-MaH"/>
<constraint firstItem="0Lp-Fy-R0s" firstAttribute="trailing" secondItem="Apb-MM-jue" secondAttribute="trailing" constant="20" id="ENw-M0-fRs"/>
<constraint firstItem="Apb-MM-jue" firstAttribute="top" secondItem="0Lp-Fy-R0s" secondAttribute="top" constant="45" id="RHG-Fs-SLZ"/>
<constraint firstItem="Apb-MM-jue" firstAttribute="leading" secondItem="0Lp-Fy-R0s" secondAttribute="leading" constant="20" id="l5v-Y0-GXP"/>
</constraints>
</view>
<tabBarItem key="tabBarItem" title="Stopwatch" image="clock.arrow.circlepath" catalog="system" selectedImage="clock.arrow.circlepath" id="hNc-UI-vIQ"/>
<connections>
<outlet property="hourLabel" destination="54s-5X-INP" id="Ugg-ul-ebm"/>
<outlet property="lapButton" destination="794-VN-m96" id="1aX-pS-Cjr"/>
<outlet property="minuteLabel" destination="rpt-j6-UiB" id="Qaf-xg-UCX"/>
<outlet property="resetButton" destination="Q7i-3U-NbI" id="gYT-DB-XpP"/>
<outlet property="secondLabel" destination="SdB-cz-eTv" id="syA-P8-NFX"/>
<outlet property="startButton" destination="Jse-AL-cOs" id="iq2-xE-Nir"/>
<outlet property="stopButton" destination="O4A-eq-kEz" id="dd7-v0-fqc"/>
<outlet property="tableView" destination="O7B-Tj-vT0" id="kfu-vG-sgE"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ZlX-5W-Pjn" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="192.75362318840581" y="868.52678571428567"/>
</scene>
<!--Add Alarm View Controller-->
<scene sceneID="sJi-AZ-FUw">
@@ -388,6 +424,9 @@
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="30"/>
<state key="normal" image="checkmark" catalog="system"/>
<connections>
<action selector="addAlarmButton:" destination="Mki-dC-5Kc" eventType="touchUpInside" id="AiG-Cc-DlR"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6d8-Gi-Ipa">
<rect key="frame" x="20" y="20" width="30" height="30"/>
@@ -397,6 +436,9 @@
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="30"/>
<state key="normal" image="trash.fill" catalog="system"/>
<connections>
<action selector="cancelAlarmButton:" destination="Mki-dC-5Kc" eventType="touchUpInside" id="4zo-hG-Mnk"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Going off in 23 hr 59 min" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Xqs-n0-H9G">
<rect key="frame" x="20" y="40.5" width="374" height="14.5"/>
@@ -436,10 +478,16 @@
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cZ8-yN-fp6">
<rect key="frame" x="0.0" y="0.0" width="374" height="30"/>
<state key="normal" title="Pick From iOS Default Ringtones"/>
<connections>
<action selector="defaultRingtonesButton:" destination="Mki-dC-5Kc" eventType="touchUpInside" id="0oM-fE-Gyh"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="A3Z-Qp-XmN">
<rect key="frame" x="0.0" y="30" width="374" height="30"/>
<state key="normal" title="Pick From Sound Library"/>
<connections>
<action selector="soundLibraryButton:" destination="Mki-dC-5Kc" eventType="touchUpInside" id="5G8-FV-bDx"/>
</connections>
</button>
</subviews>
</stackView>
@@ -462,7 +510,7 @@
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="e8v-cM-bxf">
<rect key="frame" x="20" y="553.5" width="334" height="72"/>
<rect key="frame" x="20" y="553.5" width="334" height="116"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="iAX-G9-qxh">
<rect key="frame" x="0.0" y="0.0" width="334" height="31"/>
@@ -492,6 +540,22 @@
</switch>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="gdH-Ok-RIH">
<rect key="frame" x="0.0" y="82" width="334" height="34"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Alarm Name:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5LP-Zk-4Sh">
<rect key="frame" x="0.0" y="0.0" width="98.5" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="bJg-zp-Aan">
<rect key="frame" x="118.5" y="0.0" width="215.5" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
@@ -553,6 +617,9 @@
</view>
<navigationItem key="navigationItem" id="Ydw-dw-vLC"/>
<connections>
<outlet property="alarmNameTextField" destination="bJg-zp-Aan" id="Itt-3v-GJB"/>
<outlet property="repeatWeekdaysSwitch" destination="5oN-BL-Xtu" id="gqb-l3-1jZ"/>
<outlet property="repeatWeekendsSwitch" destination="WPM-Fh-sRB" id="LB7-zW-jpC"/>
<outlet property="scrollView" destination="ybc-8d-6pJ" id="m1B-ff-zeC"/>
<outlet property="scrollViewInner" destination="N7f-vi-SFU" id="LQW-6T-f6x"/>
<outlet property="timePicker" destination="qSt-1V-2DQ" id="aDM-jE-0OP"/>
@@ -561,12 +628,137 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="0OD-e8-Pfh" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-494" y="1576"/>
<point key="canvasLocation" x="-494.20289855072468" y="1575.6696428571429"/>
</scene>
<!--Tab Bar Controller-->
<!--Alarm Activation View Controller-->
<scene sceneID="21H-AI-pzd">
<objects>
<viewController id="hDW-11-g9U" customClass="AlarmActivationViewController" customModule="ProjectClock" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="BZn-UX-vps">
<rect key="frame" x="0.0" y="0.0" width="414" height="842"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="17:40" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vmg-Oj-8tB">
<rect key="frame" x="20" y="20" width="374" height="137.5"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="115"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Jan 17, Sunday" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="42Q-0v-ZS3">
<rect key="frame" x="20" y="152.5" width="374" height="25.5"/>
<fontDescription key="fontDescription" type="system" pointSize="21"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OMQ-qK-fej" userLabel="factorView">
<rect key="frame" x="20" y="249" width="374" height="343"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Solve: " lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CZ0-R6-FDq">
<rect key="frame" x="39" y="35" width="300" height="33"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="27"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="eTb-g7-8x3">
<rect key="frame" x="39" y="154" width="309" height="34"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" textContentType="cc-number"/>
<connections>
<action selector="checkBinomialSolution:" destination="hDW-11-g9U" eventType="editingChanged" id="nuZ-mN-UR3"/>
</connections>
</textField>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Input 1 answer:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vHe-pz-8w2">
<rect key="frame" x="39" y="113" width="174" height="33"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="27"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemGray6Color"/>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Smash your phone to dismiss" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mjE-Hr-RIc">
<rect key="frame" x="95.5" y="411" width="223.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NmX-iJ-1D0" userLabel="rpsView">
<rect key="frame" x="20" y="261" width="374" height="343"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" fixedFrame="YES" spacing="64" translatesAutoresizingMaskIntoConstraints="NO" id="213-rS-oYj">
<rect key="frame" x="19" y="134" width="336" height="42"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ndj-R4-AKk">
<rect key="frame" x="0.0" y="0.0" width="55" height="42"/>
<fontDescription key="fontDescription" type="system" pointSize="25"/>
<state key="normal" title="Rock"/>
<connections>
<action selector="rockChoice:" destination="hDW-11-g9U" eventType="touchUpInside" id="w4O-MC-ohr"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Iiv-Co-j8G">
<rect key="frame" x="119" y="0.0" width="62" height="42"/>
<fontDescription key="fontDescription" type="system" pointSize="25"/>
<state key="normal" title="Paper"/>
<connections>
<action selector="paperChoice:" destination="hDW-11-g9U" eventType="touchUpInside" id="giR-wy-jqv"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="U4y-ls-yuK">
<rect key="frame" x="245" y="0.0" width="91" height="42"/>
<fontDescription key="fontDescription" type="system" pointSize="25"/>
<state key="normal" title="Scissors"/>
<connections>
<action selector="scissorChoice:" destination="hDW-11-g9U" eventType="touchUpInside" id="BVu-ST-Hfr"/>
</connections>
</button>
</subviews>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="RPS: What do you choose?" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HEP-oh-VSY">
<rect key="frame" x="31" y="8" width="313" height="33"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="27"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemGray4Color"/>
</view>
</subviews>
<viewLayoutGuide key="safeArea" id="hS6-fS-yWp"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="vmg-Oj-8tB" firstAttribute="top" secondItem="hS6-fS-yWp" secondAttribute="top" constant="20" id="5lz-9m-i9F"/>
<constraint firstItem="vmg-Oj-8tB" firstAttribute="leading" secondItem="hS6-fS-yWp" secondAttribute="leading" constant="20" id="7fm-Y8-FaE"/>
<constraint firstItem="42Q-0v-ZS3" firstAttribute="top" secondItem="vmg-Oj-8tB" secondAttribute="bottom" constant="-5" id="GNM-uI-sQt"/>
<constraint firstItem="hS6-fS-yWp" firstAttribute="trailing" secondItem="42Q-0v-ZS3" secondAttribute="trailing" constant="20" id="L1F-Bv-r5M"/>
<constraint firstItem="42Q-0v-ZS3" firstAttribute="leading" secondItem="hS6-fS-yWp" secondAttribute="leading" constant="20" id="Nbf-jB-Uq5"/>
<constraint firstItem="mjE-Hr-RIc" firstAttribute="centerY" secondItem="BZn-UX-vps" secondAttribute="centerY" id="SFw-9a-XAc"/>
<constraint firstItem="mjE-Hr-RIc" firstAttribute="centerX" secondItem="BZn-UX-vps" secondAttribute="centerX" id="oBA-RV-cEO"/>
<constraint firstItem="hS6-fS-yWp" firstAttribute="trailing" secondItem="vmg-Oj-8tB" secondAttribute="trailing" constant="20" id="vVE-ID-dgj"/>
</constraints>
</view>
<connections>
<outlet property="puzzleAnswerInput" destination="eTb-g7-8x3" id="xIh-TJ-vhq"/>
<outlet property="puzzleQuestionLabel" destination="CZ0-R6-FDq" id="gon-N6-XTD"/>
<outlet property="puzzleView" destination="OMQ-qK-fej" id="KLT-oe-RJX"/>
<outlet property="rpsResult" destination="HEP-oh-VSY" id="W2G-eZ-mzI"/>
<outlet property="rpsView" destination="NmX-iJ-1D0" id="Rhg-Hm-2Xx"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="78q-sr-CNz" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2391" y="1102"/>
</scene>
<!--Alarm Activator-->
<scene sceneID="c7a-VN-D68">
<objects>
<tabBarController automaticallyAdjustsScrollViewInsets="NO" id="s8U-C8-W2S" sceneMemberID="viewController">
<tabBarController automaticallyAdjustsScrollViewInsets="NO" id="s8U-C8-W2S" customClass="AlarmActivator" customModule="ProjectClock" customModuleProvider="target" sceneMemberID="viewController">
<toolbarItems/>
<tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="203-Gr-Mvz">
<rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
@@ -577,30 +769,214 @@
<segue destination="Bqt-du-DT2" kind="relationship" relationship="viewControllers" id="ZTh-ke-ZIV"/>
<segue destination="BYZ-38-t0r" kind="relationship" relationship="viewControllers" destinationCreationSelector="Account" id="NN6-JO-Hmi"/>
<segue destination="r8W-6e-Hn2" kind="relationship" relationship="viewControllers" destinationCreationSelector="Testing" id="SLn-vq-UnH"/>
<segue destination="hDW-11-g9U" kind="showDetail" identifier="activate-alarm" destinationCreationSelector="sendAlarm:" id="z9o-Jh-fnM"/>
<segue destination="PYt-Lf-JNp" kind="relationship" relationship="viewControllers" id="uMq-nh-i7c"/>
</connections>
</tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="S6R-Xr-Nfe" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1406" y="1102"/>
</scene>
<!--LoginVC-->
<scene sceneID="erw-PT-N27">
<objects>
<viewController id="ZAC-hn-zGl" customClass="LoginVC" customModule="ProjectClock" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="ikD-PZ-wEA">
<rect key="frame" x="0.0" y="0.0" width="414" height="200"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="bey-TF-Fqa">
<rect key="frame" x="20" y="29" width="374" height="142"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="4Rf-oJ-54p">
<rect key="frame" x="0.0" y="0.0" width="374" height="34"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2A7-sm-WU9">
<rect key="frame" x="0.0" y="0.0" width="80" height="34"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="sge-J8-P4B"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="1M0-Wo-TZA">
<rect key="frame" x="100" y="0.0" width="274" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" smartDashesType="no" smartInsertDeleteType="no" smartQuotesType="no" textContentType="username"/>
</textField>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="8Az-dM-tXe">
<rect key="frame" x="0.0" y="54" width="374" height="34"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Password" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vtI-qz-pCA">
<rect key="frame" x="0.0" y="0.0" width="80" height="34"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="CfI-BL-Ifg"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="3pJ-zP-vKy">
<rect key="frame" x="100" y="0.0" width="274" height="34"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" secureTextEntry="YES"/>
</textField>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="2Vc-MS-Vmc">
<rect key="frame" x="0.0" y="108" width="374" height="34"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DpZ-cR-QRd">
<rect key="frame" x="0.0" y="0.0" width="177" height="34"/>
<state key="normal" title="Register"/>
<connections>
<action selector="register:" destination="ZAC-hn-zGl" eventType="touchUpInside" id="t9e-S1-E1e"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="C8G-k3-WeR">
<rect key="frame" x="197" y="0.0" width="177" height="34"/>
<state key="normal" title="Login"/>
<connections>
<action selector="login:" destination="ZAC-hn-zGl" eventType="touchUpInside" id="hda-pr-3rN"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="bky-eU-lyX"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="bey-TF-Fqa" firstAttribute="centerY" secondItem="ikD-PZ-wEA" secondAttribute="centerY" id="61k-0f-XAy"/>
<constraint firstAttribute="trailing" secondItem="bey-TF-Fqa" secondAttribute="trailing" constant="20" id="6q6-l9-TNU"/>
<constraint firstItem="bey-TF-Fqa" firstAttribute="leading" secondItem="ikD-PZ-wEA" secondAttribute="leading" constant="20" id="Juc-Oa-X2W"/>
</constraints>
</view>
<connections>
<outlet property="password" destination="3pJ-zP-vKy" id="Cnb-HO-uMj"/>
<outlet property="username" destination="1M0-Wo-TZA" id="rfc-YG-20V"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="M0T-zq-vZ0" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="949" y="1342"/>
</scene>
<!--ManageVC-->
<scene sceneID="jRZ-qD-YDj">
<objects>
<viewController id="3gV-kF-UbK" customClass="ManageVC" customModule="ProjectClock" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="yUd-Ri-s9C">
<rect key="frame" x="0.0" y="0.0" width="414" height="704"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="gYR-mG-zfS">
<rect key="frame" x="20" y="0.0" width="374" height="270"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gUf-g1-1af">
<rect key="frame" x="0.0" y="0.0" width="374" height="170"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="person.crop.circle.badge.checkmark" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="yVW-fL-SIQ">
<rect key="frame" x="132" y="0.0" width="110" height="109.5"/>
<constraints>
<constraint firstAttribute="width" constant="110" id="So8-k5-nLS"/>
<constraint firstAttribute="height" constant="110" id="inA-vb-CrL"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Username 233" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kAN-ll-4wh">
<rect key="frame" x="20" y="118" width="334" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Joined on Jan 8, 2021" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cT0-Ux-t7H">
<rect key="frame" x="20" y="138.5" width="334" height="14.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="cT0-Ux-t7H" firstAttribute="leading" secondItem="gUf-g1-1af" secondAttribute="leading" constant="20" id="1Ik-pd-j1d"/>
<constraint firstItem="cT0-Ux-t7H" firstAttribute="top" secondItem="kAN-ll-4wh" secondAttribute="bottom" id="8Tf-2A-QR5"/>
<constraint firstItem="yVW-fL-SIQ" firstAttribute="centerX" secondItem="gUf-g1-1af" secondAttribute="centerX" id="BgL-qD-g20"/>
<constraint firstItem="kAN-ll-4wh" firstAttribute="top" secondItem="yVW-fL-SIQ" secondAttribute="bottom" constant="8" symbolic="YES" id="Bt4-2a-aPr"/>
<constraint firstAttribute="trailing" secondItem="kAN-ll-4wh" secondAttribute="trailing" constant="20" id="DNM-FH-WaB"/>
<constraint firstItem="yVW-fL-SIQ" firstAttribute="top" secondItem="gUf-g1-1af" secondAttribute="top" id="bfq-gx-ofm"/>
<constraint firstItem="kAN-ll-4wh" firstAttribute="leading" secondItem="gUf-g1-1af" secondAttribute="leading" constant="20" id="dqc-ZN-G6v"/>
<constraint firstAttribute="height" constant="170" id="xvU-zX-6BQ"/>
<constraint firstAttribute="trailing" secondItem="cT0-Ux-t7H" secondAttribute="trailing" constant="20" id="yRX-lY-fXX"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3pG-br-PVl">
<rect key="frame" x="0.0" y="190" width="374" height="30"/>
<state key="normal" title="Log Out">
<color key="titleColor" systemColor="systemOrangeColor"/>
</state>
<connections>
<action selector="logout:" destination="3gV-kF-UbK" eventType="touchUpInside" id="dyQ-AR-u9Y"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="awy-Du-cqu">
<rect key="frame" x="0.0" y="240" width="374" height="30"/>
<state key="normal" title="Delete Account">
<color key="titleColor" systemColor="systemRedColor"/>
</state>
<connections>
<action selector="deleteAccount:" destination="3gV-kF-UbK" eventType="touchUpInside" id="iQ9-m9-VIm"/>
</connections>
</button>
</subviews>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="xo1-tu-MEz"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="gYR-mG-zfS" firstAttribute="leading" secondItem="yUd-Ri-s9C" secondAttribute="leading" constant="20" id="LuV-cO-Q8K"/>
<constraint firstItem="gYR-mG-zfS" firstAttribute="top" secondItem="yUd-Ri-s9C" secondAttribute="top" id="aTB-LN-BGK"/>
<constraint firstAttribute="trailing" secondItem="gYR-mG-zfS" secondAttribute="trailing" constant="20" id="fxQ-LY-4QQ"/>
</constraints>
</view>
<connections>
<outlet property="lJoinDate" destination="cT0-Ux-t7H" id="1XG-r8-Qr4"/>
<outlet property="lUsername" destination="kAN-ll-4wh" id="3Ta-rI-wql"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="pLc-eQ-yBW" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="948" y="1676"/>
</scene>
</scenes>
<resources>
<image name="alarm.fill" catalog="system" width="124" height="128"/>
<image name="checkmark" catalog="system" width="128" height="114"/>
<image name="clock.arrow.circlepath" catalog="system" width="128" height="110"/>
<image name="hammer.fill" catalog="system" width="128" height="117"/>
<image name="person.crop.circle" catalog="system" width="128" height="121"/>
<image name="person.crop.circle.badge.checkmark" catalog="system" width="128" height="113"/>
<image name="trash.fill" catalog="system" width="121" height="128"/>
<namedColor name="AccentColor">
<color red="0.0" green="0.46000000000000002" blue="0.89000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<systemColor name="labelColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="secondaryLabelColor">
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemGray4Color">
<color red="0.81960784313725488" green="0.81960784313725488" blue="0.83921568627450982" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemGray6Color">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemOrangeColor">
<color red="1" green="0.58431372549019611" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemRedColor">
<color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
+13
View File
@@ -2,6 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
-20
View File
@@ -1,20 +0,0 @@
//
// ProjectClock
//
// Created by Hykilpikonna on 1/8/21.
//
import Foundation
struct WVM
{
let name: String
let desc: String
}
let wvms = [
WVM(name: "Walk", desc: "Walk a few steps"),
WVM(name: "Jump", desc: "Make a few jumps"),
WVM(name: "Puzzle", desc: "Complete a simple puzzle"),
WVM(name: "Smash", desc: "It'll never truns off"),
]
+198
View File
@@ -0,0 +1,198 @@
//
// MathExpressions.swift
// ProjectClock
//
// Puzzles to complete for task (math or RPS)
//
import Foundation
/**
Math element for problem generation (Credit: https://stackoverflow.com/a/43132311/7346633)
*/
enum MathElement : CustomStringConvertible {
case Integer(value: Int)
case Percentage(value: Int)
case Expression(expression: MathExpression)
var description: String {
switch self {
case .Integer(let value): return "\(value)"
case .Percentage(let percentage): return "\(percentage)%"
case .Expression(let expr): return expr.description
}
}
var nsExpressionFormatString : String {
switch self {
case .Integer(let value): return "\(value).0"
case .Percentage(let percentage): return "\(Double(percentage) / 100)"
case .Expression(let expr): return "(\(expr.description))"
}
}
}
/**
Math operator for problem generation (Credit: https://stackoverflow.com/a/43132311/7346633)
*/
enum MathOperator : String {
case plus = "+"
case minus = "-"
case multiply = "*"
case divide = "/"
case power = "**"
static func random() -> MathOperator {
let allMathOperators: [MathOperator] = [.plus, .minus, .multiply, .divide, .power]
let index = Int(arc4random_uniform(UInt32(allMathOperators.count)))
return allMathOperators[index]
}
}
/**
Math expressions for problem generation (Credit: https://stackoverflow.com/a/43132311/7346633)
*/
class MathExpression : CustomStringConvertible {
var lhs: MathElement
var rhs: MathElement
var op: MathOperator
init(lhs: MathElement, rhs: MathElement, op: MathOperator) {
self.lhs = lhs
self.rhs = rhs
self.op = op
}
var description: String {
var leftString = ""
var rightString = ""
if case .Expression(_) = lhs {
leftString = "(\(lhs))"
} else {
leftString = lhs.description
}
if case .Expression(_) = rhs {
rightString = "(\(rhs))"
} else {
rightString = rhs.description
}
return "\(leftString) \(self.op.rawValue) \(rightString)"
}
var result : Int? {
let format = "\(lhs.nsExpressionFormatString) \(op.rawValue) \(rhs.nsExpressionFormatString)"
let expr = NSExpression(format: format)
return expr.expressionValue(with: nil, context: nil) as? Int
}
static func random() -> MathExpression {
let lhs = MathElement.Integer(value: Int(arc4random_uniform(10)))
let rhs = MathElement.Integer(value: Int(arc4random_uniform(10)))
return MathExpression(lhs: lhs, rhs: rhs, op: .random())
}
}
/**
Generate simple problem - 2 expressions
*/
class AlgProb2 : MathExpression {
let a = MathExpression.random()
let b = MathExpression.random()
func getProblem() -> String {
return "\(a) + \(b)"
}
func getAnswer() -> String {
return "\(a.result! + b.result!)"
}
}
/**
Generate simple problem - 3 expressions
*/
class AlgProb3 : MathExpression {
let a = MathExpression.random()
let b = MathExpression.random()
let c = MathExpression.random()
func getProblem() -> String {
return "\(a) + \(b) + \(c)"
}
func getAnswer() -> String {
return "\(a.result! + b.result! + c.result!)"
}
}
/**
Generate quadratic factorization problem
*/
class QuadraticProb {
// Generates the roots
let root1 = Int.random(in: 1...10)
let root2 = Int.random(in: 1...10)
/**
Generate problem description
*/
func getProblem() -> String {
//a is 1
let b = root1 + root2 //bx
let c = root1 * root2 //x
return "x^2 + \(b)x + \(c)"
}
/**
Finds the roots of the quadratic **NOTE**: the return type is [Int], not a String
*/
func getAnswer() -> [Int] {
return [root1, root2]
}
}
class RPS {
//@IBOutlet weak var resultsLabel: UILabel!
enum Choice: String {
case rock = "ROCK"
case paper = "PAPER"
case scissors = "SCISSORS"
}
static func randomComputerChoice() -> Choice {
let choices: [Choice] = [.rock, .paper, .scissors]
return choices[Int.random(in: 0...2)]
}
func playRPS(you: Choice, computer: Choice) -> Bool? {
if you == .rock && computer == .scissors { return true }
else if you == .paper && computer == .rock { return true}
else if you == .scissors && computer == .paper { return true }
else {
return false
}
}
/*
@IBAction func rock(_ sender: UIButton) {
let computerChoice = Choice.randomComputerChoice()
resultsLabel.text = playRPS(you: .rock, computer: computerChoice)
}
@IBAction func paper(_ sender: UIButton) {
let computerChoice = Choice.randomComputerChoice()
resultsLabel.text = playRPS(you: .paper, computer: computerChoice)
}
@IBAction func scissors(_ sender: UIButton) {
let computerChoice = Choice.randomComputerChoice()
resultsLabel.text = playRPS(you: .scissors, computer: computerChoice)
}
*/
}
+112 -1
View File
@@ -7,10 +7,121 @@
import Foundation
struct User: Decodable
struct User: Codable
{
var id: Int
var name: String
var email: String
var pass: String
}
struct Family: Codable
{
var fid: Int
var fname: String
var members: [String]
// And a hidden field: admin pin
}
struct WVM: Codable
{
let name: String
let desc: String
}
let wvms = [
WVM(name: "Factor", desc: "Factor a binomial"),
WVM(name: "RPS", desc: "Win a game of rock paper scissors"),
WVM(name: "Smash", desc: "It'll never turn off"),
WVM(name: "Walk", desc: "Walk a few steps"),
WVM(name: "Jump", desc: "Make a few jumps")
]
class Alarm: Codable
{
var enabled: Bool
var hour: Int // Hour (24)
var minute: Int
var text: String
var wakeMethod: WVM
/// What days does it repeat (Sun, Mon, Tue, Wed, Thu, Fri, Sat)
var repeats: [Bool]
/// Does it automatically disable after activating once
var oneTime: Bool
/// When is the last time that the alarm went off
var lastActivate: Date
/// Constructor
init(enabled: Bool = true,
hour: Int, minute: Int, text: String, wakeMethod: WVM,
repeats: [Bool] = [false, true, true, true, true, true, false],
oneTime: Bool = false, lastActivate: Date = Date()
)
{
self.enabled = enabled
self.hour = hour
self.minute = minute
self.text = text
self.wakeMethod = wakeMethod
self.repeats = repeats
self.oneTime = oneTime
self.lastActivate = lastActivate
}
/// When should the alarm activate next since lastActivate?
var nextActivate: Date?
{
let (y, m, d) = lastActivate.getYMD()
let (nh, nm, _) = lastActivate.getHMS()
// Create activation date
var date = Date.create(y, m, d, hour, minute)
// If it will activate tomorrow
if nh > hour || (nh == hour && nm >= minute) { date = date.added(.day, 1) }
// If it's one-time, don't have to check for repeating date
if oneTime { return date }
// Make sure it's repeating
guard (repeats.contains { $0 }) else { return nil }
// If the day is not one of the "repeat" days, keep adding 1 until it is
while !repeats[date.get(.weekday) - 1] { date = date.added(.day, 1) }
return date
}
}
class Alarms: Codable
{
var list: [Alarm] = []
/// Save alarms to local storage
func localSave()
{
localStorage.setValue(JSON.stringify(list)!, forKey: "alarms")
// Reload table view
if let table = AlarmViewController.staticTable { table.reloadData() }
}
/// Read alarms from local storage
func localRead() { list = JSON.parse([Alarm].self, localStorage.string(forKey: "alarms")!)! }
/// Read an alarm object from local storage
static func fromLocal() -> Alarms { return Alarms().apply { $0.localRead() } }
/// Get enabled alarms
var listEnabled: [Alarm] { return list.filter { $0.enabled } }
/// Get alarms that should be activating now
var listActivating: [Alarm]
{
let now = Date()
return listEnabled.filter { guard let n = $0.nextActivate else { return false }; return n < now }
}
}
+119 -24
View File
@@ -7,8 +7,27 @@
import Foundation
/// Base URL of the HTTP server
let baseUrl = "http://localhost:8080/api" // TODO: Production settings
let JSON = JSONDecoder()
let baseUrl = "https://alarm-clock-api.hydev.org"
/// Json class
class JSON
{
static let decoder = JSONDecoder()
static let encoder = JSONEncoder()
static func stringify<T: Encodable>(_ o: T) -> String?
{
guard let jsonData = try? encoder.encode(o) else { return nil }
return String(data: jsonData, encoding: String.Encoding.utf8)
}
static func parse<T: Decodable>(_ type: T.Type, _ j: String) -> T?
{
return try? decoder.decode(type, from: j.data(using: .utf8)!)
}
}
/// Local storage
let localStorage = UserDefaults(suiteName: "group.org.hydev.alarm.clock")!
/// API class
@@ -24,21 +43,32 @@ class APIs
Register the user in the database.
## Parameters
- name: The user's name (this is not username because it doesn't have to be unique)
- email: The user's email (this does have to be unique)
- pass: Password (initial hash)
- username: The user's unique username
- password: Password hash
## Returns
Success or error
*/
static let register = API<String>(loc: "/user/register")
/**
Verify password and login.
## Parameters
- username: The user's unique username
- password: Password hash
## Returns
Success or error
*/
static let login = API<String>(loc: "/user/login")
/**
Delete a user from the database.
## Parameters
- email: The user's email
- pass: Password (initial hash)
- username: The user's unique username
- password: Password hash
## Returns
Success or error
@@ -48,7 +78,7 @@ class APIs
/**
Upload curent config to the cloud.
## Parameters
## Parameters (Besides from username and password)
- config: The config json
## Returns
@@ -59,7 +89,7 @@ class APIs
/**
Download the config from the cloud.
## Parameters
## Parameters (Besides from username and password)
None
## Returns
@@ -67,24 +97,88 @@ class APIs
*/
static let downloadConfig = API<String>(loc: "/backup/download")
/**
Create a family
## Parameters (Besides from username and password)
- fname: Family name
- pin: Admin pin
## Returns
Family object
*/
static let familyCreate = API<Family>(loc: "/family/create")
/**
Delete a family
## Parameters (Besides from username and password)
- fid: Family ID
- pin: Admin pin
## Returns
Success or not
*/
static let familyDelete = API<String>(loc: "/family/delete")
/**
Change a family's admin pin
## Parameters (Besides from username and password)
- fid: Family ID
- orig_pin: Original admin pin
- new_pin: New admin pin
## Returns
Success or not
*/
static let familyChangePin = API<String>(loc: "/family/update_pin")
/**
Join family
## Parameters (Besides from username and password)
- fid: Family ID
- pin: Admin pin
## Returns
Family object
*/
static let familyJoin = API<Family>(loc: "/family/join")
/**
Leave family
## Parameters (Besides from username and password)
- fid: Family ID
- pin: Admin pin
## Returns
Success or not
*/
static let familyLeave = API<String>(loc: "/family/leave")
private init() {}
}
/**
Build a URL with the node path and params
Build a URLRequest with the node path and params
- Parameter api: API Node (Eg. APIs.register)
- Parameter params: Parameters to send to the server (Check the documentation of the API node to see which parameters you need)
- Returns: URL
- Returns: URLRequest
*/
func createUrl(_ node: String, _ params: [String: String]? = [:]) -> URL
func createRequest(_ node: String, _ params: [String: String]? = [:]) -> URLRequest
{
var url = URLComponents(string: baseUrl + node)
if let params = params
{
url?.queryItems = params.map { URLQueryItem(name: $0, value: $1) }
}
return url!.url!
// Create URL and request
let url = URLComponents(string: baseUrl + node)
var request = URLRequest(url: url!.url!)
request.httpMethod = "POST"
// Put parameters inside headers
params?.forEach { request.setValue($1, forHTTPHeaderField: $0) }
return request
}
/**
@@ -101,14 +195,12 @@ func send<T: Decodable>(_ api: API<T>, _ params: [String: String]? = [:], _ succ
var params = params
if params != nil
{
if params!["email"] == nil { params!["email"] = localStorage.string(forKey: "email") }
if params!["pass"] == nil { params!["pass"] = localStorage.string(forKey: "pass") }
if params!["username"] == nil { params!["username"] = localStorage.string(forKey: "name") }
if params!["password"] == nil { params!["password"] = localStorage.string(forKey: "pass") }
}
let url = createUrl(api.loc, params)
// Create task
let task = URLSession.shared.dataTask(with: url) { (raw, response, error) in
let task = URLSession.shared.dataTask(with: createRequest(api.loc, params)) { (raw, response, error) in
// Check if raw data exists
guard let response = response as? HTTPURLResponse, let raw = raw else { err("Data doesn't exist"); return }
@@ -116,8 +208,11 @@ func send<T: Decodable>(_ api: API<T>, _ params: [String: String]? = [:], _ succ
// If success
if (200...299).contains(response.statusCode)
{
// If the desired type is string, it doesn't have to parse json.
if T.self == String.self, let msg = String(data: raw, encoding: .utf8) { success(msg as! T); return }
// Parse JSON
guard let obj = try? JSON.decode(T.self, from: raw) else { err("JSON cannot be parsed"); return }
guard let obj = try? JSON.decoder.decode(T.self, from: raw) else { err("JSON cannot be parsed"); return }
// Call callback
success(obj)
+17 -11
View File
@@ -8,16 +8,7 @@
import Foundation
import CoreMotion
import UserNotifications
let motionManager = CMMotionManager()
func getAccelerometer() {
motionManager.startAccelerometerUpdates()
//print(motionManager.accelerometerData)
if let accelerometerData = motionManager.accelerometerData {
print("Acclerometer: \(accelerometerData)")
}
}
import UIKit
func walkAction() {
@@ -27,10 +18,25 @@ func jumpAction() {
}
func puzzleAction() {
func rpsAction(choice: RPS.Choice) -> Bool? {
let rps = RPS()
return rps.playRPS(you: choice, computer: RPS.randomComputerChoice())
}
// Handles the core logic behind the factoring alarm
func factorAction(puzzleQuestionLabel: UILabel) -> [Int] {
let problem = QuadraticProb()
let answer = problem.getAnswer()
let problemString = problem.getProblem()
puzzleQuestionLabel.text = "Solve: \(problemString)"
print("Answer: \(answer)")
return answer
}
func smashAction() {
}
-52
View File
@@ -1,52 +0,0 @@
//
// SceneDelegate.swift
// ProjectClock
//
// Created by Hykilpikonna on 1/6/21.
//
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
+129
View File
@@ -0,0 +1,129 @@
//
// StopwatchViewController.swift
// ProjectClock
//
// Created by Dallon Archibald on 1/23/21.
// Reference: https://youtu.be/H691qFRpaWA
import UIKit
class StopwatchViewController: UIViewController {
@IBOutlet weak var hourLabel: UILabel!
@IBOutlet weak var minuteLabel: UILabel!
@IBOutlet weak var secondLabel: UILabel!
@IBOutlet weak var startButton: UIButton!
@IBOutlet weak var stopButton: UIButton!
@IBOutlet weak var resetButton: UIButton!
@IBOutlet weak var lapButton: UIButton!
@IBOutlet weak var tableView: UITableView!
var hours = 0
var minutes = 0
var seconds = 0
var lappedTimes: [String] = []
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
//lapButton.isHidden = true
}
@IBAction func start(_ sender: UIButton) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(count), userInfo: nil, repeats: true)
//startButton.isHidden = true
//lapButton.isHidden = false
}
@objc fileprivate func count() {
seconds += 1
if seconds == 60 {
minutes += 1
seconds = 0
}
if minutes == 60 {
hours += 1
minutes = 0
}
if hours == 24 {
resetTimes()
}
if seconds >= 10 { secondLabel.text = "\(seconds)" }
else { secondLabel.text = "0\(seconds)" }
if minutes >= 10 { minuteLabel.text = "\(minutes)" }
else { minuteLabel.text = "0\(minutes)" }
if hours >= 10 { hourLabel.text = "\(hours)" }
else { hourLabel.text = "0\(hours)" }
}
@IBAction func stop(_ sender: UIButton) {
timer.invalidate()
//startButton.isHidden = false
}
@IBAction func reset(_ sender: UIButton) {
resetTimes()
}
func resetTimes() {
seconds = 0
minutes = 0
seconds = 0
lappedTimes = []
timer.invalidate()
secondLabel.text = "00"
minuteLabel.text = "00"
hourLabel.text = "00"
tableView.reloadData()
//startButton.isHidden = false
//lapButton.isHidden = true
}
@IBAction func lap(_ sender: UIButton) {
var currentSec = ""
if seconds >= 10 { currentSec = "\(seconds)" }
else { currentSec = "0\(seconds)" }
var currentMin = ""
if minutes >= 10 { currentMin = "\(minutes)" }
else { currentMin = "0\(minutes)" }
var currentHour = ""
if hours >= 10 { currentHour = "\(hours)" }
else { currentHour = "0\(hours)" }
let currentTime = "\(currentHour):\(currentMin):\(currentSec)" //CHECK THIS
lappedTimes.append(currentTime)
let indexPath = IndexPath(row: lappedTimes.count - 1, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
}
extension StopwatchViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return lappedTimes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "lapCell", for: indexPath)
cell.textLabel?.text = lappedTimes[indexPath.row]
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
lappedTimes.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
}
+24 -29
View File
@@ -8,30 +8,26 @@
import UIKit
import UserNotifications
class TestingViewController: UIViewController {
override func viewDidLoad() {
class TestingViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) {
(granted, error) in
if granted {
print("Authorized Notifications")
} else {
print("Error: No notification access")
}
}
// Do any additional setup after loading the view.
}
@IBAction func getAccel(_ sender: Any) {
getAccelerometer()
// Request notification permission
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
print("All set!")
} else if let error = error {
print(error.localizedDescription)
}
}
}
//Sends a test notification
@IBAction func sendNotification(_ sender: Any) {
let alarm = Alarm(alarmTime: Date(), text: "Good morning!", wakeMethod: WVM(name: "walking", desc: "Walk"))
@IBAction func sendNotification(_ sender: Any)
{
let alarm = Alarm(hour: 7, minute: 20, text: "Good morning!", wakeMethod: WVM(name: "walking", desc: "Walk"))
let content = UNMutableNotificationContent()
@@ -51,7 +47,6 @@ class TestingViewController: UIViewController {
let attachment = try! UNNotificationAttachment(identifier: imageName, url: imageURL, options: .none)
content.attachments = [attachment]
// Readies notification to be sent
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "notification.id.01", content: content, trigger: trigger)
@@ -60,14 +55,14 @@ class TestingViewController: UIViewController {
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
@IBAction func addAlarm(_ sender: Any)
{
let (h, m, _) = Date().getHMS()
Alarms.fromLocal().apply { $0.list.append(Alarm(hour: h, minute: m, text: "Test alarm - \(h * m)", wakeMethod: wvms[1], repeats: [true, true, true, true, true, true, true], oneTime: true, lastActivate: Date().added(.minute, -1))) }.localSave()
}
@IBAction func deleteAlarm(_ sender: Any)
{
Alarms.fromLocal().apply { $0.list.removeAll() }.localSave()
}
*/
}
+211
View File
@@ -0,0 +1,211 @@
//
// Utils.swift
// ProjectClock
//
// Created by Hykilpikonna on 1/17/21.
//
import Foundation
import CryptoKit
import UIKit
/// Date manipulations
extension Date
{
/// Add toString to Date
func str() -> String
{
let f = DateFormatter()
f.dateFormat = "yyyy-MM-dd hh:mm:ss"
return f.string(from: self)
}
/// Constructor from components
static func create(_ year: Int, _ month: Int, _ day: Int, _ hour: Int, _ minute: Int) -> Date
{
var c = DateComponents()
c.year = year
c.month = month
c.day = day
c.hour = hour
c.minute = minute
let cal = Calendar(identifier: .gregorian)
return cal.date(from: c)!
}
/// Get year, month, day
func getYMD() -> (y: Int, m: Int, d: Int)
{
let calendar = Calendar.current
let comp = calendar.dateComponents([.year, .month, .day], from: self)
return (comp.year!, comp.month!, comp.day!)
}
/// Get hour, minute, seconds
func getHMS() -> (h: Int, m: Int, s: Int)
{
let calendar = Calendar.current
let comp = calendar.dateComponents([.hour, .minute, .second], from: self)
return (comp.hour!, comp.minute!, comp.second!)
}
/// Get another component
func get(_ c: Calendar.Component) -> Int
{
let calendar = Calendar.current
let comp = calendar.dateComponents([c], from: self)
return comp.value(for: c)!
}
/// Return a new modified date
func added(_ c: Calendar.Component, _ v: Int) -> Date
{
return Calendar.current.date(byAdding: c, value: v, to: self)!
}
}
extension TimeInterval
{
var seconds: Int { return Int(self) % 60 }
var minutes: Int { return (Int(self) / 60) % 60 }
var hours: Int { return (Int(self) / 3600) % 24 }
var days: Int { return Int(self) / (3600 * 24) }
/// Add toString to time interval
func str() -> String
{
if days != 0 { return "\(days)d \(hours)h \(minutes)m \(seconds)s" }
else if hours != 0 { return "\(hours)h \(minutes)m \(seconds)s" }
else if minutes != 0 { return "\(minutes)m \(seconds)s" }
else { return "\(seconds)s" }
}
}
/// Apply like Kotlin
protocol HasApply {}
extension HasApply
{
@discardableResult
func apply(_ c: (Self) -> ()) -> Self
{
c(self)
return self
}
}
extension Alarm: HasApply {}
extension Alarms: HasApply {}
/// Hashing
extension Digest
{
var bytes: [UInt8] { Array(makeIterator()) }
var b64: String { Data(bytes).base64EncodedString() }
}
extension String
{
var sha256: String { SHA256.hash(data: self.data(using: .utf8)!).b64 }
}
/// UI Extensions
extension UIViewController
{
/**
Send an alert
- Parameter title: Title of the alert
- Parameter message: Body message of the alert
- Parameter okayable: Whether the alert can be okayed
*/
@discardableResult
func alert(_ title: String, _ message: String, okayable: Bool = false) -> UIAlertController
{
// Create alert
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
// Add okay button if it's okayable
if okayable { alert.addAction(UIAlertAction(title: "OK", style: .default)) }
// Display alert
self.present(alert, animated: true, completion: nil)
return alert
}
/// A message is an okayable alert
@discardableResult
func msg(_ title: String, _ message: String) -> UIAlertController { alert(title, message, okayable: true) }
/// More convenient dismiss function
func dismiss(_ completion: (() -> Void)? = nil) { ui { self.dismiss(animated: false, completion: completion) } }
/**
Send a http request even more conveniently
*/
func sendReq<T: Decodable>(_ api: API<T>, title: String, errors: [String: String] = [:], params: [String: String]? = [:], _ success: @escaping (T) -> Void, err: @escaping (String) -> Void = {it in})
{
// Send request
let a = alert(title, "Please Wait")
send(api, params) { it in a.dismiss { success(it) } }
err:
{
// Display error message
print("===== Error: \($0) =====")
let message = errors[$0.trimmingCharacters(in: .whitespaces)]
?? "Maybe the server is on fire, just wait a few hours."
a.dismiss { self.msg("An error occurred", message) }
}
}
}
/// Regex Matching (Credit: https://www.hackingwithswift.com/articles/108/how-to-use-regular-expressions-in-swift)
extension NSRegularExpression
{
convenience init(_ pattern: String)
{
do { try self.init(pattern: pattern) }
catch { preconditionFailure("Illegal regular expression: \(pattern).") }
}
func matches(_ string: String) -> Bool
{
let range = NSRange(location: 0, length: string.utf16.count)
return firstMatch(in: string, options: [], range: range) != nil
}
}
extension String
{
static func ~= (lhs: String, rhs: String) -> Bool
{
guard let regex = try? NSRegularExpression(pattern: rhs) else { return false }
let range = NSRange(location: 0, length: lhs.utf16.count)
return regex.firstMatch(in: lhs, options: [], range: range) != nil
}
}
/// More convenient ui update closure
func ui(closure: @escaping () -> Void) { DispatchQueue.main.async { closure() } }
/// More convenient UserDefaults access (Credit: https://gist.github.com/Otbivnoe/04b8bd7984fba0cb58ca7f136fd95582)
extension UserDefaults
{
subscript<T>(key: String) -> T?
{
get { return value(forKey: key) as? T }
set { set(newValue, forKey: key) }
}
subscript<T: RawRepresentable>(key: String) -> T?
{
get
{
if let rawValue = value(forKey: key) as? T.RawValue { return T(rawValue: rawValue) }
return nil
}
set { self[key] = newValue?.rawValue }
}
}