diff --git a/Podfile b/Podfile index bd8ef69..6e9d1b3 100644 --- a/Podfile +++ b/Podfile @@ -7,4 +7,6 @@ target 'lesson31_Auth_Flow+AppCoordinator' do # Pods for lesson31_Auth_Flow+AppCoordinator pod 'R.swift' + pod 'SnapKit', '~> 5.0.0' + pod 'ProgressHUD' end diff --git a/Podfile.lock b/Podfile.lock index 10c0518..6f7330f 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,20 +1,28 @@ PODS: + - ProgressHUD (2.70) - R.swift (5.2.2): - R.swift.Library (~> 5.2.0) - R.swift.Library (5.2.0) + - SnapKit (5.0.1) DEPENDENCIES: + - ProgressHUD - R.swift + - SnapKit (~> 5.0.0) SPEC REPOS: trunk: + - ProgressHUD - R.swift - R.swift.Library + - SnapKit SPEC CHECKSUMS: + ProgressHUD: e603e8b8622c47d8818b9fb38b3cfe9d3e7ca421 R.swift: 7c52cdc57a66840ffe6cbd8a823d732059d42a32 R.swift.Library: 5ba4f1631300caf9a4d890186930da85d540769d + SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb -PODFILE CHECKSUM: 387a4777a0acf2fecaa335f3f058fe7945f9fbdb +PODFILE CHECKSUM: f0ae180ca3ac9151f8cfde0645edb6989f89ea5b -COCOAPODS: 1.9.1 +COCOAPODS: 1.9.3 diff --git a/lesson31_Auth_Flow+AppCoordinator.xcodeproj/project.pbxproj b/lesson31_Auth_Flow+AppCoordinator.xcodeproj/project.pbxproj index 1d7270a..988acaf 100644 --- a/lesson31_Auth_Flow+AppCoordinator.xcodeproj/project.pbxproj +++ b/lesson31_Auth_Flow+AppCoordinator.xcodeproj/project.pbxproj @@ -7,13 +7,38 @@ objects = { /* Begin PBXBuildFile section */ - 30085B2524C090860023889F /* Registration.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 30085B2424C090860023889F /* Registration.storyboard */; }; - 30085B2724C0909A0023889F /* RestorePassword.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 30085B2624C0909A0023889F /* RestorePassword.storyboard */; }; 30085B2924C1799F0023889F /* AuthFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30085B2824C1799F0023889F /* AuthFlowCoordinator.swift */; }; - 30085B2B24C17F710023889F /* CoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30085B2A24C17F710023889F /* CoordinatorProtocol.swift */; }; 301358CB24BEF5D300416177 /* AuthButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301358CA24BEF5D300416177 /* AuthButton.swift */; }; 301358CD24BF261700416177 /* FieldsValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301358CC24BF261700416177 /* FieldsValidator.swift */; }; + AF2BAF2424C99CD400487900 /* SlideModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2BAF2324C99CD400487900 /* SlideModel.swift */; }; + AF2BAF6E24C99EA000487900 /* SlideView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2BAF6A24C99E9F00487900 /* SlideView.swift */; }; + AF2BAF6F24C99EA000487900 /* Button.xib in Resources */ = {isa = PBXBuildFile; fileRef = AF2BAF6B24C99E9F00487900 /* Button.xib */; }; + AF2BAF7024C99EA000487900 /* Slide.xib in Resources */ = {isa = PBXBuildFile; fileRef = AF2BAF6C24C99E9F00487900 /* Slide.xib */; }; + AF2BAF7124C99EA000487900 /* TutorialButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2BAF6D24C99E9F00487900 /* TutorialButton.swift */; }; + AF9CB03B24C8BE1D00D5CDFA /* TutorialCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF9CB03A24C8BE1D00D5CDFA /* TutorialCoordinator.swift */; }; E657DBE5F790CF2C8A191BEE /* Pods_lesson31_Auth_Flow_AppCoordinator.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA8EED1D3C5088404923F605 /* Pods_lesson31_Auth_Flow_AppCoordinator.framework */; }; + E72B37EF24C9B02700F07DEF /* MyLessonsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F910424C2174400860461 /* MyLessonsCoordinator.swift */; }; + 30B1ABFC24C864DF000EAE1C /* RestoreController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B1ABFB24C864DF000EAE1C /* RestoreController.swift */; }; + 30B3416324CAE1C90038057A /* FieldsFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B3416224CAE1C90038057A /* FieldsFormatter.swift */; }; + E657DBE5F790CF2C8A191BEE /* Pods_lesson31_Auth_Flow_AppCoordinator.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA8EED1D3C5088404923F605 /* Pods_lesson31_Auth_Flow_AppCoordinator.framework */; }; + E72B37F124CB41C500F07DEF /* LessonDetailedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72B37F024CB41C500F07DEF /* LessonDetailedController.swift */; }; + E72B37F324CB41D600F07DEF /* Lesson.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72B37F224CB41D600F07DEF /* Lesson.swift */; }; + E72B37F624CB420300F07DEF /* LessonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72B37F524CB420300F07DEF /* LessonCell.swift */; }; + E72B37FA24CB484B00F07DEF /* MyLessonsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72B37F924CB484B00F07DEF /* MyLessonsViewModel.swift */; }; + E78F90EB24C2118000860461 /* MainCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F90EA24C2118000860461 /* MainCoordinator.swift */; }; + E78F90F124C2140700860461 /* Kupons.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E78F90F024C2140700860461 /* Kupons.storyboard */; }; + E78F90F324C2140F00860461 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E78F90F224C2140F00860461 /* Settings.storyboard */; }; + E78F90F524C2142600860461 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F90F424C2142600860461 /* SettingsController.swift */; }; + E78F90F724C2143400860461 /* KuponsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F90F624C2143400860461 /* KuponsController.swift */; }; + E78F90F924C2143F00860461 /* MyLessonsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F90F824C2143F00860461 /* MyLessonsController.swift */; }; + E78F90FB24C2144600860461 /* MyLessons.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E78F90FA24C2144600860461 /* MyLessons.storyboard */; }; + E78F90FD24C2145000860461 /* Lessons.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E78F90FC24C2145000860461 /* Lessons.storyboard */; }; + E78F90FF24C2145A00860461 /* LessonsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F90FE24C2145A00860461 /* LessonsController.swift */; }; + E78F910124C2172E00860461 /* KuponsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F910024C2172E00860461 /* KuponsCoordinator.swift */; }; + E78F910324C2173B00860461 /* SettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F910224C2173B00860461 /* SettingsCoordinator.swift */; }; + E78F910724C2174D00860461 /* LessonsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F910624C2174D00860461 /* LessonsCoordinator.swift */; }; + E78F910C24C21CB600860461 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F910A24C21CB500860461 /* Coordinator.swift */; }; + E78F910D24C21CB600860461 /* CoordinatorProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E78F910B24C21CB500860461 /* CoordinatorProtocol.swift */; }; E7A50E7D24B8D790007274E2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A50E7C24B8D790007274E2 /* AppDelegate.swift */; }; E7A50E8624B8D793007274E2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E7A50E8524B8D793007274E2 /* Assets.xcassets */; }; E7A50E8924B8D793007274E2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E7A50E8724B8D793007274E2 /* LaunchScreen.storyboard */; }; @@ -25,27 +50,48 @@ E7A50EAE24B8D7D7007274E2 /* RegistrationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A50E9A24B8D7D6007274E2 /* RegistrationController.swift */; }; E7A50EAF24B8D7D7007274E2 /* LoginController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A50E9B24B8D7D6007274E2 /* LoginController.swift */; }; E7A50EB024B8D7D7007274E2 /* RestorePasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A50E9C24B8D7D6007274E2 /* RestorePasswordController.swift */; }; - E7A50EB124B8D7D7007274E2 /* Login.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E7A50E9D24B8D7D6007274E2 /* Login.storyboard */; }; - E7A50EB224B8D7D7007274E2 /* Start.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E7A50E9F24B8D7D6007274E2 /* Start.storyboard */; }; - E7A50EB324B8D7D7007274E2 /* StartController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A50EA024B8D7D6007274E2 /* StartController.swift */; }; E7A50EB424B8D7D7007274E2 /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A50EA224B8D7D6007274E2 /* MainController.swift */; }; - E7A50EB524B8D7D7007274E2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E7A50EA324B8D7D6007274E2 /* Main.storyboard */; }; E7A50EB624B8D7D7007274E2 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A50EA524B8D7D7007274E2 /* BaseViewController.swift */; }; E7A50EB724B8D7D7007274E2 /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A50EA624B8D7D7007274E2 /* NavigationController.swift */; }; E7A50EB824B8D7D7007274E2 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A50EA824B8D7D7007274E2 /* AppSettings.swift */; }; E7B0A53A24B8DD0F00221B50 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B0A53924B8DD0F00221B50 /* AppCoordinator.swift */; }; E7B0A54224B8E2E600221B50 /* R.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7B0A54124B8E2E600221B50 /* R.generated.swift */; }; + E7F1729A24C207A200B25942 /* Auth.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E7F1729924C207A200B25942 /* Auth.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 1D61E26FA2C80D98B6F840CD /* Pods-lesson31_Auth_Flow+AppCoordinator.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-lesson31_Auth_Flow+AppCoordinator.release.xcconfig"; path = "Target Support Files/Pods-lesson31_Auth_Flow+AppCoordinator/Pods-lesson31_Auth_Flow+AppCoordinator.release.xcconfig"; sourceTree = ""; }; - 30085B2424C090860023889F /* Registration.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Registration.storyboard; sourceTree = ""; }; - 30085B2624C0909A0023889F /* RestorePassword.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = RestorePassword.storyboard; sourceTree = ""; }; 30085B2824C1799F0023889F /* AuthFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthFlowCoordinator.swift; sourceTree = ""; }; - 30085B2A24C17F710023889F /* CoordinatorProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatorProtocol.swift; sourceTree = ""; }; 301358CA24BEF5D300416177 /* AuthButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthButton.swift; sourceTree = ""; }; 301358CC24BF261700416177 /* FieldsValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldsValidator.swift; sourceTree = ""; }; + 30B1ABFB24C864DF000EAE1C /* RestoreController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoreController.swift; sourceTree = ""; }; + 30B3416224CAE1C90038057A /* FieldsFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldsFormatter.swift; sourceTree = ""; }; 54B81FF14751E81C8551CD44 /* Pods-lesson31_Auth_Flow+AppCoordinator.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-lesson31_Auth_Flow+AppCoordinator.debug.xcconfig"; path = "Target Support Files/Pods-lesson31_Auth_Flow+AppCoordinator/Pods-lesson31_Auth_Flow+AppCoordinator.debug.xcconfig"; sourceTree = ""; }; + AF2BAF2324C99CD400487900 /* SlideModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlideModel.swift; sourceTree = ""; }; + AF2BAF6A24C99E9F00487900 /* SlideView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SlideView.swift; sourceTree = ""; }; + AF2BAF6B24C99E9F00487900 /* Button.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Button.xib; sourceTree = ""; }; + AF2BAF6C24C99E9F00487900 /* Slide.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Slide.xib; sourceTree = ""; }; + AF2BAF6D24C99E9F00487900 /* TutorialButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TutorialButton.swift; sourceTree = ""; }; + AF9CB03A24C8BE1D00D5CDFA /* TutorialCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TutorialCoordinator.swift; sourceTree = ""; }; + E72B37F024CB41C500F07DEF /* LessonDetailedController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LessonDetailedController.swift; sourceTree = ""; }; + E72B37F224CB41D600F07DEF /* Lesson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lesson.swift; sourceTree = ""; }; + E72B37F524CB420300F07DEF /* LessonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LessonCell.swift; sourceTree = ""; }; + E72B37F924CB484B00F07DEF /* MyLessonsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyLessonsViewModel.swift; sourceTree = ""; }; + E78F90EA24C2118000860461 /* MainCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainCoordinator.swift; sourceTree = ""; }; + E78F90F024C2140700860461 /* Kupons.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Kupons.storyboard; sourceTree = ""; }; + E78F90F224C2140F00860461 /* Settings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; + E78F90F424C2142600860461 /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = ""; }; + E78F90F624C2143400860461 /* KuponsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KuponsController.swift; sourceTree = ""; }; + E78F90F824C2143F00860461 /* MyLessonsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyLessonsController.swift; sourceTree = ""; }; + E78F90FA24C2144600860461 /* MyLessons.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MyLessons.storyboard; sourceTree = ""; }; + E78F90FC24C2145000860461 /* Lessons.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Lessons.storyboard; sourceTree = ""; }; + E78F90FE24C2145A00860461 /* LessonsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LessonsController.swift; sourceTree = ""; }; + E78F910024C2172E00860461 /* KuponsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KuponsCoordinator.swift; sourceTree = ""; }; + E78F910224C2173B00860461 /* SettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCoordinator.swift; sourceTree = ""; }; + E78F910424C2174400860461 /* MyLessonsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyLessonsCoordinator.swift; sourceTree = ""; }; + E78F910624C2174D00860461 /* LessonsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LessonsCoordinator.swift; sourceTree = ""; }; + E78F910A24C21CB500860461 /* Coordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; + E78F910B24C21CB500860461 /* CoordinatorProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoordinatorProtocol.swift; sourceTree = ""; }; E7A50E7924B8D790007274E2 /* lesson31_Auth_Flow+AppCoordinator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "lesson31_Auth_Flow+AppCoordinator.app"; sourceTree = BUILT_PRODUCTS_DIR; }; E7A50E7C24B8D790007274E2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; E7A50E8524B8D793007274E2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -59,16 +105,13 @@ E7A50E9A24B8D7D6007274E2 /* RegistrationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegistrationController.swift; sourceTree = ""; }; E7A50E9B24B8D7D6007274E2 /* LoginController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginController.swift; sourceTree = ""; }; E7A50E9C24B8D7D6007274E2 /* RestorePasswordController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestorePasswordController.swift; sourceTree = ""; }; - E7A50E9D24B8D7D6007274E2 /* Login.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Login.storyboard; sourceTree = ""; }; - E7A50E9F24B8D7D6007274E2 /* Start.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Start.storyboard; sourceTree = ""; }; - E7A50EA024B8D7D6007274E2 /* StartController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StartController.swift; sourceTree = ""; }; E7A50EA224B8D7D6007274E2 /* MainController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = ""; }; - E7A50EA324B8D7D6007274E2 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; E7A50EA524B8D7D7007274E2 /* BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; E7A50EA624B8D7D7007274E2 /* NavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationController.swift; sourceTree = ""; }; E7A50EA824B8D7D7007274E2 /* AppSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = ""; }; E7B0A53924B8DD0F00221B50 /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = ""; }; E7B0A54124B8E2E600221B50 /* R.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = R.generated.swift; sourceTree = ""; }; + E7F1729924C207A200B25942 /* Auth.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Auth.storyboard; sourceTree = ""; }; EA8EED1D3C5088404923F605 /* Pods_lesson31_Auth_Flow_AppCoordinator.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_lesson31_Auth_Flow_AppCoordinator.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -92,6 +135,17 @@ name = Frameworks; sourceTree = ""; }; + AF2BAF6924C99E9F00487900 /* Views */ = { + isa = PBXGroup; + children = ( + AF2BAF6B24C99E9F00487900 /* Button.xib */, + AF2BAF6D24C99E9F00487900 /* TutorialButton.swift */, + AF2BAF6C24C99E9F00487900 /* Slide.xib */, + AF2BAF6A24C99E9F00487900 /* SlideView.swift */, + ); + path = Views; + sourceTree = ""; + }; D637E7D9864C43F996879238 /* Pods */ = { isa = PBXGroup; children = ( @@ -101,6 +155,85 @@ path = Pods; sourceTree = ""; }; + E72B37F424CB41E900F07DEF /* Cells */ = { + isa = PBXGroup; + children = ( + E72B37F524CB420300F07DEF /* LessonCell.swift */, + ); + path = Cells; + sourceTree = ""; + }; + E72B37F824CB483800F07DEF /* ViewModel */ = { + isa = PBXGroup; + children = ( + E72B37F924CB484B00F07DEF /* MyLessonsViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + E78F90EC24C213D600860461 /* Lessons */ = { + isa = PBXGroup; + children = ( + E72B37F424CB41E900F07DEF /* Cells */, + E78F90FE24C2145A00860461 /* LessonsController.swift */, + E72B37F024CB41C500F07DEF /* LessonDetailedController.swift */, + E78F910624C2174D00860461 /* LessonsCoordinator.swift */, + E78F90FC24C2145000860461 /* Lessons.storyboard */, + ); + path = Lessons; + sourceTree = ""; + }; + E78F90ED24C213DD00860461 /* MyLessons */ = { + isa = PBXGroup; + children = ( + E72B37F824CB483800F07DEF /* ViewModel */, + E78F90F824C2143F00860461 /* MyLessonsController.swift */, + E78F910424C2174400860461 /* MyLessonsCoordinator.swift */, + E78F90FA24C2144600860461 /* MyLessons.storyboard */, + ); + path = MyLessons; + sourceTree = ""; + }; + E78F90EE24C213E300860461 /* Settings */ = { + isa = PBXGroup; + children = ( + E78F90F424C2142600860461 /* SettingsController.swift */, + E78F910224C2173B00860461 /* SettingsCoordinator.swift */, + E78F90F224C2140F00860461 /* Settings.storyboard */, + ); + path = Settings; + sourceTree = ""; + }; + E78F90EF24C213E900860461 /* Kupons */ = { + isa = PBXGroup; + children = ( + E78F90F624C2143400860461 /* KuponsController.swift */, + E78F910024C2172E00860461 /* KuponsCoordinator.swift */, + E78F90F024C2140700860461 /* Kupons.storyboard */, + ); + path = Kupons; + sourceTree = ""; + }; + E78F910824C2179300860461 /* Controllers */ = { + isa = PBXGroup; + children = ( + E7A50E9B24B8D7D6007274E2 /* LoginController.swift */, + E7A50E9A24B8D7D6007274E2 /* RegistrationController.swift */, + E7A50E9C24B8D7D6007274E2 /* RestorePasswordController.swift */, + 30B1ABFB24C864DF000EAE1C /* RestoreController.swift */, + ); + path = Controllers; + sourceTree = ""; + }; + E78F910924C21BD900860461 /* Core */ = { + isa = PBXGroup; + children = ( + E78F910A24C21CB500860461 /* Coordinator.swift */, + E78F910B24C21CB500860461 /* CoordinatorProtocol.swift */, + ); + path = Core; + sourceTree = ""; + }; E7A50E7024B8D790007274E2 = { isa = PBXGroup; children = ( @@ -122,6 +255,7 @@ E7A50E7B24B8D790007274E2 /* lesson31_Auth_Flow+AppCoordinator */ = { isa = PBXGroup; children = ( + E78F910924C21BD900860461 /* Core */, E7B0A54024B8E2B700221B50 /* Tools */, E7A50EA724B8D7D7007274E2 /* BusinessLogic */, E7A50E9024B8D7D6007274E2 /* Extensions */, @@ -147,6 +281,8 @@ isa = PBXGroup; children = ( E7A50E9424B8D7D6007274E2 /* User.swift */, + AF2BAF2324C99CD400487900 /* SlideModel.swift */, + E72B37F224CB41D600F07DEF /* Lesson.swift */, ); path = Models; sourceTree = ""; @@ -156,7 +292,6 @@ children = ( E7A50E9624B8D7D6007274E2 /* Tutorial */, E7A50E9924B8D7D6007274E2 /* Auth */, - E7A50E9E24B8D7D6007274E2 /* Start */, E7A50EA124B8D7D6007274E2 /* Main */, E7A50EA424B8D7D7007274E2 /* Base */, ); @@ -166,8 +301,10 @@ E7A50E9624B8D7D6007274E2 /* Tutorial */ = { isa = PBXGroup; children = ( + AF2BAF6924C99E9F00487900 /* Views */, E7A50E9724B8D7D6007274E2 /* TutorialController.swift */, E7A50E9824B8D7D6007274E2 /* Tutorial.storyboard */, + AF9CB03A24C8BE1D00D5CDFA /* TutorialCoordinator.swift */, ); path = Tutorial; sourceTree = ""; @@ -175,32 +312,23 @@ E7A50E9924B8D7D6007274E2 /* Auth */ = { isa = PBXGroup; children = ( - 301358CA24BEF5D300416177 /* AuthButton.swift */, - E7A50E9B24B8D7D6007274E2 /* LoginController.swift */, - E7A50E9D24B8D7D6007274E2 /* Login.storyboard */, - E7A50E9A24B8D7D6007274E2 /* RegistrationController.swift */, - 30085B2424C090860023889F /* Registration.storyboard */, - E7A50E9C24B8D7D6007274E2 /* RestorePasswordController.swift */, - 30085B2624C0909A0023889F /* RestorePassword.storyboard */, + E78F910824C2179300860461 /* Controllers */, + E7F1729B24C2080A00B25942 /* Views */, 30085B2824C1799F0023889F /* AuthFlowCoordinator.swift */, + E7F1729924C207A200B25942 /* Auth.storyboard */, ); path = Auth; sourceTree = ""; }; - E7A50E9E24B8D7D6007274E2 /* Start */ = { - isa = PBXGroup; - children = ( - E7A50EA024B8D7D6007274E2 /* StartController.swift */, - E7A50E9F24B8D7D6007274E2 /* Start.storyboard */, - ); - path = Start; - sourceTree = ""; - }; E7A50EA124B8D7D6007274E2 /* Main */ = { isa = PBXGroup; children = ( + E78F90EC24C213D600860461 /* Lessons */, + E78F90ED24C213DD00860461 /* MyLessons */, + E78F90EF24C213E900860461 /* Kupons */, + E78F90EE24C213E300860461 /* Settings */, E7A50EA224B8D7D6007274E2 /* MainController.swift */, - E7A50EA324B8D7D6007274E2 /* Main.storyboard */, + E78F90EA24C2118000860461 /* MainCoordinator.swift */, ); path = Main; sourceTree = ""; @@ -220,7 +348,6 @@ E7A50E7C24B8D790007274E2 /* AppDelegate.swift */, E7A50EA824B8D7D7007274E2 /* AppSettings.swift */, E7B0A53924B8DD0F00221B50 /* AppCoordinator.swift */, - 30085B2A24C17F710023889F /* CoordinatorProtocol.swift */, ); path = BusinessLogic; sourceTree = ""; @@ -230,10 +357,19 @@ children = ( E7B0A54124B8E2E600221B50 /* R.generated.swift */, 301358CC24BF261700416177 /* FieldsValidator.swift */, + 30B3416224CAE1C90038057A /* FieldsFormatter.swift */, ); path = Tools; sourceTree = ""; }; + E7F1729B24C2080A00B25942 /* Views */ = { + isa = PBXGroup; + children = ( + 301358CA24BEF5D300416177 /* AuthButton.swift */, + ); + path = Views; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -263,6 +399,12 @@ E7A50E7124B8D790007274E2 /* Project object */ = { isa = PBXProject; attributes = { + KnownAssetTags = ( + scr1, + scr2, + scr3, + scr4, + ); LastSwiftUpdateCheck = 1150; LastUpgradeCheck = 1150; ORGANIZATIONNAME = Bosov; @@ -295,13 +437,15 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 30085B2724C0909A0023889F /* RestorePassword.storyboard in Resources */, - E7A50EB124B8D7D7007274E2 /* Login.storyboard in Resources */, + E7F1729A24C207A200B25942 /* Auth.storyboard in Resources */, E7A50E8924B8D793007274E2 /* LaunchScreen.storyboard in Resources */, - 30085B2524C090860023889F /* Registration.storyboard in Resources */, - E7A50EB224B8D7D7007274E2 /* Start.storyboard in Resources */, - E7A50EB524B8D7D7007274E2 /* Main.storyboard in Resources */, + AF2BAF7024C99EA000487900 /* Slide.xib in Resources */, + AF2BAF6F24C99EA000487900 /* Button.xib in Resources */, + E78F90F124C2140700860461 /* Kupons.storyboard in Resources */, + E78F90F324C2140F00860461 /* Settings.storyboard in Resources */, + E78F90FB24C2144600860461 /* MyLessons.storyboard in Resources */, E7A50EAD24B8D7D7007274E2 /* Tutorial.storyboard in Resources */, + E78F90FD24C2145000860461 /* Lessons.storyboard in Resources */, E7A50E8624B8D793007274E2 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -375,20 +519,39 @@ buildActionMask = 2147483647; files = ( E7A50EB824B8D7D7007274E2 /* AppSettings.swift in Sources */, + E78F90EB24C2118000860461 /* MainCoordinator.swift in Sources */, + E78F90FF24C2145A00860461 /* LessonsController.swift in Sources */, E7A50EAB24B8D7D7007274E2 /* User.swift in Sources */, 301358CD24BF261700416177 /* FieldsValidator.swift in Sources */, + 30B1ABFC24C864DF000EAE1C /* RestoreController.swift in Sources */, + E72B37FA24CB484B00F07DEF /* MyLessonsViewModel.swift in Sources */, E7B0A54224B8E2E600221B50 /* R.generated.swift in Sources */, + E72B37EF24C9B02700F07DEF /* MyLessonsCoordinator.swift in Sources */, E7A50EB724B8D7D7007274E2 /* NavigationController.swift in Sources */, E7A50E7D24B8D790007274E2 /* AppDelegate.swift in Sources */, + E78F910C24C21CB600860461 /* Coordinator.swift in Sources */, E7A50EB624B8D7D7007274E2 /* BaseViewController.swift in Sources */, - E7A50EB324B8D7D7007274E2 /* StartController.swift in Sources */, + AF9CB03B24C8BE1D00D5CDFA /* TutorialCoordinator.swift in Sources */, + AF2BAF2424C99CD400487900 /* SlideModel.swift in Sources */, 30085B2924C1799F0023889F /* AuthFlowCoordinator.swift in Sources */, E7B0A53A24B8DD0F00221B50 /* AppCoordinator.swift in Sources */, + AF2BAF7124C99EA000487900 /* TutorialButton.swift in Sources */, + AF2BAF6E24C99EA000487900 /* SlideView.swift in Sources */, E7A50EA924B8D7D7007274E2 /* NSObject.swift in Sources */, - 30085B2B24C17F710023889F /* CoordinatorProtocol.swift in Sources */, + E78F910D24C21CB600860461 /* CoordinatorProtocol.swift in Sources */, + E72B37F624CB420300F07DEF /* LessonCell.swift in Sources */, + E78F910124C2172E00860461 /* KuponsCoordinator.swift in Sources */, + E78F90F924C2143F00860461 /* MyLessonsController.swift in Sources */, 301358CB24BEF5D300416177 /* AuthButton.swift in Sources */, + E78F90F724C2143400860461 /* KuponsController.swift in Sources */, E7A50EB424B8D7D7007274E2 /* MainController.swift in Sources */, + E78F90F524C2142600860461 /* SettingsController.swift in Sources */, E7A50EAC24B8D7D7007274E2 /* TutorialController.swift in Sources */, + E78F910724C2174D00860461 /* LessonsCoordinator.swift in Sources */, + E72B37F124CB41C500F07DEF /* LessonDetailedController.swift in Sources */, + E78F910324C2173B00860461 /* SettingsCoordinator.swift in Sources */, + 30B3416324CAE1C90038057A /* FieldsFormatter.swift in Sources */, + E72B37F324CB41D600F07DEF /* Lesson.swift in Sources */, E7A50EAE24B8D7D7007274E2 /* RegistrationController.swift in Sources */, E7A50EB024B8D7D7007274E2 /* RestorePasswordController.swift in Sources */, E7A50EAA24B8D7D7007274E2 /* UIViewController.swift in Sources */, @@ -530,7 +693,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 2DLN7CKF97; + DEVELOPMENT_TEAM = 64A5F5X892; INFOPLIST_FILE = "lesson31_Auth_Flow+AppCoordinator/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/Contents.json new file mode 100644 index 0000000..28d6397 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "EiffelTower.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "EiffelTower@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "EiffelTower@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/EiffelTower.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/EiffelTower.png new file mode 100644 index 0000000..3f7f274 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/EiffelTower.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/EiffelTower@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/EiffelTower@2x.png new file mode 100644 index 0000000..1bc5612 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/EiffelTower@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/EiffelTower@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/EiffelTower@3x.png new file mode 100644 index 0000000..9824aa2 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/EiffelTower.imageset/EiffelTower@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/Contents.json new file mode 100644 index 0000000..10ceb07 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "FoodAndWine.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "FoodAndWine@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "FoodAndWine@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/FoodAndWine.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/FoodAndWine.png new file mode 100644 index 0000000..d7a1ac7 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/FoodAndWine.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/FoodAndWine@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/FoodAndWine@2x.png new file mode 100644 index 0000000..2c4634b Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/FoodAndWine@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/FoodAndWine@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/FoodAndWine@3x.png new file mode 100644 index 0000000..19b935d Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/FoodAndWine.imageset/FoodAndWine@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Contents.json new file mode 100644 index 0000000..3575b4c --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "Marker.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Marker@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Marker@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Marker.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Marker.png new file mode 100644 index 0000000..09095b4 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Marker.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Marker@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Marker@2x.png new file mode 100644 index 0000000..5ec7945 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Marker@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Marker@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Marker@3x.png new file mode 100644 index 0000000..dee5e45 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/Marker.imageset/Marker@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/Contents.json new file mode 100644 index 0000000..38feb1f --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "VoiceRecognition.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "VoiceRecognition@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "VoiceRecognition@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/VoiceRecognition.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/VoiceRecognition.png new file mode 100644 index 0000000..9b5c52f Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/VoiceRecognition.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/VoiceRecognition@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/VoiceRecognition@2x.png new file mode 100644 index 0000000..d759f77 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/VoiceRecognition@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/VoiceRecognition@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/VoiceRecognition@3x.png new file mode 100644 index 0000000..6ed4d22 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/VoiceRecognition.imageset/VoiceRecognition@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/Contents.json new file mode 100644 index 0000000..45ac297 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "icons8Right100Px1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icons8Right100Px1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "icons8Right100Px1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/icons8Right100Px1.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/icons8Right100Px1.png new file mode 100644 index 0000000..3110120 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/icons8Right100Px1.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/icons8Right100Px1@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/icons8Right100Px1@2x.png new file mode 100644 index 0000000..a7aa203 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/icons8Right100Px1@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/icons8Right100Px1@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/icons8Right100Px1@3x.png new file mode 100644 index 0000000..f33f080 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/Icons/icons8Right100Px1.imageset/icons8Right100Px1@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/12.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/12.png new file mode 100644 index 0000000..eb76b5e Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/12.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/12@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/12@2x.png new file mode 100644 index 0000000..b2a0b07 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/12@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/12@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/12@3x.png new file mode 100644 index 0000000..37a6f29 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/12@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/Contents.json new file mode 100644 index 0000000..b8a30d5 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/1.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "12.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "12@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "12@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/2.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/2.png new file mode 100644 index 0000000..994d567 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/2.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/2@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/2@2x.png new file mode 100644 index 0000000..f2ff3a4 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/2@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/2@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/2@3x.png new file mode 100644 index 0000000..da45c29 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/2@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/Contents.json new file mode 100644 index 0000000..b7ad070 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/2.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "2@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "2@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/3.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/3.png new file mode 100644 index 0000000..e5ccab1 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/3.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/3@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/3@2x.png new file mode 100644 index 0000000..7103ebc Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/3@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/3@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/3@3x.png new file mode 100644 index 0000000..c91ca2f Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/3@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/Contents.json new file mode 100644 index 0000000..721c744 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/3.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "3.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "3@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "3@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/4.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/4.png new file mode 100644 index 0000000..533f931 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/4.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/4@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/4@2x.png new file mode 100644 index 0000000..2ecf6c7 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/4@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/4@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/4@3x.png new file mode 100644 index 0000000..1abcd7c Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/4@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/Contents.json new file mode 100644 index 0000000..dad02ed --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/4.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "4.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "4@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "4@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/Tutorial/TutorialScreens/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/Contents.json new file mode 100644 index 0000000..3d2118e --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "allLessonsIcon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "allLessonsIcon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "allLessonsIcon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/allLessonsIcon.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/allLessonsIcon.png new file mode 100644 index 0000000..1b4a906 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/allLessonsIcon.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/allLessonsIcon@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/allLessonsIcon@2x.png new file mode 100644 index 0000000..8f42a89 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/allLessonsIcon@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/allLessonsIcon@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/allLessonsIcon@3x.png new file mode 100644 index 0000000..d080891 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/allLessonsIcon.imageset/allLessonsIcon@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/Contents.json new file mode 100644 index 0000000..1c54843 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "kuponIcon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "kuponIcon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "kuponIcon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/kuponIcon.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/kuponIcon.png new file mode 100644 index 0000000..f13221f Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/kuponIcon.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/kuponIcon@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/kuponIcon@2x.png new file mode 100644 index 0000000..2f9e278 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/kuponIcon@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/kuponIcon@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/kuponIcon@3x.png new file mode 100644 index 0000000..4695ab6 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/kuponIcon.imageset/kuponIcon@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/Contents.json new file mode 100644 index 0000000..af1123f --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "logoutIcon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "logoutIcon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "logoutIcon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/logoutIcon.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/logoutIcon.png new file mode 100644 index 0000000..c79ae9b Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/logoutIcon.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/logoutIcon@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/logoutIcon@2x.png new file mode 100644 index 0000000..66ed7f1 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/logoutIcon@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/logoutIcon@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/logoutIcon@3x.png new file mode 100644 index 0000000..c540000 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/logoutIcon.imageset/logoutIcon@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/Contents.json new file mode 100644 index 0000000..ca3b36f --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "myLessons.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "myLessons@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "myLessons@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/myLessons.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/myLessons.png new file mode 100644 index 0000000..2af79d2 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/myLessons.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/myLessons@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/myLessons@2x.png new file mode 100644 index 0000000..f97b020 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/myLessons@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/myLessons@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/myLessons@3x.png new file mode 100644 index 0000000..d58fd1d Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/myLessons.imageset/myLessons@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/Contents.json new file mode 100644 index 0000000..a25316c --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "restoreIcon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "restoreIcon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "restoreIcon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/restoreIcon.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/restoreIcon.png new file mode 100644 index 0000000..5029313 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/restoreIcon.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/restoreIcon@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/restoreIcon@2x.png new file mode 100644 index 0000000..f362c80 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/restoreIcon@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/restoreIcon@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/restoreIcon@3x.png new file mode 100644 index 0000000..1ac0d9b Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/restoreIcon.imageset/restoreIcon@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/Contents.json new file mode 100644 index 0000000..20518c2 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "settingsIcon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "settingsIcon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "settingsIcon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/settingsIcon.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/settingsIcon.png new file mode 100644 index 0000000..bff292c Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/settingsIcon.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/settingsIcon@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/settingsIcon@2x.png new file mode 100644 index 0000000..e0e14f4 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/settingsIcon@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/settingsIcon@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/settingsIcon@3x.png new file mode 100644 index 0000000..a617950 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/settingsIcon.imageset/settingsIcon@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/Contents.json b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/Contents.json new file mode 100644 index 0000000..b9bb468 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "ups.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "ups@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "ups@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/ups.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/ups.png new file mode 100644 index 0000000..33767b0 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/ups.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/ups@2x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/ups@2x.png new file mode 100644 index 0000000..f6fbf40 Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/ups@2x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/ups@3x.png b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/ups@3x.png new file mode 100644 index 0000000..0d1c69b Binary files /dev/null and b/lesson31_Auth_Flow+AppCoordinator/Assets.xcassets/ups.imageset/ups@3x.png differ diff --git a/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppCoordinator.swift b/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppCoordinator.swift index 59b4b33..a99032c 100644 --- a/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppCoordinator.swift +++ b/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppCoordinator.swift @@ -9,17 +9,16 @@ import UIKit import Rswift -class AppCoordinator: CoordinatorProtocol { +class AppCoordinator: Coordinator { - let window: UIWindow? - let settings: AppSettings + private let settings: AppSettings - init(window: UIWindow?, settings: AppSettings) { - self.window = window + init(window: UIWindow, settings: AppSettings) { self.settings = settings + super.init(window: window) } - func start() { + override func startFlow() { if settings.isShowedTutorial { if settings.isUserLogged { startMainFlow() @@ -32,32 +31,38 @@ class AppCoordinator: CoordinatorProtocol { } private func startTutorialFlow() { - if let controller = R.storyboard.tutorial.tutorialController() { - controller.onAppStarted = { [weak self] _ in - self?.settings.isShowedTutorial = true - self?.start() - } - let navController = NavigationController.init(rootViewController: controller) - window?.rootViewController = navController + let tutorialCoordinator = TutorialCoordinator(window: window, settings: settings) + tutorialCoordinator.startFlow() + tutorialCoordinator.onTutorialIsFinish = { [weak self] coordinator in + self?.removeChildrenCoordinator(coordinator: coordinator) + self?.settings.isShowedTutorial = true + self?.startFlow() } + self.addChildrenCoordinator(coordinator: tutorialCoordinator) } private func startMainFlow() { - if let controller = R.storyboard.main.mainController() { - controller.onLogout = { [weak self] _ in - self?.settings.logoutUser() - self?.start() - } - let navController = NavigationController.init(rootViewController: controller) - window?.rootViewController = navController + let coordinator = MainCoordinator(window: window, appSettings: settings) + coordinator.onSuccessFlow = { [weak self] coordinator in + self?.removeChildrenCoordinator(coordinator: coordinator) + self?.settings.logoutUser() + self?.startFlow() } + + self.addChildrenCoordinator(coordinator: coordinator) + coordinator.startFlow() } private func startAuthFlow() { - let authFlowCoordinator = AuthFlowCoordinator(window: window, settings: settings) - authFlowCoordinator.start() - authFlowCoordinator.onAuthSuccess = { - self.start() + let coordinator = AuthFlowCoordinator(window: window, rootViewController: NavigationController()) + + coordinator.onSuccessFlow = { [weak self] coordinator, user in + self?.removeChildrenCoordinator(coordinator: coordinator) + self?.settings.loginUser(user) + self?.startMainFlow() } + + self.addChildrenCoordinator(coordinator: coordinator) + coordinator.startFlow() } } diff --git a/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppDelegate.swift b/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppDelegate.swift index 1268060..969742f 100644 --- a/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppDelegate.swift +++ b/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppDelegate.swift @@ -11,20 +11,21 @@ import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - private var appCoordinator: AppCoordinator? - var window: UIWindow? + var appCoordinator: AppCoordinator? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) + let window = UIWindow(frame: UIScreen.main.bounds) let settings = AppSettings() + let appCoordinator = AppCoordinator(window: window, + settings: settings) - appCoordinator = AppCoordinator(window: window, - settings: settings) - appCoordinator?.start() + self.window = window + self.appCoordinator = appCoordinator - window?.makeKeyAndVisible() + appCoordinator.startFlow() + window.makeKeyAndVisible() return true } diff --git a/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppSettings.swift b/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppSettings.swift index 471d9b3..bbc5cd8 100644 --- a/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppSettings.swift +++ b/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/AppSettings.swift @@ -25,6 +25,12 @@ class AppSettings { } } + var currentUser: User? { + get { + return user + } + } + var isShowedTutorial: Bool { get { return UserDefaults.standard.bool(forKey: Key.IsShowedTutorialKey) @@ -38,7 +44,6 @@ class AppSettings { return user != nil } - //TODO: login user with mock func loginUser(_ user: User) { self.user = user if let data = try? JSONEncoder().encode(user) { @@ -46,17 +51,12 @@ class AppSettings { } } - func registerUser(_ user: User) { - self.user = user - if let data = try? JSONEncoder().encode(user) { - UserDefaults.standard.set(data, forKey: Key.UserLoggedKey) - } - } - func logoutUser() { self.user = nil UserDefaults.standard.removeObject(forKey: Key.UserLoggedKey) } - + func updateUser() { + + } } diff --git a/lesson31_Auth_Flow+AppCoordinator/Core/Coordinator.swift b/lesson31_Auth_Flow+AppCoordinator/Core/Coordinator.swift new file mode 100644 index 0000000..075e06a --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Core/Coordinator.swift @@ -0,0 +1,49 @@ +// +// Coordinator.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class Coordinator: CoordinatorProtocol { + + var window: UIWindow + + private var childrenCoordinators: [Coordinator] = [] + + init(window: UIWindow) { + self.window = window + } + + deinit { + print("deinit \(self)") + } + + func startFlow() { + // + } + + func addChildrenCoordinator(coordinator: Coordinator?) { + if + let coordinator = coordinator, + childrenCoordinators.firstIndex(where: { (element) -> Bool in + return element === coordinator + }) == nil + { + childrenCoordinators.append(coordinator) + } + } + + func removeChildrenCoordinator(coordinator: Coordinator?) { + if let index = childrenCoordinators.firstIndex(where: { (element) -> Bool in + return element === coordinator + }) { + childrenCoordinators.remove(at: index) + } + } + + +} diff --git a/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/CoordinatorProtocol.swift b/lesson31_Auth_Flow+AppCoordinator/Core/CoordinatorProtocol.swift similarity index 62% rename from lesson31_Auth_Flow+AppCoordinator/BusinessLogic/CoordinatorProtocol.swift rename to lesson31_Auth_Flow+AppCoordinator/Core/CoordinatorProtocol.swift index 1fa5449..9c0d541 100644 --- a/lesson31_Auth_Flow+AppCoordinator/BusinessLogic/CoordinatorProtocol.swift +++ b/lesson31_Auth_Flow+AppCoordinator/Core/CoordinatorProtocol.swift @@ -6,6 +6,9 @@ // Copyright © 2020 Bosov. All rights reserved. // -protocol CoordinatorProtocol { - func start() +import UIKit + +protocol CoordinatorProtocol { + var window: UIWindow { get set } + func startFlow() } diff --git a/lesson31_Auth_Flow+AppCoordinator/Models/Lesson.swift b/lesson31_Auth_Flow+AppCoordinator/Models/Lesson.swift new file mode 100644 index 0000000..4510c3d --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Models/Lesson.swift @@ -0,0 +1,23 @@ +// +// Lesson.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 24.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import Foundation + +struct Lesson { + let title: String + + static func testData() -> [Lesson] { + return [ + Lesson(title: "1"), + Lesson(title: "2"), + Lesson(title: "3"), + Lesson(title: "4"), + Lesson(title: "5") + ] + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Models/SlideModel.swift b/lesson31_Auth_Flow+AppCoordinator/Models/SlideModel.swift new file mode 100644 index 0000000..b1bb7a5 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Models/SlideModel.swift @@ -0,0 +1,41 @@ +// +// SlideModel.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Олег Чудновский on 23.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import Foundation + +struct SlideModel { + private var title: String + private var image: String + private var icon: String + + //MARK: - Getters + func getTitle() -> String { + return title + } + + func getImage() -> String { + return image + } + + func getIcon() -> String { + return icon + } + + //MARK: - Create SlideModel + static func createSlides() -> [SlideModel] { + let slide1 = SlideModel(title: "Выбирете блюдо, продукт или французский специалитет, который Вас интересует", image: "1", icon: "FoodAndWine") + + let slide2 = SlideModel(title: "Найдите и посетите самые вкусные места с Фпвнцузскими специалистами вокруг Вас", image: "2", icon: "Marker") + + let slide3 = SlideModel(title: "Практикуй свой французский, учи слова и фразы, чтобы свободно изъясняться", image: "3", icon: "EiffelTower") + + let slide4: SlideModel = SlideModel(title: "Получай баллы за ответы на вопросы и комментарии. Баллы меня на призы.", image: "4", icon: "VoiceRecognition") + + return [slide1, slide2, slide3, slide4] + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/Tools/FieldsFormatter.swift b/lesson31_Auth_Flow+AppCoordinator/Tools/FieldsFormatter.swift new file mode 100644 index 0000000..074c2b8 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/Tools/FieldsFormatter.swift @@ -0,0 +1,62 @@ +// +// FieldsFormatter.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Roman Berezin on 24.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class FieldsFormatter { + + static func nameFormatter(_ field: UITextField) { + + if let value = field.text?.trimmingCharacters(in: .whitespacesAndNewlines), value.count != 0 { + + var count = 0 + var newValue = "" + for v in value { + if v == " " { + if count == 0 { + newValue.append(v) + } + count += 1 + } else { + newValue.append(v) + } + } + field.text = newValue.capitalized + } + } + + static func phoneFormatter (_ field: UITextField) { + +// let prefix = "+" +// if let value = field.text?.trimmingCharacters(in: .whitespacesAndNewlines), value.count != 0 { +// +// var count = 0 +// var number = "" +// var codeNumber = "" +// var countryNumber = "" + +// for v in value.reversed() { +// if count < 7 { +// number.insert(v, at: number.startIndex) +// } else if count == 7 { +// codeNumber.insert(")", at: codeNumber.startIndex) +// } else if count > 7 && count < 11{ +// codeNumber.insert(v, at: codeNumber.startIndex) +// } else if count == 11 { +// codeNumber.insert("(", at: codeNumber.startIndex) +// } else if count > 11 { +// countryNumber.insert(v, at: countryNumber.startIndex) +// } +// count += 1 +// } +// field.text = prefix + countryNumber + codeNumber + number +// } + } + +} + diff --git a/lesson31_Auth_Flow+AppCoordinator/Tools/FieldsValidator.swift b/lesson31_Auth_Flow+AppCoordinator/Tools/FieldsValidator.swift index 69c5ec5..cfb004e 100644 --- a/lesson31_Auth_Flow+AppCoordinator/Tools/FieldsValidator.swift +++ b/lesson31_Auth_Flow+AppCoordinator/Tools/FieldsValidator.swift @@ -7,55 +7,76 @@ // import Foundation +import UIKit final class FieldsValidator { - static func isNameValid(_ value: String) -> Bool { - do { - if try NSRegularExpression(pattern: "^[A-Za-z]+ [A-Za-z]", options: .caseInsensitive).firstMatch(in: value, options: [], range: NSRange(location: 0, length: value.count)) == nil { + static func notValidField(_ field: UITextField) { + field.layer.borderWidth = 0.8 + field.layer.borderColor = UIColor.red.cgColor + } + + static func isNameValid(_ field: UITextField) -> Bool{ + if let value = field.text, value.count != 0 { + do { + if try NSRegularExpression(pattern: "^[A-Za-z]+ [A-Za-z]", options: .caseInsensitive).firstMatch(in: value, options: [], range: NSRange(location: 0, length: value.count)) == nil { + notValidField(field) + return false + } + } catch { return false } - } catch { - return false } return true } - static func isEmailValid(_ value: String) -> Bool { - do { - if try NSRegularExpression(pattern: "^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}$", options: .caseInsensitive).firstMatch(in: value, options: [], range: NSRange(location: 0, length: value.count)) == nil { + static func isEmailValid(_ field: UITextField) -> Bool { + if let value = field.text, value.count != 0 { + do { + if try NSRegularExpression(pattern: "^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}$", options: .caseInsensitive).firstMatch(in: value, options: [], range: NSRange(location: 0, length: value.count)) == nil { + notValidField(field) + return false + } + } catch { return false } - } catch { - return false } return true } - static func isPhoneValid(_ value: String) -> Bool { -// do { -// if try NSRegularExpression(pattern: "^[0-9]{2,4}$", options: .caseInsensitive).firstMatch(in: value, options: [], range: NSRange(location: 0, length: value.count)) == nil { -// return false -// } -// } catch { -// return false -// } -// return true - let PHONE_REGEX = "^\\d{3}\\d{3}\\d{4}$" - let phoneTest = NSPredicate(format: "SELF MATCHES %@", PHONE_REGEX) - let result = phoneTest.evaluate(with: value) - return result - } - static func isPassValid(_ value: String) -> Bool { - if value.count < 8 { - return false + static func isPhoneValid(_ field: UITextField) -> Bool { + if let value = field.text, value.count != 0 { + do { + if try NSRegularExpression(pattern: "^[0-9]{10,13}$", options: .caseInsensitive).firstMatch(in: value, options: [], range: NSRange(location: 0, length: value.count)) == nil { + notValidField(field) + return false + } + } catch { + return false + } } return true } + + + static func isPassValid(_ field: UITextField) -> Bool { + if let value = field.text, value.count != 0 { + do { + if try NSRegularExpression(pattern: /*"^[A-Z0-9a-z._%+-].{8,}$"*/ "(?=.*[a-z])(?=.*[A-Z]).{8,}", options: .caseInsensitive).firstMatch(in: value, options: [], range: NSRange(location: 0, length: value.count)) == nil { + notValidField(field) + return false + } + } catch { + return false + } + } + return true + } - static func isPassConfirmed(_ passValue: String, _ confirmingPassValue: String) -> Bool { - if passValue != confirmingPassValue { + static func isPassConfirmed(_ passField: UITextField, _ confirmPassField: UITextField) -> Bool { + if let firstValue = passField.text, let secondValue = confirmPassField.text, firstValue != secondValue { + notValidField(confirmPassField) return false } return true diff --git a/lesson31_Auth_Flow+AppCoordinator/Tools/R.generated.swift b/lesson31_Auth_Flow+AppCoordinator/Tools/R.generated.swift index acb3f29..11957cd 100644 --- a/lesson31_Auth_Flow+AppCoordinator/Tools/R.generated.swift +++ b/lesson31_Auth_Flow+AppCoordinator/Tools/R.generated.swift @@ -91,60 +91,60 @@ struct R: Rswift.Validatable { #if os(iOS) || os(tvOS) /// This `R.storyboard` struct is generated, and contains static references to 7 storyboards. struct storyboard { + /// Storyboard `Auth`. + static let auth = _R.storyboard.auth() + /// Storyboard `Kupons`. + static let kupons = _R.storyboard.kupons() /// Storyboard `LaunchScreen`. static let launchScreen = _R.storyboard.launchScreen() - /// Storyboard `Login`. - static let login = _R.storyboard.login() - /// Storyboard `Main`. - static let main = _R.storyboard.main() - /// Storyboard `Registration`. - static let registration = _R.storyboard.registration() - /// Storyboard `RestorePassword`. - static let restorePassword = _R.storyboard.restorePassword() - /// Storyboard `Start`. - static let start = _R.storyboard.start() + /// Storyboard `Lessons`. + static let lessons = _R.storyboard.lessons() + /// Storyboard `MyLessons`. + static let myLessons = _R.storyboard.myLessons() + /// Storyboard `Settings`. + static let settings = _R.storyboard.settings() /// Storyboard `Tutorial`. static let tutorial = _R.storyboard.tutorial() #if os(iOS) || os(tvOS) - /// `UIStoryboard(name: "LaunchScreen", bundle: ...)` - static func launchScreen(_: Void = ()) -> UIKit.UIStoryboard { - return UIKit.UIStoryboard(resource: R.storyboard.launchScreen) + /// `UIStoryboard(name: "Auth", bundle: ...)` + static func auth(_: Void = ()) -> UIKit.UIStoryboard { + return UIKit.UIStoryboard(resource: R.storyboard.auth) } #endif #if os(iOS) || os(tvOS) - /// `UIStoryboard(name: "Login", bundle: ...)` - static func login(_: Void = ()) -> UIKit.UIStoryboard { - return UIKit.UIStoryboard(resource: R.storyboard.login) + /// `UIStoryboard(name: "Kupons", bundle: ...)` + static func kupons(_: Void = ()) -> UIKit.UIStoryboard { + return UIKit.UIStoryboard(resource: R.storyboard.kupons) } #endif #if os(iOS) || os(tvOS) - /// `UIStoryboard(name: "Main", bundle: ...)` - static func main(_: Void = ()) -> UIKit.UIStoryboard { - return UIKit.UIStoryboard(resource: R.storyboard.main) + /// `UIStoryboard(name: "LaunchScreen", bundle: ...)` + static func launchScreen(_: Void = ()) -> UIKit.UIStoryboard { + return UIKit.UIStoryboard(resource: R.storyboard.launchScreen) } #endif #if os(iOS) || os(tvOS) - /// `UIStoryboard(name: "Registration", bundle: ...)` - static func registration(_: Void = ()) -> UIKit.UIStoryboard { - return UIKit.UIStoryboard(resource: R.storyboard.registration) + /// `UIStoryboard(name: "Lessons", bundle: ...)` + static func lessons(_: Void = ()) -> UIKit.UIStoryboard { + return UIKit.UIStoryboard(resource: R.storyboard.lessons) } #endif #if os(iOS) || os(tvOS) - /// `UIStoryboard(name: "RestorePassword", bundle: ...)` - static func restorePassword(_: Void = ()) -> UIKit.UIStoryboard { - return UIKit.UIStoryboard(resource: R.storyboard.restorePassword) + /// `UIStoryboard(name: "MyLessons", bundle: ...)` + static func myLessons(_: Void = ()) -> UIKit.UIStoryboard { + return UIKit.UIStoryboard(resource: R.storyboard.myLessons) } #endif #if os(iOS) || os(tvOS) - /// `UIStoryboard(name: "Start", bundle: ...)` - static func start(_: Void = ()) -> UIKit.UIStoryboard { - return UIKit.UIStoryboard(resource: R.storyboard.start) + /// `UIStoryboard(name: "Settings", bundle: ...)` + static func settings(_: Void = ()) -> UIKit.UIStoryboard { + return UIKit.UIStoryboard(resource: R.storyboard.settings) } #endif @@ -159,10 +159,111 @@ struct R: Rswift.Validatable { } #endif - /// This `R.image` struct is generated, and contains static references to 1 images. + /// This `R.image` struct is generated, and contains static references to 13 images. struct image { + /// Image `EiffelTower`. + static let eiffelTower = Rswift.ImageResource(bundle: R.hostingBundle, name: "EiffelTower") + /// Image `FoodAndWine`. + static let foodAndWine = Rswift.ImageResource(bundle: R.hostingBundle, name: "FoodAndWine") + /// Image `Marker`. + static let marker = Rswift.ImageResource(bundle: R.hostingBundle, name: "Marker") + /// Image `VoiceRecognition`. + static let voiceRecognition = Rswift.ImageResource(bundle: R.hostingBundle, name: "VoiceRecognition") + /// Image `allLessonsIcon`. + static let allLessonsIcon = Rswift.ImageResource(bundle: R.hostingBundle, name: "allLessonsIcon") + /// Image `icons8Right100Px1`. + static let icons8Right100Px1 = Rswift.ImageResource(bundle: R.hostingBundle, name: "icons8Right100Px1") + /// Image `kuponIcon`. + static let kuponIcon = Rswift.ImageResource(bundle: R.hostingBundle, name: "kuponIcon") + /// Image `logoutIcon`. + static let logoutIcon = Rswift.ImageResource(bundle: R.hostingBundle, name: "logoutIcon") + /// Image `myLessons`. + static let myLessons = Rswift.ImageResource(bundle: R.hostingBundle, name: "myLessons") + /// Image `restoreIcon`. + static let restoreIcon = Rswift.ImageResource(bundle: R.hostingBundle, name: "restoreIcon") + /// Image `settingsIcon`. + static let settingsIcon = Rswift.ImageResource(bundle: R.hostingBundle, name: "settingsIcon") /// Image `splash`. static let splash = Rswift.ImageResource(bundle: R.hostingBundle, name: "splash") + /// Image `ups`. + static let ups = Rswift.ImageResource(bundle: R.hostingBundle, name: "ups") + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "EiffelTower", bundle: ..., traitCollection: ...)` + static func eiffelTower(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.eiffelTower, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "FoodAndWine", bundle: ..., traitCollection: ...)` + static func foodAndWine(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.foodAndWine, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "Marker", bundle: ..., traitCollection: ...)` + static func marker(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.marker, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "VoiceRecognition", bundle: ..., traitCollection: ...)` + static func voiceRecognition(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.voiceRecognition, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "allLessonsIcon", bundle: ..., traitCollection: ...)` + static func allLessonsIcon(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.allLessonsIcon, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "icons8Right100Px1", bundle: ..., traitCollection: ...)` + static func icons8Right100Px1(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.icons8Right100Px1, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "kuponIcon", bundle: ..., traitCollection: ...)` + static func kuponIcon(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.kuponIcon, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "logoutIcon", bundle: ..., traitCollection: ...)` + static func logoutIcon(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.logoutIcon, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "myLessons", bundle: ..., traitCollection: ...)` + static func myLessons(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.myLessons, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "restoreIcon", bundle: ..., traitCollection: ...)` + static func restoreIcon(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.restoreIcon, compatibleWith: traitCollection) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UIImage(named: "settingsIcon", bundle: ..., traitCollection: ...)` + static func settingsIcon(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.settingsIcon, compatibleWith: traitCollection) + } + #endif #if os(iOS) || os(tvOS) /// `UIImage(named: "splash", bundle: ..., traitCollection: ...)` @@ -171,6 +272,55 @@ struct R: Rswift.Validatable { } #endif + #if os(iOS) || os(tvOS) + /// `UIImage(named: "ups", bundle: ..., traitCollection: ...)` + static func ups(compatibleWith traitCollection: UIKit.UITraitCollection? = nil) -> UIKit.UIImage? { + return UIKit.UIImage(resource: R.image.ups, compatibleWith: traitCollection) + } + #endif + + fileprivate init() {} + } + + /// This `R.nib` struct is generated, and contains static references to 2 nibs. + struct nib { + /// Nib `Button`. + static let button = _R.nib._Button() + /// Nib `Slide`. + static let slide = _R.nib._Slide() + + #if os(iOS) || os(tvOS) + /// `UINib(name: "Button", in: bundle)` + @available(*, deprecated, message: "Use UINib(resource: R.nib.button) instead") + static func button(_: Void = ()) -> UIKit.UINib { + return UIKit.UINib(resource: R.nib.button) + } + #endif + + #if os(iOS) || os(tvOS) + /// `UINib(name: "Slide", in: bundle)` + @available(*, deprecated, message: "Use UINib(resource: R.nib.slide) instead") + static func slide(_: Void = ()) -> UIKit.UINib { + return UIKit.UINib(resource: R.nib.slide) + } + #endif + + static func button(owner ownerOrNil: AnyObject?, options optionsOrNil: [UINib.OptionsKey : Any]? = nil) -> UIKit.UIView? { + return R.nib.button.instantiate(withOwner: ownerOrNil, options: optionsOrNil)[0] as? UIKit.UIView + } + + static func slide(owner ownerOrNil: AnyObject?, options optionsOrNil: [UINib.OptionsKey : Any]? = nil) -> SlideView? { + return R.nib.slide.instantiate(withOwner: ownerOrNil, options: optionsOrNil)[0] as? SlideView + } + + fileprivate init() {} + } + + /// This `R.reuseIdentifier` struct is generated, and contains static references to 1 reuse identifiers. + struct reuseIdentifier { + /// Reuse identifier `lessonCell`. + static let lessonCell: Rswift.ReuseIdentifier = Rswift.ReuseIdentifier(identifier: "lessonCell") + fileprivate init() {} } @@ -189,31 +339,83 @@ struct R: Rswift.Validatable { struct _R: Rswift.Validatable { static func validate() throws { + #if os(iOS) || os(tvOS) + try nib.validate() + #endif #if os(iOS) || os(tvOS) try storyboard.validate() #endif } + #if os(iOS) || os(tvOS) + struct nib: Rswift.Validatable { + static func validate() throws { + try _Button.validate() + try _Slide.validate() + } + + struct _Button: Rswift.NibResourceType, Rswift.Validatable { + let bundle = R.hostingBundle + let name = "Button" + + func firstView(owner ownerOrNil: AnyObject?, options optionsOrNil: [UINib.OptionsKey : Any]? = nil) -> UIKit.UIView? { + return instantiate(withOwner: ownerOrNil, options: optionsOrNil)[0] as? UIKit.UIView + } + + func secondView(owner ownerOrNil: AnyObject?, options optionsOrNil: [UINib.OptionsKey : Any]? = nil) -> UIKit.UIView? { + return instantiate(withOwner: ownerOrNil, options: optionsOrNil)[1] as? UIKit.UIView + } + + static func validate() throws { + if UIKit.UIImage(named: "icons8Right100Px1", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: "[R.swift] Image named 'icons8Right100Px1' is used in nib 'Button', but couldn't be loaded.") } + if #available(iOS 11.0, tvOS 11.0, *) { + } + } + + fileprivate init() {} + } + + struct _Slide: Rswift.NibResourceType, Rswift.Validatable { + let bundle = R.hostingBundle + let name = "Slide" + + func firstView(owner ownerOrNil: AnyObject?, options optionsOrNil: [UINib.OptionsKey : Any]? = nil) -> SlideView? { + return instantiate(withOwner: ownerOrNil, options: optionsOrNil)[0] as? SlideView + } + + static func validate() throws { + if UIKit.UIImage(named: "FoodAndWine", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: "[R.swift] Image named 'FoodAndWine' is used in nib 'Slide', but couldn't be loaded.") } + if #available(iOS 11.0, tvOS 11.0, *) { + } + } + + fileprivate init() {} + } + + fileprivate init() {} + } + #endif + #if os(iOS) || os(tvOS) struct storyboard: Rswift.Validatable { static func validate() throws { #if os(iOS) || os(tvOS) - try launchScreen.validate() + try auth.validate() #endif #if os(iOS) || os(tvOS) - try login.validate() + try kupons.validate() #endif #if os(iOS) || os(tvOS) - try main.validate() + try launchScreen.validate() #endif #if os(iOS) || os(tvOS) - try registration.validate() + try lessons.validate() #endif #if os(iOS) || os(tvOS) - try restorePassword.validate() + try myLessons.validate() #endif #if os(iOS) || os(tvOS) - try start.validate() + try settings.validate() #endif #if os(iOS) || os(tvOS) try tutorial.validate() @@ -221,16 +423,33 @@ struct _R: Rswift.Validatable { } #if os(iOS) || os(tvOS) - struct launchScreen: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { - typealias InitialController = UIKit.UIViewController + struct auth: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { + typealias InitialController = NavigationController let bundle = R.hostingBundle - let name = "LaunchScreen" + let loginController = StoryboardViewControllerResource(identifier: "LoginController") + let name = "Auth" + let registrationController = StoryboardViewControllerResource(identifier: "RegistrationController") + let restorePasswordController = StoryboardViewControllerResource(identifier: "RestorePasswordController") + + func loginController(_: Void = ()) -> LoginController? { + return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: loginController) + } + + func registrationController(_: Void = ()) -> RegistrationController? { + return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: registrationController) + } + + func restorePasswordController(_: Void = ()) -> RestorePasswordController? { + return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: restorePasswordController) + } static func validate() throws { - if UIKit.UIImage(named: "splash", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: "[R.swift] Image named 'splash' is used in storyboard 'LaunchScreen', but couldn't be loaded.") } if #available(iOS 11.0, tvOS 11.0, *) { } + if _R.storyboard.auth().loginController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'loginController' could not be loaded from storyboard 'Auth' as 'LoginController'.") } + if _R.storyboard.auth().registrationController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'registrationController' could not be loaded from storyboard 'Auth' as 'RegistrationController'.") } + if _R.storyboard.auth().restorePasswordController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'restorePasswordController' could not be loaded from storyboard 'Auth' as 'RestorePasswordController'.") } } fileprivate init() {} @@ -238,21 +457,21 @@ struct _R: Rswift.Validatable { #endif #if os(iOS) || os(tvOS) - struct login: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { + struct kupons: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { typealias InitialController = NavigationController let bundle = R.hostingBundle - let loginController = StoryboardViewControllerResource(identifier: "LoginController") - let name = "Login" + let kuponsController = StoryboardViewControllerResource(identifier: "KuponsController") + let name = "Kupons" - func loginController(_: Void = ()) -> LoginController? { - return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: loginController) + func kuponsController(_: Void = ()) -> KuponsController? { + return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: kuponsController) } static func validate() throws { if #available(iOS 11.0, tvOS 11.0, *) { } - if _R.storyboard.login().loginController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'loginController' could not be loaded from storyboard 'Login' as 'LoginController'.") } + if _R.storyboard.kupons().kuponsController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'kuponsController' could not be loaded from storyboard 'Kupons' as 'KuponsController'.") } } fileprivate init() {} @@ -260,21 +479,16 @@ struct _R: Rswift.Validatable { #endif #if os(iOS) || os(tvOS) - struct main: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { - typealias InitialController = NavigationController + struct launchScreen: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { + typealias InitialController = UIKit.UIViewController let bundle = R.hostingBundle - let mainController = StoryboardViewControllerResource(identifier: "MainController") - let name = "Main" - - func mainController(_: Void = ()) -> MainController? { - return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: mainController) - } + let name = "LaunchScreen" static func validate() throws { + if UIKit.UIImage(named: "splash", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: "[R.swift] Image named 'splash' is used in storyboard 'LaunchScreen', but couldn't be loaded.") } if #available(iOS 11.0, tvOS 11.0, *) { } - if _R.storyboard.main().mainController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'mainController' could not be loaded from storyboard 'Main' as 'MainController'.") } } fileprivate init() {} @@ -282,21 +496,27 @@ struct _R: Rswift.Validatable { #endif #if os(iOS) || os(tvOS) - struct registration: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { + struct lessons: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { typealias InitialController = NavigationController let bundle = R.hostingBundle - let name = "Registration" - let registrationController = StoryboardViewControllerResource(identifier: "RegistrationController") + let lessonDetailedController = StoryboardViewControllerResource(identifier: "lessonDetailedController") + let lessonsController = StoryboardViewControllerResource(identifier: "LessonsController") + let name = "Lessons" - func registrationController(_: Void = ()) -> RegistrationController? { - return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: registrationController) + func lessonDetailedController(_: Void = ()) -> LessonDetailedController? { + return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: lessonDetailedController) + } + + func lessonsController(_: Void = ()) -> LessonsController? { + return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: lessonsController) } static func validate() throws { if #available(iOS 11.0, tvOS 11.0, *) { } - if _R.storyboard.registration().registrationController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'registrationController' could not be loaded from storyboard 'Registration' as 'RegistrationController'.") } + if _R.storyboard.lessons().lessonsController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'lessonsController' could not be loaded from storyboard 'Lessons' as 'LessonsController'.") } + if _R.storyboard.lessons().lessonDetailedController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'lessonDetailedController' could not be loaded from storyboard 'Lessons' as 'LessonDetailedController'.") } } fileprivate init() {} @@ -304,15 +524,21 @@ struct _R: Rswift.Validatable { #endif #if os(iOS) || os(tvOS) - struct restorePassword: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { + struct myLessons: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { typealias InitialController = NavigationController let bundle = R.hostingBundle - let name = "RestorePassword" + let myLessonsController = StoryboardViewControllerResource(identifier: "MyLessonsController") + let name = "MyLessons" + + func myLessonsController(_: Void = ()) -> MyLessonsController? { + return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: myLessonsController) + } static func validate() throws { if #available(iOS 11.0, tvOS 11.0, *) { } + if _R.storyboard.myLessons().myLessonsController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'myLessonsController' could not be loaded from storyboard 'MyLessons' as 'MyLessonsController'.") } } fileprivate init() {} @@ -320,16 +546,22 @@ struct _R: Rswift.Validatable { #endif #if os(iOS) || os(tvOS) - struct start: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { - typealias InitialController = StartController + struct settings: Rswift.StoryboardResourceWithInitialControllerType, Rswift.Validatable { + typealias InitialController = NavigationController let bundle = R.hostingBundle - let name = "Start" + let name = "Settings" + let settingsController = StoryboardViewControllerResource(identifier: "SettingsController") + + func settingsController(_: Void = ()) -> SettingsController? { + return UIKit.UIStoryboard(resource: self).instantiateViewController(withResource: settingsController) + } static func validate() throws { - if UIKit.UIImage(named: "splash", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: "[R.swift] Image named 'splash' is used in storyboard 'Start', but couldn't be loaded.") } + if UIKit.UIImage(named: "logoutIcon", in: R.hostingBundle, compatibleWith: nil) == nil { throw Rswift.ValidationError(description: "[R.swift] Image named 'logoutIcon' is used in storyboard 'Settings', but couldn't be loaded.") } if #available(iOS 11.0, tvOS 11.0, *) { } + if _R.storyboard.settings().settingsController() == nil { throw Rswift.ValidationError(description:"[R.swift] ViewController with identifier 'settingsController' could not be loaded from storyboard 'Settings' as 'SettingsController'.") } } fileprivate init() {} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Auth.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Auth.storyboard new file mode 100644 index 0000000..e303320 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Auth.storyboard @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/AuthButton.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/AuthButton.swift deleted file mode 100644 index a38308d..0000000 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/AuthButton.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// AuthButton.swift -// lesson31_Auth_Flow+AppCoordinator -// -// Created by Roman Berezin on 15.07.2020. -// Copyright © 2020 Bosov. All rights reserved. -// - -import UIKit - -class AuthButton: UIButton { - - required public init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - //self.layer.borderWidth = 1 - self.layer.cornerRadius = 11.3 - self.backgroundColor = UIColor(red: 24/255, green: 105/255, blue: 132/255, alpha: 1) - } -} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/AuthFlowCoordinator.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/AuthFlowCoordinator.swift index 6c59db3..dd53063 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/AuthFlowCoordinator.swift +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/AuthFlowCoordinator.swift @@ -9,51 +9,98 @@ import UIKit import Rswift -class AuthFlowCoordinator: AppCoordinator { +class AuthFlowCoordinator: Coordinator { - var onAuthSuccess: (()->())? + var onSuccessFlow: ((AuthFlowCoordinator?, User) -> ())? + var alertOkClicked: (()->())? + private let rootViewController: UINavigationController - override func start() { - startLogin() + init(window: UIWindow, rootViewController: UINavigationController) { + self.rootViewController = rootViewController + super.init(window: window) } - + + override func startFlow() { + startLogin() + } + private func startLogin() { - if let controller = R.storyboard.login.loginController() { - controller.onLoginSuccess = { user, _ in - self.settings.registerUser(user) - self.onAuthSuccess?() + if let controller = R.storyboard.auth.loginController() { + controller.onLoginSuccess = { [weak self] user, _ in + self?.onSuccessFlow?(self, user) } - controller.onLoginFailure = { _ in + controller.onLoginFailure = { [weak self] _ in let alert = UIAlertController(title: "Something wrong", message: "Check your e-mail or pass \n Sign in if you have no account", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil)) - controller.present(alert, animated: true, completion: nil) + self?.window.rootViewController?.present(alert, animated: true, completion: nil) + } + controller.onSignIn = { [weak self] in + self?.startSignIn() } - controller.onSignIn = { - self.startSignIn() + controller.onRestore = { [weak self] in + self?.startResetPass() } - - let navController = NavigationController.init(rootViewController: controller) - window?.rootViewController = navController } + rootViewController.viewControllers = [controller] + window.rootViewController = rootViewController + } } private func startSignIn() { - if let controller = R.storyboard.registration.registrationController() { - controller.onRegSuccess = { [weak self] user, _ in - self?.settings.registerUser(user) - self?.onAuthSuccess!() + if let controller = R.storyboard.auth.registrationController() { + controller.onRegSuccess = { [weak self] user in + self?.onSuccessFlow?(self, user) } - controller.onRegFailure = { _ in + controller.onRegFailure = { [weak self] in let alert = UIAlertController(title: "Something wrong", message: "Feel all fields correctly", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil)) - controller.present(alert, animated: true, completion: nil) + self?.window.rootViewController?.present(alert, animated: true, completion: nil) } - let navController = NavigationController.init(rootViewController: controller) - window?.rootViewController = navController + rootViewController.pushViewController(controller, animated: true) } } private func startResetPass() { - + + let controller = RestoreController() + rootViewController.pushViewController(controller, animated: true) + + controller.onProceedSuccess = { [weak controller, weak self] _ in + let code = String(UInt.random(in:1000...9999)) + let alert = UIAlertController(title: "Continue with Code from this SMS", message:"Code: \(code)", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { _ in + controller?.code = code + controller?.userConfirmedAlert = true + })) + self?.window.rootViewController?.present(alert, animated: true, completion: nil) + } + + controller.onProceedFailure = { [weak self] _ in + let alert = UIAlertController(title: "Phone number is wrong", message: "Please provide correct number", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil)) + self?.window.rootViewController?.present(alert, animated: true, completion: nil) + } + + + controller.onConfirmFailure = { [weak self] in + let alert = UIAlertController(title: "The Code is wrong", message: "Please enter correct Code", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil)) + self?.window.rootViewController?.present(alert, animated: true, completion: nil) + } + + controller.onFinishSuccess = { [weak self] _, user in + //self?.onSuccessFlow?(self, user) + let alert = UIAlertController(title: "Greate", message: "Your password was successfully restored", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: {_ in + self?.startLogin() + })) + self?.window.rootViewController?.present(alert, animated: true, completion: nil) + } + + controller.onFinishFailure = { [weak self] in + let alert = UIAlertController(title: "Password mismatch", message: "Feel all fields correctly", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil)) + self?.window.rootViewController?.present(alert, animated: true, completion: nil) + } } } diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/LoginController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/LoginController.swift similarity index 73% rename from lesson31_Auth_Flow+AppCoordinator/UI/Auth/LoginController.swift rename to lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/LoginController.swift index 8f8af0b..79224ef 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/LoginController.swift +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/LoginController.swift @@ -15,80 +15,74 @@ class LoginController: BaseViewController, UITextFieldDelegate { @IBOutlet private var confirmButton: UIButton? @IBOutlet private var regButton: UIButton? - var onLoginSuccess: ((User, LoginController)->())? - //var onLoginSuccess: ((LoginController)->())? + var onLoginSuccess: ((User, LoginController)->())? var onLoginFailure: ((LoginController)->())? var onSignIn: (()->())? + var onRestore: (()->())? override func viewDidLoad() { super.viewDidLoad() - - } - - override func touchesBegan(_ touches: Set, with event: UIEvent?) { - view.endEditing(true) } - - override func setup() { - super.setup() + + override func setupView() { + super.setupView() title = "Login" emailField?.delegate = self - emailField?.placeholder = "E-mail" + emailField?.placeholder = "E-mail: user@mydomen.com" + emailField?.keyboardType = .emailAddress emailField?.returnKeyType = .next emailField?.enablesReturnKeyAutomatically = true emailField?.autocorrectionType = .no + emailField?.backgroundColor = .white + emailField?.borderStyle = .roundedRect emailField?.textContentType = .emailAddress emailField?.clearButtonMode = .whileEditing passField?.delegate = self - passField?.placeholder = "Password" + passField?.placeholder = "New Password: min 8 characters" passField?.returnKeyType = .done - passField?.enablesReturnKeyAutomatically = true //?? + passField?.enablesReturnKeyAutomatically = true passField?.autocorrectionType = .no + passField?.backgroundColor = .white + passField?.borderStyle = .roundedRect passField?.textContentType = .password passField?.clearButtonMode = .whileEditing passField?.isSecureTextEntry = true confirmButton?.isEnabled = false - confirmButton?.backgroundColor = UIColor(red: 24/255, green: 105/255, blue: 132/255, alpha: 0.3) - } - - @IBAction private func loginButtonClicked() { - - guard let emailF = emailField, let passF = passField else { - return - } - - if FieldsValidator.isEmailValid(emailF.text!), FieldsValidator.isPassValid(passF.text!) { - //IF USER EXIST IN BASE return his settings - let user = User(name: nil, email: emailF.text!, phone: nil, password: passF.text!, photo: nil) - onLoginSuccess?(user, self) - //TODO: MOCK.DB - //onLoginSuccess?(self) - } else { - onLoginFailure?(self) - } - - - } //MARK: - Actions @IBAction private func editingChanged(_ textField: UITextField) { - + textField.layer.borderWidth = 0 guard let emailF = emailField, let passF = passField else { return } if emailF.text!.count > 0 && passF.text!.count > 0{ confirmButton?.isEnabled = true - confirmButton?.backgroundColor = UIColor(red: 24/255, green: 105/255, blue: 132/255, alpha: 1) } else { confirmButton?.isEnabled = false - confirmButton?.backgroundColor = UIColor(red: 24/255, green: 105/255, blue: 132/255, alpha: 0.3) + } + } + + @IBAction private func loginButtonClicked() { + guard let emailF = emailField, let passF = passField else { + return + } + + if + FieldsValidator.isEmailValid(emailF), + FieldsValidator.isPassValid(passF) { + //IF USER EXIST IN BASE return his settings + let user = User(name: nil, email: emailF.text!, phone: nil, password: passF.text!, photo: nil) + onLoginSuccess?(user, self) + //TODO: MOCK.DB + } else { + onLoginFailure?(self) } } @@ -96,10 +90,16 @@ class LoginController: BaseViewController, UITextFieldDelegate { onSignIn?() } + @IBAction private func restoreButtonClicked() { + onRestore?() + } + //MARK: - UITextFieldDelegate + func textFieldDidEndEditing(_ textField: UITextField) { + + } func textFieldShouldReturn(_ textField: UITextField) -> Bool { - if textField == emailField { passField?.becomeFirstResponder() } else { @@ -108,5 +108,4 @@ class LoginController: BaseViewController, UITextFieldDelegate { } return true } - } diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/RegistrationController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/RegistrationController.swift similarity index 57% rename from lesson31_Auth_Flow+AppCoordinator/UI/Auth/RegistrationController.swift rename to lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/RegistrationController.swift index b4cd4b4..c612e59 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/RegistrationController.swift +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/RegistrationController.swift @@ -16,26 +16,16 @@ class RegistrationController: BaseViewController, UITextFieldDelegate { @IBOutlet private var passField: UITextField? @IBOutlet private var confirmPassField: UITextField? @IBOutlet private var confirmButton: UIButton? - @IBOutlet private var BottomConstraint: NSLayoutConstraint! + var onRegSuccess: ((User)->())? + var onRegFailure: (()->())? - var onRegSuccess: ((User, RegistrationController)->())? - var onRegFailure: ((RegistrationController)->())? - - override func viewDidLoad() { - super.viewDidLoad() - } - - override func touchesBegan(_ touches: Set, with event: UIEvent?) { - view.endEditing(true) - } - - override func setup() { - super.setup() + override func setupView() { + super.setupView() title = "Sign in" nameField?.delegate = self - nameField?.placeholder = "Name" + nameField?.placeholder = "Name: First Last" nameField?.returnKeyType = .next nameField?.enablesReturnKeyAutomatically = true nameField?.autocorrectionType = .no @@ -43,7 +33,7 @@ class RegistrationController: BaseViewController, UITextFieldDelegate { nameField?.clearButtonMode = .whileEditing emailField?.delegate = self - emailField?.placeholder = "E-mail" + emailField?.placeholder = "E-mail: user@mydomen.com" emailField?.returnKeyType = .next emailField?.enablesReturnKeyAutomatically = true emailField?.autocorrectionType = .no @@ -51,7 +41,7 @@ class RegistrationController: BaseViewController, UITextFieldDelegate { emailField?.clearButtonMode = .whileEditing phoneField?.delegate = self - phoneField?.placeholder = "Phone" + phoneField?.placeholder = "Phone: 380991234567" phoneField?.returnKeyType = .next phoneField?.enablesReturnKeyAutomatically = true phoneField?.autocorrectionType = .no @@ -59,63 +49,68 @@ class RegistrationController: BaseViewController, UITextFieldDelegate { phoneField?.clearButtonMode = .whileEditing passField?.delegate = self - passField?.placeholder = "Password" + passField?.placeholder = "Password: min 8 charachters" passField?.returnKeyType = .next passField?.enablesReturnKeyAutomatically = true //?? passField?.autocorrectionType = .no passField?.textContentType = .password passField?.clearButtonMode = .whileEditing - passField?.isSecureTextEntry = true + passField?.isSecureTextEntry = false//true confirmPassField?.delegate = self - confirmPassField?.placeholder = "Password" + confirmPassField?.placeholder = "Confirm password" confirmPassField?.returnKeyType = .done confirmPassField?.enablesReturnKeyAutomatically = true //?? confirmPassField?.autocorrectionType = .no confirmPassField?.textContentType = .password confirmPassField?.clearButtonMode = .whileEditing - confirmPassField?.isSecureTextEntry = true + confirmPassField?.isSecureTextEntry = false//true confirmButton?.isEnabled = false - confirmButton?.backgroundColor = UIColor(red: 24/255, green: 105/255, blue: 132/255, alpha: 0.3) - - let notificationCenter = NotificationCenter.default - notificationCenter.addObserver( - forName: UIResponder.keyboardWillChangeFrameNotification, - object: nil, queue: .main) { (notification) in - self.handleKeyboard(notification: notification) - } - notificationCenter.addObserver( - forName: UIResponder.keyboardWillHideNotification, - object: nil, queue: .main) { (notification) in - self.handleKeyboard(notification: notification) - } + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) + } + + //MARK: Override Deinit + + deinit { + NotificationCenter.default.removeObserver(self) } //MARK: - Actions + + @IBAction private func touchesBegun() { + view.endEditing(true) + } + @IBAction private func confirmButtonClicked() { - if let nameF = nameField, let emailF = emailField, let phoneF = phoneField, let passF = passField, - let confirmPassF = confirmPassField, - FieldsValidator.isNameValid(nameF.text!), - FieldsValidator.isEmailValid(emailF.text!), - FieldsValidator.isPhoneValid(phoneF.text!), - FieldsValidator.isPassValid(passF.text!), - FieldsValidator.isPassConfirmed(passF.text!, confirmPassF.text!){ - let user = User(name: nameF.text!, email: emailF.text!, phone: phoneF.text!, password: confirmPassF.text!, photo: nil) - onRegSuccess?(user, self) + let confirmPassF = confirmPassField + { + let isNameValid = FieldsValidator.isNameValid(nameF) + let isEmailValid = FieldsValidator.isEmailValid(emailF) + let isPhoneValid = FieldsValidator.isPhoneValid(phoneF) + let isPassValid = FieldsValidator.isPassValid(passF) + let isPassConfirmed = FieldsValidator.isPassConfirmed(passF, confirmPassF) + + if isNameValid && isEmailValid && isPhoneValid && isPassValid && isPassConfirmed { + let user = User(name: nameF.text!, email: emailF.text!, phone: phoneF.text!, password: confirmPassF.text!, photo: nil) + onRegSuccess?(user) + } else { + onRegFailure?() + } } else { - onRegFailure?(self) + onRegFailure?() } } @IBAction private func editingChanged(_ textField: UITextField) { - + textField.layer.borderWidth = 0 guard let nameF = nameField, let emailF = emailField, let phoneF = phoneField, @@ -126,42 +121,39 @@ class RegistrationController: BaseViewController, UITextFieldDelegate { if nameF.text!.count > 0 && emailF.text!.count > 0 && phoneF.text!.count > 0 && passF.text!.count > 0 && confirmPassF.text!.count > 0 { confirmButton?.isEnabled = true - confirmButton?.backgroundColor = UIColor(red: 24/255, green: 105/255, blue: 132/255, alpha: 1) } else { confirmButton?.isEnabled = false - confirmButton?.backgroundColor = UIColor(red: 24/255, green: 105/255, blue: 132/255, alpha: 0.3) } } //MARK: - Private Methods - func handleKeyboard(notification: Notification) { - // 1 - guard notification.name == UIResponder.keyboardWillChangeFrameNotification else { - BottomConstraint.constant = 0 - view.layoutIfNeeded() - return - } - - guard - let info = notification.userInfo, - let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue - else { - return - } - - // 2 - let keyboardHeight = keyboardFrame.cgRectValue.size.height - UIView.animate(withDuration: 0.1, animations: { () -> Void in - self.BottomConstraint.constant = keyboardHeight - self.view.layoutIfNeeded() - }) + @objc func keyboardWillShow(notification: NSNotification) { + if self.view.frame.origin.y == 0 { + self.view.frame.origin.y -= 80 + } + } + + @objc func keyboardWillHide(notification: NSNotification) { + if self.view.frame.origin.y != 0 { + self.view.frame.origin.y = 0 + } } //MARK: - UITextFieldDelegate + func textFieldDidEndEditing(_ textField: UITextField) { + switch textField { + case nameField: + FieldsFormatter.nameFormatter(textField) + case phoneField: + FieldsFormatter.phoneFormatter(textField) + default: + break + } + } + func textFieldShouldReturn(_ textField: UITextField) -> Bool { - switch textField { case nameField: emailField?.becomeFirstResponder() @@ -177,4 +169,5 @@ class RegistrationController: BaseViewController, UITextFieldDelegate { } return true } + } diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/RestoreController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/RestoreController.swift new file mode 100644 index 0000000..1c44028 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/RestoreController.swift @@ -0,0 +1,295 @@ +// +// File.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Roman Berezin on 22.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit +import SnapKit + +class RestoreController: BaseViewController, UITextFieldDelegate { + + private var scrollView = UIScrollView() + private var headerLabel = UILabel() + private var phoneField = UITextField() + private var smsField = UITextField() + private var passField = UITextField() + private var confirmPassField = UITextField() + private var proceedButton = AuthButton(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width - 160, height: 30)) + private var confirmButton = AuthButton(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width - 160, height: 30)) + private var finishButton = AuthButton(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width - 160, height: 30)) + + var userConfirmedAlert: Bool = false { + didSet { + setupSmsLayout() + } + } + var code: String = "" + + var onProceedSuccess: ((RestoreController)->())? + var onProceedFailure: ((RestoreController)->())? + var onConfirmSuccess: ((RestoreController)->())? + var onConfirmFailure: (()->())? + var onFinishSuccess: ((RestoreController, User)->())? + var onFinishFailure: (()->())? + + override func setupView() { + super.setupView() + setupPhoneLayout() + } + + private func setupPhoneLayout() { + + proceedButton.setTitle("Proceed", for: .normal) + proceedButton.setTitleColor(.black, for: .normal) + proceedButton.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .regular) + proceedButton.isEnabled = false + proceedButton.addTarget(self, action: #selector(onProceedButtonClicked), for: .touchUpInside) + + headerLabel.text = "Please provide your phone number to restore password" + headerLabel.textAlignment = .center + headerLabel.numberOfLines = 2 + + phoneField.delegate = self + phoneField.placeholder = "Phone: 380991234567" + phoneField.keyboardType = .numberPad + phoneField.returnKeyType = .send + phoneField.enablesReturnKeyAutomatically = true + phoneField.autocorrectionType = .no + phoneField.backgroundColor = .white + phoneField.borderStyle = .roundedRect + phoneField.textContentType = .telephoneNumber + phoneField.clearButtonMode = .whileEditing + phoneField.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged) + + view.addSubview(scrollView) + scrollView.addSubview(headerLabel) + scrollView.addSubview(phoneField) + scrollView.addSubview(proceedButton) + + scrollView.snp.makeConstraints { maker in + maker.edges.equalToSuperview() + } + + headerLabel.snp.makeConstraints { maker in + maker.top.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.centerX.equalToSuperview() + } + + phoneField.snp.makeConstraints { maker in + maker.top.equalTo(headerLabel.snp.bottom).offset(50) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(40) + } + + proceedButton.snp.makeConstraints { maker in + maker.top.equalTo(phoneField.snp.bottom).offset(20) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(80) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(80) + maker.bottom.greaterThanOrEqualToSuperview() + } + } + + private func setupSmsLayout() { + + for view in scrollView.subviews { + view.removeFromSuperview() + } + + confirmButton.setTitle("Confirm", for: .normal) + confirmButton.setTitleColor(.black, for: .normal) + confirmButton.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .regular) + confirmButton.isEnabled = false + confirmButton.addTarget(self, action: #selector(onConfirmButtonClicked), for: .touchUpInside) + + headerLabel.text = "Please enter the Code\n \(code)" + headerLabel.textAlignment = .center + headerLabel.numberOfLines = 2 + + smsField.delegate = self + smsField.placeholder = "Code" + smsField.keyboardType = .numberPad + smsField.returnKeyType = .send + smsField.enablesReturnKeyAutomatically = true + smsField.autocorrectionType = .no + smsField.backgroundColor = .white + smsField.borderStyle = .roundedRect + smsField.textContentType = .oneTimeCode + smsField.clearButtonMode = .whileEditing + smsField.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged) + + scrollView.addSubview(headerLabel) + scrollView.addSubview(smsField) + scrollView.addSubview(confirmButton) + + scrollView.snp.makeConstraints { maker in + maker.edges.equalToSuperview() + } + + headerLabel.snp.makeConstraints { maker in + maker.top.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.centerX.equalToSuperview() + } + + smsField.snp.makeConstraints { maker in + maker.top.equalTo(headerLabel.snp.bottom).offset(50) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(40) + } + + confirmButton.snp.makeConstraints { maker in + maker.top.equalTo(smsField.snp.bottom).offset(20) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(80) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(80) + maker.bottom.greaterThanOrEqualToSuperview() + + } + } + + private func setupFinishLayout() { + + for view in scrollView.subviews { + view.removeFromSuperview() + } + + finishButton.setTitle("Finish", for: .normal) + finishButton.setTitleColor(.black, for: .normal) + finishButton.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .regular) + finishButton.isEnabled = false + finishButton.addTarget(self, action: #selector(onFinishButtonClicked), for: .touchUpInside) + + headerLabel.text = "Please enter new Password\n" + headerLabel.textAlignment = .center + headerLabel.numberOfLines = 2 + + passField.delegate = self + passField.placeholder = "New Password: min 8 characters" + passField.returnKeyType = .next + passField.enablesReturnKeyAutomatically = true + passField.autocorrectionType = .no + passField.backgroundColor = .white + passField.borderStyle = .roundedRect + passField.textContentType = .password + passField.clearButtonMode = .whileEditing + passField.isSecureTextEntry = true + passField.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged) + + confirmPassField.delegate = self + confirmPassField.placeholder = "Confirm Password" + confirmPassField.returnKeyType = .done + confirmPassField.enablesReturnKeyAutomatically = true + confirmPassField.autocorrectionType = .no + confirmPassField.backgroundColor = .white + confirmPassField.borderStyle = .roundedRect + confirmPassField.textContentType = .password + confirmPassField.clearButtonMode = .whileEditing + confirmPassField.isSecureTextEntry = true + confirmPassField.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged) + + scrollView.addSubview(headerLabel) + scrollView.addSubview(passField) + scrollView.addSubview(confirmPassField) + scrollView.addSubview(finishButton) + + scrollView.snp.makeConstraints { maker in + maker.edges.equalToSuperview() + } + + headerLabel.snp.makeConstraints { maker in + maker.top.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.centerX.equalToSuperview() + } + + passField.snp.makeConstraints { maker in + maker.top.equalTo(headerLabel.snp.bottom).offset(50) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(40) + } + + confirmPassField.snp.makeConstraints { maker in + maker.top.equalTo(passField.snp.bottom).offset(40) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(40) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(40) + } + + finishButton.snp.makeConstraints { maker in + maker.top.equalTo(confirmPassField.snp.bottom).offset(20) + maker.left.equalTo(view.safeAreaLayoutGuide).inset(80) + maker.right.equalTo(view.safeAreaLayoutGuide).inset(80) + maker.bottom.greaterThanOrEqualToSuperview() + + } + } + + //MARK: - Private Functions + + @objc private func editingChanged(_ textField: UITextField) { + textField.layer.borderWidth = 0 + if textField == phoneField && textField.text?.count != 0 { + proceedButton.isEnabled = true + } else if textField == smsField && smsField.text?.count != 0 { + confirmButton.isEnabled = true + } else if passField.text?.count != 0 && confirmPassField.text?.count != 0{ + finishButton.isEnabled = true + } + } + + @objc private func onProceedButtonClicked() { + if FieldsValidator.isPhoneValid(phoneField) { + onProceedSuccess?(self) + //TODO: MOCK.DB.request + } else { + onProceedFailure?(self) + } + + } + + @objc private func onConfirmButtonClicked() { + print(code) + if smsField.text == code { + onConfirmSuccess?(self) + setupFinishLayout() + } else { + onConfirmFailure?() + } + } + + @objc private func onFinishButtonClicked() { + if + FieldsValidator.isPassValid(passField), + FieldsValidator.isPassConfirmed(passField, confirmPassField) { + let user = User(name: "Test", email: "TEST@TEST.TEST", phone: nil, password: phoneField.text!, photo: nil) + onFinishSuccess?(self, user) + //TODO: MOCK.DB.UPDATE + } else { + onFinishFailure?() + } + } + + //MARK: - UITextFieldDelegate + func textFieldDidEndEditing(_ textField: UITextField) { + + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + if textField == phoneField { + onProceedButtonClicked() + } else if textField == smsField { + onConfirmButtonClicked() + } else if textField == passField { + confirmPassField.becomeFirstResponder() + } else { + confirmPassField.resignFirstResponder() + onFinishButtonClicked() + } + return true + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/RestorePasswordController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/RestorePasswordController.swift similarity index 100% rename from lesson31_Auth_Flow+AppCoordinator/UI/Auth/RestorePasswordController.swift rename to lesson31_Auth_Flow+AppCoordinator/UI/Auth/Controllers/RestorePasswordController.swift diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Login.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Login.storyboard deleted file mode 100644 index 5308cdc..0000000 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Login.storyboard +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Registration.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Registration.storyboard deleted file mode 100644 index e9f1bb1..0000000 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Registration.storyboard +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Views/AuthButton.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Views/AuthButton.swift new file mode 100644 index 0000000..fdb0885 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Auth/Views/AuthButton.swift @@ -0,0 +1,45 @@ +// +// AuthButton.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Roman Berezin on 15.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class AuthButton: UIButton { + + override init(frame: CGRect) { + super.init(frame: frame) + setupButton() + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setupButton() + } + + private func setupButton() { + //self.layer.borderWidth = 1 + self.layer.cornerRadius = 11.3 + self.backgroundColor = UIColor(red: 24/255, green: 105/255, blue: 132/255, alpha: 1) + + } + + override var isHighlighted: Bool { + didSet { + self.backgroundColor = self.backgroundColor?.withAlphaComponent(isHighlighted ? 0.5 : 1) + self.setTitleColor(titleColor(for: .normal)?.withAlphaComponent(isHighlighted ? 0.7 : 1), + for: .normal) + } + } + + override var isEnabled: Bool { + didSet { + self.backgroundColor = self.backgroundColor?.withAlphaComponent(isEnabled ? 1 : 0.3) + self.setTitleColor(titleColor(for: .normal)?.withAlphaComponent(isEnabled ? 1 : 0.6), + for: .normal) + } + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Base/BaseViewController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Base/BaseViewController.swift index ef0b017..cf06ce7 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Base/BaseViewController.swift +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Base/BaseViewController.swift @@ -10,13 +10,23 @@ import UIKit class BaseViewController: UIViewController { + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + setupController() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupController() + } + deinit { print("deinit \(self.className)") } override func viewDidLoad() { super.viewDidLoad() - setup() + setupView() } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { @@ -27,8 +37,15 @@ class BaseViewController: UIViewController { return .default } - func setup() { + func setupController() { + + } + + func setupView() { self.view.backgroundColor = UIColor(red: 53/255, green: 132/255, blue: 159/255, alpha: 1) } - + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + view.endEditing(true) + } } diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Base/NavigationController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Base/NavigationController.swift index 31e7f86..1f49fb0 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Base/NavigationController.swift +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Base/NavigationController.swift @@ -21,4 +21,8 @@ class NavigationController: UINavigationController { override var preferredStatusBarStyle: UIStatusBarStyle { return topViewController?.preferredStatusBarStyle ?? .lightContent } + + override var prefersStatusBarHidden: Bool { + return topViewController?.prefersStatusBarHidden ?? false + } } diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/RestorePassword.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Kupons/Kupons.storyboard similarity index 66% rename from lesson31_Auth_Flow+AppCoordinator/UI/Auth/RestorePassword.storyboard rename to lesson31_Auth_Flow+AppCoordinator/UI/Main/Kupons/Kupons.storyboard index a00a791..072495a 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Auth/RestorePassword.storyboard +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Kupons/Kupons.storyboard @@ -1,5 +1,5 @@ - + @@ -8,39 +8,39 @@ - - + + - - + + - + - + - + - + - + - + - + - + - + - + diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Kupons/KuponsController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Kupons/KuponsController.swift new file mode 100644 index 0000000..7dec149 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Kupons/KuponsController.swift @@ -0,0 +1,17 @@ +// +// KuponsController.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class KuponsController: BaseViewController { + + override func setupController() { + self.title = "Kupons" + self.tabBarItem = UITabBarItem(title: "Kupons", image: R.image.kuponIcon(), tag: 0) + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Kupons/KuponsCoordinator.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Kupons/KuponsCoordinator.swift new file mode 100644 index 0000000..cd3ce2a --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Kupons/KuponsCoordinator.swift @@ -0,0 +1,20 @@ +// +// KuponsCoordinator.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class KuponsCoordinator: Coordinator { + + let rootController = NavigationController() + + override func startFlow() { + if let controller = R.storyboard.kupons.kuponsController() { + rootController.viewControllers = [controller] + } + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/Cells/LessonCell.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/Cells/LessonCell.swift new file mode 100644 index 0000000..714107b --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/Cells/LessonCell.swift @@ -0,0 +1,17 @@ +// +// LessonCell.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 24.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class LessonCell: UITableViewCell { + var model: Lesson? { + didSet { + self.textLabel?.text = model?.title + } + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/LessonDetailedController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/LessonDetailedController.swift new file mode 100644 index 0000000..40eb6ed --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/LessonDetailedController.swift @@ -0,0 +1,20 @@ +// +// LessonDetailedController.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 24.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class LessonDetailedController: BaseViewController { + + var lesson: Lesson? + + override func viewDidLoad() { + super.viewDidLoad() + title = lesson?.title + } + +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/Lessons.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/Lessons.storyboard new file mode 100644 index 0000000..95e7140 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/Lessons.storyboard @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/LessonsController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/LessonsController.swift new file mode 100644 index 0000000..243ee07 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/LessonsController.swift @@ -0,0 +1,45 @@ +// +// LessonsController.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class LessonsController: BaseViewController { + + var onSelectedLesson: ((Lesson)->())? + + @IBOutlet private var tableView: UITableView? + private let dataSource: [Lesson] = Lesson.testData() + + override func setupController() { + self.title = "All lessons" + self.tabBarItem = UITabBarItem(title: "Lessons", + image: R.image.allLessonsIcon(), + tag: 0) + } +} + +extension LessonsController: UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return dataSource.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.lessonCell, for: indexPath)! + + cell.model = dataSource[indexPath.row] + + return cell + } +} + +extension LessonsController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + onSelectedLesson?(dataSource[indexPath.row]) + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/LessonsCoordinator.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/LessonsCoordinator.swift new file mode 100644 index 0000000..6a21b6a --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Lessons/LessonsCoordinator.swift @@ -0,0 +1,30 @@ +// +// LessonsCoordinator.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class LessonsCoordinator: Coordinator { + + let rootController = NavigationController() + + override func startFlow() { + if let controller = R.storyboard.lessons.lessonsController() { + controller.onSelectedLesson = { [weak self] lesson in + self?.openLessonDetailed(lesson) + } + rootController.viewControllers = [controller] + } + } + + private func openLessonDetailed(_ lesson: Lesson) { + if let controller = R.storyboard.lessons.lessonDetailedController() { + controller.lesson = lesson + rootController.pushViewController(controller, animated: true) + } + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/MainController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MainController.swift index 3a60186..38f844f 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Main/MainController.swift +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MainController.swift @@ -8,25 +8,22 @@ import UIKit -class MainController: BaseViewController { +class MainController: UITabBarController { - var onLogout: ((MainController)->())? + deinit { + print("deinit \(self.className)") + } override func viewDidLoad() { super.viewDidLoad() - title = "Main" + self.tabBar.tintColor = UIColor(red: 53/255, green: 132/255, blue: 159/255, alpha: 1) + } + + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + return .portrait } - @IBAction private func logoutButtonClicked() { - - let alert = UIAlertController(title: "Вы точно хотите выйти?", message: nil, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "Да", style: .destructive, handler: { [weak self] _ in - if let strongSelf = self { - self?.onLogout?(strongSelf) - } - })) - alert.addAction(UIAlertAction(title: "Отмена", style: .cancel, handler: nil)) - - self.present(alert, animated: true, completion: nil) + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.selectedViewController?.preferredStatusBarStyle ?? .lightContent } } diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/MainCoordinator.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MainCoordinator.swift new file mode 100644 index 0000000..d9798ed --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MainCoordinator.swift @@ -0,0 +1,64 @@ +// +// MainCoordinator.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class MainCoordinator: Coordinator { + + var onSuccessFlow: ((MainCoordinator?) -> ())? + + private let mainTabbar = MainController() + private let appSettings: AppSettings + + init(window: UIWindow, appSettings: AppSettings) { + self.appSettings = appSettings + super.init(window: window) + } + + override func startFlow() { + + // создадим кучу координаторов для каждого табика + //MARK: - coordinator 1 + let lessonsCoordinator = LessonsCoordinator(window: self.window) + addChildrenCoordinator(coordinator: lessonsCoordinator) + + //MARK: - coordinator 2 + let myLessonsCoordinator = MyLessonsCoordinator(window: self.window) + addChildrenCoordinator(coordinator: myLessonsCoordinator) + + //MARK: - coordinator 3 + let kuponsCoordinator = KuponsCoordinator(window: self.window) + addChildrenCoordinator(coordinator: kuponsCoordinator) + + //MARK: - coordinator 4 + alert + let settingsCoordinator = SettingsCoordinator(window: self.window, appSettings: appSettings) + settingsCoordinator.onLogout = { [weak self] in + let alert = UIAlertController(title: "Вы точно хотите выйти?", message: nil, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Да", style: .destructive, handler: { [weak self] _ in + self?.onSuccessFlow?(self) + })) + alert.addAction(UIAlertAction(title: "Отмена", style: .cancel, handler: nil)) + self?.window.rootViewController?.present(alert, animated: true, completion: nil) + } + addChildrenCoordinator(coordinator: settingsCoordinator) + + //MARK: - + lessonsCoordinator.startFlow() + myLessonsCoordinator.startFlow() + kuponsCoordinator.startFlow() + settingsCoordinator.startFlow() + + //MARK: - + mainTabbar.viewControllers = [lessonsCoordinator.rootController, + myLessonsCoordinator.rootController, + kuponsCoordinator.rootController, + settingsCoordinator.rootController] + window.rootViewController = mainTabbar + } + +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/MyLessons.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/MyLessons.storyboard new file mode 100644 index 0000000..0ec09d4 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/MyLessons.storyboard @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/MyLessonsController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/MyLessonsController.swift new file mode 100644 index 0000000..d17931e --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/MyLessonsController.swift @@ -0,0 +1,82 @@ +// +// MyLessonsController.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit +import ProgressHUD + +class MyLessonsController: BaseViewController { + + var onSelectedLesson: ((Lesson) -> ())? + var viewModel: ViewModel? + + @IBOutlet private var tableView: UITableView? + private var dataSource: [Lesson] = [] + + //MARK: - Setup Controller + override func setupController() { + self.title = "My lessons" + self.tabBarItem = UITabBarItem(title: "My lessons", + image: R.image.myLessons(), + tag: 0) + } + + //MARK: - Override func + override func viewDidLoad() { + super.viewDidLoad() + + // pull to refresh + let refreshControl = UIRefreshControl() + tableView?.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(refreshData), for: .valueChanged) + + + // setup view model + viewModel?.onLoading = { + ProgressHUD.show() + } + viewModel?.onLoadedFailed = { [weak self] errorMessage in + self?.tableView?.refreshControl?.endRefreshing() + ProgressHUD.showError(errorMessage) + } + viewModel?.onLoadedSuccess = { [weak self] dataSource in + self?.tableView?.refreshControl?.endRefreshing() + ProgressHUD.dismiss() + if let dataSource = dataSource as? [Lesson] { + self?.dataSource = dataSource + self?.tableView?.reloadData() + } + } + + viewModel?.fetchData() + } + + //MARK: - Actions + @objc private func refreshData() { + viewModel?.fetchData() + } +} + +extension MyLessonsController: UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return dataSource.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.lessonCell, for: indexPath)! + + cell.model = dataSource[indexPath.row] + + return cell + } +} + +extension MyLessonsController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/MyLessonsCoordinator.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/MyLessonsCoordinator.swift new file mode 100644 index 0000000..9288fdf --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/MyLessonsCoordinator.swift @@ -0,0 +1,33 @@ +// +// MyLessonsCoordinator.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class MyLessonsCoordinator: Coordinator { + + let rootController = NavigationController() + + override func startFlow() { + if let controller = R.storyboard.myLessons.myLessonsController() { + + controller.viewModel = MyLessonsViewModel() + controller.onSelectedLesson = { [weak self] lesson in + self?.openLessonDetailed(lesson) + } + rootController.viewControllers = [controller] + } + } + + private func openLessonDetailed(_ lesson: Lesson) { + if let controller = R.storyboard.lessons.lessonDetailedController() { + controller.lesson = lesson + rootController.pushViewController(controller, animated: true) + } + } + +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/ViewModel/MyLessonsViewModel.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/ViewModel/MyLessonsViewModel.swift new file mode 100644 index 0000000..e94cbe5 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/MyLessons/ViewModel/MyLessonsViewModel.swift @@ -0,0 +1,46 @@ +// +// MyLessonsViewModel.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 24.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import Foundation + +protocol ViewModel { + var onLoading: (()->())? { get set } + var onLoadedSuccess: ((Any)->())? { get set } + var onLoadedFailed: ((String)->())? { get set } + + func fetchData() +} + +class MyLessonsViewModel: ViewModel { + + var onLoading: (() -> ())? + var onLoadedSuccess: ((Any) -> ())? + var onLoadedFailed: ((String) -> ())? + + func fetchData() { + onLoading?() + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) { [weak self] in + + self?.onLoadedSuccess?([ + Lesson(title: "1"), + Lesson(title: "2"), + Lesson(title: "3"), + Lesson(title: "4"), + Lesson(title: "5") + ]) + // or +// self?.onLoadedFailed?("Errore message") + } + } +} + +class MyLessonsViewModelMock: MyLessonsViewModel { + override func fetchData() { + + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Settings/Settings.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Settings/Settings.storyboard new file mode 100644 index 0000000..1a772f0 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Settings/Settings.storyboard @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Settings/SettingsController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Settings/SettingsController.swift new file mode 100644 index 0000000..36eeaab --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Settings/SettingsController.swift @@ -0,0 +1,32 @@ +// +// SettingsController.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class SettingsController: BaseViewController { + + var user: User? + var onLogoutClicked: (()->())? + + override func setupController() { + self.title = "Settings" + self.tabBarItem = UITabBarItem(title: "Settings", + image: R.image.settingsIcon(), + tag: 0) + } + + override func viewDidLoad() { + super.viewDidLoad() + title = user?.name + } + + @IBAction private func logoutButtonClicked() { + onLogoutClicked?() + } + +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Settings/SettingsCoordinator.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Settings/SettingsCoordinator.swift new file mode 100644 index 0000000..6c9049d --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Main/Settings/SettingsCoordinator.swift @@ -0,0 +1,33 @@ +// +// SettingsCoordinator.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Yurii Bosov on 17.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +class SettingsCoordinator: Coordinator { + + let rootController = NavigationController() + + var onLogout: (()->())? + + private var appSettings: AppSettings + + init(window: UIWindow, appSettings: AppSettings) { + self.appSettings = appSettings + super.init(window: window) + } + + override func startFlow() { + if let controller = R.storyboard.settings.settingsController() { + controller.user = appSettings.currentUser + controller.onLogoutClicked = { [weak self] in + self?.onLogout?() + } + rootController.viewControllers = [controller] + } + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Start/Start.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Start/Start.storyboard deleted file mode 100644 index 10d628b..0000000 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Start/Start.storyboard +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Start/StartController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Start/StartController.swift deleted file mode 100644 index 9cc9c1c..0000000 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Start/StartController.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// StartController.swift -// lesson31_Auth_Flow -// -// Created by Yurii Bosov on 10.07.2020. -// Copyright © 2020 Bosov. All rights reserved. -// - -import UIKit - -class StartController: BaseViewController { - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - check() - } - - private func check() { - - } - -} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Tutorial.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Tutorial.storyboard index b2e7c03..5ae39c5 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Tutorial.storyboard +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Tutorial.storyboard @@ -1,5 +1,5 @@ - + @@ -9,44 +9,73 @@ - + - - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + - - - - - - - + + + + + + - + - + - + - + - + - + - + - + diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialController.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialController.swift index 5239dce..2f72ef1 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialController.swift +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialController.swift @@ -1,31 +1,117 @@ // // TutorialController.swift -// lesson31_Auth_Flow +// TutorialSlider // -// Created by Yurii Bosov on 10.07.2020. -// Copyright © 2020 Bosov. All rights reserved. +// Created by OlegChudnovskiy on 17.07.2020. +// Copyright © 2020 OlegChudnovskiy. All rights reserved. // import UIKit -//protocol TutorialControllerProtocol: NSObjectProtocol { -// func tutorialControllerAppStarted(controller: TutorialController) -//} - -class TutorialController: BaseViewController { +class TutorialController: BaseViewController, UIScrollViewDelegate { + + @IBOutlet weak var scrollView: UIScrollView? { + didSet{ + if let scrollView = scrollView { + scrollView.delegate = self + } + } + } + + @IBOutlet weak var pageControl: UIPageControl? + @IBOutlet weak var customButton: TutorialButton? + + var onAppStarted: ((TutorialController?) -> ())? -// weak var delegate: TutorialControllerProtocol? - var onAppStarted: ((TutorialController)->())? + var slides = SlideView.createSlides() + //MARK: - override override func viewDidLoad() { super.viewDidLoad() - title = "Tutorial" + navigationController?.setNavigationBarHidden(true, animated: false) + setupSlideScrollView(slides: slides) + setupPageControl() + setupButtonAction() } - @IBAction private func appStart() { -// delegate?.tutorialControllerAppStarted(controller: self) - onAppStarted?(self) + override var prefersStatusBarHidden: Bool { + return true //false + } + + //MARK: - Private + private func setupSlideScrollView(slides : [SlideView]) { + if let scrollView = scrollView { + scrollView.frame = CGRect(x: 0, + y: 0, + width: view.frame.width, + height: scrollView.frame.height) + scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(slides.count), + height: scrollView.frame.height) + scrollView.isPagingEnabled = true + + for i in 0 ..< slides.count { + slides[i].frame = CGRect(x: view.frame.width * CGFloat(i), + y: 0, + width: view.frame.width, + height: scrollView.frame.height) + scrollView.addSubview(slides[i]) + slides[i].layoutIfNeeded() + } + scrollView.contentSize.height = 1.0 // disable vertical scroll + scrollView.showsVerticalScrollIndicator = false + scrollView.showsHorizontalScrollIndicator = false + } + } + + private func setupPageControl() { + if let pageControl = pageControl { + pageControl.numberOfPages = slides.count + pageControl.currentPage = 0 + pageControl.pageIndicatorTintColor = UIColor(red: 53/255, green: 132/255, blue: 159/255, alpha: 1) + pageControl.currentPageIndicatorTintColor = UIColor(red: 125/255, green: 189/255, blue: 211/255, alpha: 1) + + view.bringSubviewToFront(pageControl) + } + } + + private func setupButtonAction() { + if let customButton = customButton { + customButton.onButtonClicked = { [weak self] _ in + if + let pageControl = self?.pageControl, + let slideCount = self?.slides.count, + let scrollView = self?.scrollView + { + if pageControl.currentPage < slideCount - 1 { + pageControl.currentPage = pageControl.currentPage + 1 + if + let x = self?.slides[pageControl.currentPage].frame.origin.x, + let y = self?.slides[pageControl.currentPage].frame.origin.y + { + scrollView.setContentOffset(CGPoint(x: x, y: y), animated: true) + } + } else { + // Start Login + debugPrint("Start Login") + self?.onAppStarted?(self) + } + } + } + } +} + + //MARK: - UIScrollViewDelegate + func scrollViewDidScroll(_ scrollView: UIScrollView) { + let pageIndex = round(scrollView.contentOffset.x/view.frame.width) + + if let pageControl = pageControl { + pageControl.currentPage = Int(pageIndex) + if pageControl.currentPage == slides.count - 1 { + customButton?.textToButtonLabel = "Приступить" + } else { + customButton?.textToButtonLabel = "Далее" + } + } } - } diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialController_old.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialController_old.swift new file mode 100644 index 0000000..5239dce --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialController_old.swift @@ -0,0 +1,31 @@ +// +// TutorialController.swift +// lesson31_Auth_Flow +// +// Created by Yurii Bosov on 10.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit + +//protocol TutorialControllerProtocol: NSObjectProtocol { +// func tutorialControllerAppStarted(controller: TutorialController) +//} + +class TutorialController: BaseViewController { + +// weak var delegate: TutorialControllerProtocol? + + var onAppStarted: ((TutorialController)->())? + + override func viewDidLoad() { + super.viewDidLoad() + title = "Tutorial" + } + + @IBAction private func appStart() { +// delegate?.tutorialControllerAppStarted(controller: self) + onAppStarted?(self) + } + +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialCoordinator.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialCoordinator.swift new file mode 100644 index 0000000..b63dbee --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/TutorialCoordinator.swift @@ -0,0 +1,28 @@ +// +// TutorialCoordinator.swift +// lesson31_Auth_Flow+AppCoordinator +// +// Created by Олег Чудновский on 22.07.2020. +// Copyright © 2020 Bosov. All rights reserved. +// + +import UIKit +import Rswift + +class TutorialCoordinator: AppCoordinator { + var onTutorialIsFinish: ((TutorialCoordinator?)->())? + + override func startFlow() { + startTutorial() + } + + private func startTutorial() { + if let controller = R.storyboard.tutorial.tutorialController(){ + controller.onAppStarted = { [weak self] _ in + self?.onTutorialIsFinish?(self) + } + let navController = NavigationController.init(rootViewController: controller) + window.rootViewController = navController + } + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Main.storyboard b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Tutorial_old.storyboard similarity index 66% rename from lesson31_Auth_Flow+AppCoordinator/UI/Main/Main.storyboard rename to lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Tutorial_old.storyboard index fbf0975..b2e7c03 100644 --- a/lesson31_Auth_Flow+AppCoordinator/UI/Main/Main.storyboard +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Tutorial_old.storyboard @@ -1,5 +1,5 @@ - + @@ -8,45 +8,45 @@ - - + + - - + + - + - - + + - + - + - + - + - + - + - + - + - + diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/Button.xib b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/Button.xib new file mode 100644 index 0000000..70e86bc --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/Button.xib @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/Slide.xib b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/Slide.xib new file mode 100644 index 0000000..1679478 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/Slide.xib @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/SlideView.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/SlideView.swift new file mode 100644 index 0000000..64d9c33 --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/SlideView.swift @@ -0,0 +1,58 @@ +// +// Slide.swift +// TutorialSlider +// +// Created by OlegChudnovskiy on 17.07.2020. +// Copyright © 2020 OlegChudnovskiy. All rights reserved. +// + +import UIKit + +class SlideView: UIView { + + @IBOutlet weak var contentView: UIView? + @IBOutlet weak var titleLabel: UILabel? + @IBOutlet weak var imageView: UIImageView? + @IBOutlet weak var iconImageView: UIImageView? + @IBOutlet weak var leadingIconLayoutConstraint: NSLayoutConstraint? + + //MARK: - private func + static func createSlides() -> [SlideView] { + let slideModel: [SlideModel] = SlideModel.createSlides() + var slideView: [SlideView] = [] + + for i in 0.. CGFloat { + var result = CGFloat() + switch slideNumber { + case 1: + let frameWidth = Float(self.frame.width * 0.3) + result = CGFloat(frameWidth + 16) + break + case 2: + let frameWidth = Float(self.frame.width - (self.frame.width * 0.44)) + result = CGFloat(frameWidth + 16) + break + case 3: + let frameWidth = Float(self.frame.width * 0.28) + result = CGFloat(frameWidth - 31) + break + default: + let frameWidth = Float(self.frame.width / 2) + result = CGFloat(frameWidth - 34) + break + } + return result + } +} diff --git a/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/TutorialButton.swift b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/TutorialButton.swift new file mode 100644 index 0000000..97fde5d --- /dev/null +++ b/lesson31_Auth_Flow+AppCoordinator/UI/Tutorial/Views/TutorialButton.swift @@ -0,0 +1,56 @@ +// +// Button.swift +// TutorialSlider +// +// Created by OlegChudnovskiy on 17.07.2020. +// Copyright © 2020 OlegChudnovskiy. All rights reserved. +// + +import UIKit + +class TutorialButton: UIView { + + @IBOutlet private weak var labelButton: UILabel? + @IBOutlet private weak var imageButton: UIImageView? + @IBOutlet private weak var contentView: UIView? + + var textToButtonLabel: String = "" { + didSet{ + labelButton?.text = textToButtonLabel + } + } + + var onButtonClicked: ((TutorialButton) -> ())? + + override init(frame: CGRect) { + super.init(frame: frame) + initNib() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initNib() + } + + func initNib() { + let bundle = Bundle(for: TutorialButton.self) + bundle.loadNibNamed("Button", owner: self, options: nil) + if let contentView = contentView { + addSubview(contentView) + contentView.frame = bounds + } + } + @IBAction private func butttonTapped() { + + //TODO: сделать нажатие на кнопку как на уроке + self.onButtonClicked?(self) + + UIView.animate(withDuration: 0.3, delay: 0, options: .autoreverse, animations: { + self.contentView?.alpha = 0.5 + }) { _ in + self.contentView?.alpha = 1 + debugPrint("TutorialButton Tapped") + } + } + +}