diff --git a/.github/scripts/test_app.sh b/.github/scripts/test_app.sh new file mode 100755 index 0000000..26f0136 --- /dev/null +++ b/.github/scripts/test_app.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -eo pipefail + +xcodebuild -project DinkleBot/DinkleBot.xcodeproj \ + -scheme DinkleBot \ + -destination platform=iOS\ Simulator,OS=14.4,name=iPhone\ 11 \ + clean test | xcpretty diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 02a2214..4287c68 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -12,8 +12,11 @@ jobs: XC_PROJECT: ${{ 'Dinklebot/Dinklebot.xcodeproj' }} XC_SCHEME: ${{ 'Dinklebot' }} steps: - - name: Select latest Xcode + - name: Select Xcode 12.4 run: "sudo xcode-select -s /Applications/Xcode_$XC_VERSION.app" - - uses: actions/checkout@v2 + - name: Checkout repository + uses: actions/checkout@v2 + - name: Testing iOS app + run: exec ./.github/scripts/test_app.sh - name: Build and Test - run: /usr/bin/xcodebuild test -project "$XC_PROJECT" -scheme "$XC_SCHEME" -destination 'platform=iOS Simulator,name=iPhone 11' clean test | xcpretty + run: /usr/bin/xcodebuild test -project "$XC_PROJECT" -list diff --git a/DinkleBot/DinkleBot.xcodeproj/project.pbxproj b/DinkleBot/DinkleBot.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e8dc901 --- /dev/null +++ b/DinkleBot/DinkleBot.xcodeproj/project.pbxproj @@ -0,0 +1,910 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + BF38B339268D908900EF7544 /* DinkleBotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B338268D908900EF7544 /* DinkleBotTests.swift */; }; + BF38B344268D908900EF7544 /* DinkleBotUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B343268D908900EF7544 /* DinkleBotUITests.swift */; }; + BF38B3A1268D913700EF7544 /* RouterImp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B35B268D913600EF7544 /* RouterImp.swift */; }; + BF38B3A2268D913700EF7544 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B35C268D913600EF7544 /* Router.swift */; }; + BF38B3A3268D913700EF7544 /* DeepLinkOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B35E268D913600EF7544 /* DeepLinkOption.swift */; }; + BF38B3A4268D913700EF7544 /* Presentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B35F268D913600EF7544 /* Presentable.swift */; }; + BF38B3A5268D913700EF7544 /* BaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B360268D913600EF7544 /* BaseView.swift */; }; + BF38B3A6268D913700EF7544 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B361268D913600EF7544 /* Coordinator.swift */; }; + BF38B3A7268D913700EF7544 /* UIViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B363268D913600EF7544 /* UIViewControllerExtension.swift */; }; + BF38B3A8268D913700EF7544 /* UIViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B364268D913600EF7544 /* UIViewExtensions.swift */; }; + BF38B3A9268D913700EF7544 /* NSObjectExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B365268D913600EF7544 /* NSObjectExtensions.swift */; }; + BF38B3AA268D913700EF7544 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF38B367268D913600EF7544 /* Assets.xcassets */; }; + BF38B3AB268D913700EF7544 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF38B368268D913600EF7544 /* LaunchScreen.storyboard */; }; + BF38B3AD268D913700EF7544 /* ApplicationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B36C268D913600EF7544 /* ApplicationCoordinator.swift */; }; + BF38B3AE268D913700EF7544 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B36D268D913600EF7544 /* AppDelegate.swift */; }; + BF38B3AF268D913700EF7544 /* AuthCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B371268D913600EF7544 /* AuthCoordinator.swift */; }; + BF38B3B0268D913700EF7544 /* AuthCoordinatorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B372268D913600EF7544 /* AuthCoordinatorOutput.swift */; }; + BF38B3B1268D913700EF7544 /* TermsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B374268D913600EF7544 /* TermsController.swift */; }; + BF38B3B2268D913700EF7544 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B375268D913600EF7544 /* LoginView.swift */; }; + BF38B3B3268D913700EF7544 /* LoginController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B376268D913600EF7544 /* LoginController.swift */; }; + BF38B3B4268D913700EF7544 /* SignUpController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B377268D913600EF7544 /* SignUpController.swift */; }; + BF38B3B5268D913700EF7544 /* TermsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B378268D913600EF7544 /* TermsView.swift */; }; + BF38B3B6268D913700EF7544 /* SignUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B379268D913600EF7544 /* SignUpView.swift */; }; + BF38B3B7268D913700EF7544 /* OnboardingCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B37B268D913600EF7544 /* OnboardingCoordinator.swift */; }; + BF38B3B8268D913700EF7544 /* OnboardingCoordinatorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B37C268D913600EF7544 /* OnboardingCoordinatorOutput.swift */; }; + BF38B3B9268D913700EF7544 /* StepController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B37E268D913600EF7544 /* StepController.swift */; }; + BF38B3BA268D913700EF7544 /* OnboardingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B37F268D913600EF7544 /* OnboardingController.swift */; }; + BF38B3BB268D913700EF7544 /* PageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B380268D913600EF7544 /* PageViewController.swift */; }; + BF38B3BC268D913700EF7544 /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B381268D913600EF7544 /* OnboardingView.swift */; }; + BF38B3BD268D913700EF7544 /* HomeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B383268D913600EF7544 /* HomeController.swift */; }; + BF38B3BE268D913700EF7544 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B384268D913600EF7544 /* HomeView.swift */; }; + BF38B3BF268D913700EF7544 /* HomeCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B385268D913600EF7544 /* HomeCoordinator.swift */; }; + BF38B3C0268D913700EF7544 /* TabbarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B387268D913600EF7544 /* TabbarCoordinator.swift */; }; + BF38B3C1268D913700EF7544 /* TabbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B388268D913600EF7544 /* TabbarView.swift */; }; + BF38B3C2268D913700EF7544 /* TabbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B389268D913600EF7544 /* TabbarController.swift */; }; + BF38B3C3268D913700EF7544 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B38B268D913600EF7544 /* SettingsView.swift */; }; + BF38B3C4268D913700EF7544 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B38C268D913600EF7544 /* SettingsController.swift */; }; + BF38B3C5268D913700EF7544 /* Setting.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B38D268D913600EF7544 /* Setting.swift */; }; + BF38B3C6268D913700EF7544 /* SettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B38E268D913600EF7544 /* SettingsCoordinator.swift */; }; + BF38B3C7268D913700EF7544 /* StoryboardsEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B390268D913600EF7544 /* StoryboardsEnum.swift */; }; + BF38B3C8268D913700EF7544 /* Onboarding.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF38B391268D913600EF7544 /* Onboarding.storyboard */; }; + BF38B3C9268D913700EF7544 /* Home.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF38B392268D913600EF7544 /* Home.storyboard */; }; + BF38B3CA268D913700EF7544 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF38B393268D913600EF7544 /* Main.storyboard */; }; + BF38B3CB268D913700EF7544 /* Auth.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF38B394268D913600EF7544 /* Auth.storyboard */; }; + BF38B3CC268D913700EF7544 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF38B395268D913600EF7544 /* Settings.storyboard */; }; + BF38B3CD268D913700EF7544 /* BaseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B397268D913600EF7544 /* BaseCoordinator.swift */; }; + BF38B3CE268D913700EF7544 /* ModuleFactoryImp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B39A268D913700EF7544 /* ModuleFactoryImp.swift */; }; + BF38B3CF268D913700EF7544 /* CoordinatorFactoryImp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B39B268D913700EF7544 /* CoordinatorFactoryImp.swift */; }; + BF38B3D0268D913700EF7544 /* OnboardingModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B39C268D913700EF7544 /* OnboardingModuleFactory.swift */; }; + BF38B3D1268D913700EF7544 /* HomeModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B39D268D913700EF7544 /* HomeModuleFactory.swift */; }; + BF38B3D2268D913700EF7544 /* SettingsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B39E268D913700EF7544 /* SettingsModuleFactory.swift */; }; + BF38B3D3268D913700EF7544 /* AuthModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B39F268D913700EF7544 /* AuthModuleFactory.swift */; }; + BF38B3D4268D913700EF7544 /* CoordinatorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF38B3A0268D913700EF7544 /* CoordinatorFactory.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + BF38B335268D908900EF7544 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BF38B316268D908600EF7544 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BF38B31D268D908600EF7544; + remoteInfo = DinkleBot; + }; + BF38B340268D908900EF7544 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BF38B316268D908600EF7544 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BF38B31D268D908600EF7544; + remoteInfo = DinkleBot; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + BF38B31E268D908600EF7544 /* DinkleBot.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DinkleBot.app; sourceTree = BUILT_PRODUCTS_DIR; }; + BF38B334268D908900EF7544 /* DinkleBotTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DinkleBotTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + BF38B338268D908900EF7544 /* DinkleBotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DinkleBotTests.swift; sourceTree = ""; }; + BF38B33A268D908900EF7544 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BF38B33F268D908900EF7544 /* DinkleBotUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DinkleBotUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + BF38B343268D908900EF7544 /* DinkleBotUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DinkleBotUITests.swift; sourceTree = ""; }; + BF38B345268D908900EF7544 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BF38B35B268D913600EF7544 /* RouterImp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouterImp.swift; sourceTree = ""; }; + BF38B35C268D913600EF7544 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; + BF38B35E268D913600EF7544 /* DeepLinkOption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeepLinkOption.swift; sourceTree = ""; }; + BF38B35F268D913600EF7544 /* Presentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Presentable.swift; sourceTree = ""; }; + BF38B360268D913600EF7544 /* BaseView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseView.swift; sourceTree = ""; }; + BF38B361268D913600EF7544 /* Coordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; + BF38B363268D913600EF7544 /* UIViewControllerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewControllerExtension.swift; sourceTree = ""; }; + BF38B364268D913600EF7544 /* UIViewExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewExtensions.swift; sourceTree = ""; }; + BF38B365268D913600EF7544 /* NSObjectExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSObjectExtensions.swift; sourceTree = ""; }; + BF38B367268D913600EF7544 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + BF38B369268D913600EF7544 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + BF38B36A268D913600EF7544 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BF38B36C268D913600EF7544 /* ApplicationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationCoordinator.swift; sourceTree = ""; }; + BF38B36D268D913600EF7544 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + BF38B36E268D913600EF7544 /* DinkleBot-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DinkleBot-Bridging-Header.h"; sourceTree = ""; }; + BF38B371268D913600EF7544 /* AuthCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthCoordinator.swift; sourceTree = ""; }; + BF38B372268D913600EF7544 /* AuthCoordinatorOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthCoordinatorOutput.swift; sourceTree = ""; }; + BF38B374268D913600EF7544 /* TermsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TermsController.swift; sourceTree = ""; }; + BF38B375268D913600EF7544 /* LoginView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; + BF38B376268D913600EF7544 /* LoginController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginController.swift; sourceTree = ""; }; + BF38B377268D913600EF7544 /* SignUpController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignUpController.swift; sourceTree = ""; }; + BF38B378268D913600EF7544 /* TermsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TermsView.swift; sourceTree = ""; }; + BF38B379268D913600EF7544 /* SignUpView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignUpView.swift; sourceTree = ""; }; + BF38B37B268D913600EF7544 /* OnboardingCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingCoordinator.swift; sourceTree = ""; }; + BF38B37C268D913600EF7544 /* OnboardingCoordinatorOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingCoordinatorOutput.swift; sourceTree = ""; }; + BF38B37E268D913600EF7544 /* StepController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepController.swift; sourceTree = ""; }; + BF38B37F268D913600EF7544 /* OnboardingController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingController.swift; sourceTree = ""; }; + BF38B380268D913600EF7544 /* PageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageViewController.swift; sourceTree = ""; }; + BF38B381268D913600EF7544 /* OnboardingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = ""; }; + BF38B383268D913600EF7544 /* HomeController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeController.swift; sourceTree = ""; }; + BF38B384268D913600EF7544 /* HomeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; + BF38B385268D913600EF7544 /* HomeCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeCoordinator.swift; sourceTree = ""; }; + BF38B387268D913600EF7544 /* TabbarCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabbarCoordinator.swift; sourceTree = ""; }; + BF38B388268D913600EF7544 /* TabbarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabbarView.swift; sourceTree = ""; }; + BF38B389268D913600EF7544 /* TabbarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabbarController.swift; sourceTree = ""; }; + BF38B38B268D913600EF7544 /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + BF38B38C268D913600EF7544 /* SettingsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = ""; }; + BF38B38D268D913600EF7544 /* Setting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Setting.swift; sourceTree = ""; }; + BF38B38E268D913600EF7544 /* SettingsCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsCoordinator.swift; sourceTree = ""; }; + BF38B390268D913600EF7544 /* StoryboardsEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardsEnum.swift; sourceTree = ""; }; + BF38B391268D913600EF7544 /* Onboarding.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Onboarding.storyboard; sourceTree = ""; }; + BF38B392268D913600EF7544 /* Home.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Home.storyboard; sourceTree = ""; }; + BF38B393268D913600EF7544 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; + BF38B394268D913600EF7544 /* Auth.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Auth.storyboard; sourceTree = ""; }; + BF38B395268D913600EF7544 /* Settings.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; + BF38B397268D913600EF7544 /* BaseCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseCoordinator.swift; sourceTree = ""; }; + BF38B39A268D913700EF7544 /* ModuleFactoryImp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModuleFactoryImp.swift; sourceTree = ""; }; + BF38B39B268D913700EF7544 /* CoordinatorFactoryImp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoordinatorFactoryImp.swift; sourceTree = ""; }; + BF38B39C268D913700EF7544 /* OnboardingModuleFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingModuleFactory.swift; sourceTree = ""; }; + BF38B39D268D913700EF7544 /* HomeModuleFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeModuleFactory.swift; sourceTree = ""; }; + BF38B39E268D913700EF7544 /* SettingsModuleFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsModuleFactory.swift; sourceTree = ""; }; + BF38B39F268D913700EF7544 /* AuthModuleFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthModuleFactory.swift; sourceTree = ""; }; + BF38B3A0268D913700EF7544 /* CoordinatorFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoordinatorFactory.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + BF38B31B268D908600EF7544 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BF38B331268D908900EF7544 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BF38B33C268D908900EF7544 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + BF38B315268D908600EF7544 = { + isa = PBXGroup; + children = ( + BF38B320268D908600EF7544 /* DinkleBot */, + BF38B337268D908900EF7544 /* DinkleBotTests */, + BF38B342268D908900EF7544 /* DinkleBotUITests */, + BF38B31F268D908600EF7544 /* Products */, + ); + sourceTree = ""; + }; + BF38B31F268D908600EF7544 /* Products */ = { + isa = PBXGroup; + children = ( + BF38B31E268D908600EF7544 /* DinkleBot.app */, + BF38B334268D908900EF7544 /* DinkleBotTests.xctest */, + BF38B33F268D908900EF7544 /* DinkleBotUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + BF38B320268D908600EF7544 /* DinkleBot */ = { + isa = PBXGroup; + children = ( + BF38B36B268D913600EF7544 /* Application */, + BF38B396268D913600EF7544 /* Base */, + BF38B362268D913600EF7544 /* Extensions */, + BF38B398268D913700EF7544 /* Factories */, + BF38B36F268D913600EF7544 /* Flows */, + BF38B35D268D913600EF7544 /* Protocols */, + BF38B366268D913600EF7544 /* Resources */, + BF38B35A268D913600EF7544 /* Routers */, + BF38B38F268D913600EF7544 /* Storyboards */, + ); + path = DinkleBot; + sourceTree = ""; + }; + BF38B337268D908900EF7544 /* DinkleBotTests */ = { + isa = PBXGroup; + children = ( + BF38B338268D908900EF7544 /* DinkleBotTests.swift */, + BF38B33A268D908900EF7544 /* Info.plist */, + ); + path = DinkleBotTests; + sourceTree = ""; + }; + BF38B342268D908900EF7544 /* DinkleBotUITests */ = { + isa = PBXGroup; + children = ( + BF38B343268D908900EF7544 /* DinkleBotUITests.swift */, + BF38B345268D908900EF7544 /* Info.plist */, + ); + path = DinkleBotUITests; + sourceTree = ""; + }; + BF38B35A268D913600EF7544 /* Routers */ = { + isa = PBXGroup; + children = ( + BF38B35B268D913600EF7544 /* RouterImp.swift */, + BF38B35C268D913600EF7544 /* Router.swift */, + ); + path = Routers; + sourceTree = ""; + }; + BF38B35D268D913600EF7544 /* Protocols */ = { + isa = PBXGroup; + children = ( + BF38B35E268D913600EF7544 /* DeepLinkOption.swift */, + BF38B35F268D913600EF7544 /* Presentable.swift */, + BF38B360268D913600EF7544 /* BaseView.swift */, + BF38B361268D913600EF7544 /* Coordinator.swift */, + ); + path = Protocols; + sourceTree = ""; + }; + BF38B362268D913600EF7544 /* Extensions */ = { + isa = PBXGroup; + children = ( + BF38B363268D913600EF7544 /* UIViewControllerExtension.swift */, + BF38B364268D913600EF7544 /* UIViewExtensions.swift */, + BF38B365268D913600EF7544 /* NSObjectExtensions.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + BF38B366268D913600EF7544 /* Resources */ = { + isa = PBXGroup; + children = ( + BF38B36E268D913600EF7544 /* DinkleBot-Bridging-Header.h */, + BF38B367268D913600EF7544 /* Assets.xcassets */, + BF38B368268D913600EF7544 /* LaunchScreen.storyboard */, + BF38B36A268D913600EF7544 /* Info.plist */, + ); + path = Resources; + sourceTree = ""; + }; + BF38B36B268D913600EF7544 /* Application */ = { + isa = PBXGroup; + children = ( + BF38B36C268D913600EF7544 /* ApplicationCoordinator.swift */, + BF38B36D268D913600EF7544 /* AppDelegate.swift */, + ); + path = Application; + sourceTree = ""; + }; + BF38B36F268D913600EF7544 /* Flows */ = { + isa = PBXGroup; + children = ( + BF38B370268D913600EF7544 /* Login flow */, + BF38B37A268D913600EF7544 /* OnboardingFlow */, + BF38B382268D913600EF7544 /* Home Flow */, + BF38B386268D913600EF7544 /* MainTabbarFlow */, + BF38B38A268D913600EF7544 /* Settings flow */, + ); + path = Flows; + sourceTree = ""; + }; + BF38B370268D913600EF7544 /* Login flow */ = { + isa = PBXGroup; + children = ( + BF38B371268D913600EF7544 /* AuthCoordinator.swift */, + BF38B372268D913600EF7544 /* AuthCoordinatorOutput.swift */, + BF38B373268D913600EF7544 /* Controllers */, + ); + path = "Login flow"; + sourceTree = ""; + }; + BF38B373268D913600EF7544 /* Controllers */ = { + isa = PBXGroup; + children = ( + BF38B374268D913600EF7544 /* TermsController.swift */, + BF38B375268D913600EF7544 /* LoginView.swift */, + BF38B376268D913600EF7544 /* LoginController.swift */, + BF38B377268D913600EF7544 /* SignUpController.swift */, + BF38B378268D913600EF7544 /* TermsView.swift */, + BF38B379268D913600EF7544 /* SignUpView.swift */, + ); + path = Controllers; + sourceTree = ""; + }; + BF38B37A268D913600EF7544 /* OnboardingFlow */ = { + isa = PBXGroup; + children = ( + BF38B37B268D913600EF7544 /* OnboardingCoordinator.swift */, + BF38B37C268D913600EF7544 /* OnboardingCoordinatorOutput.swift */, + BF38B37D268D913600EF7544 /* Controllers */, + ); + path = OnboardingFlow; + sourceTree = ""; + }; + BF38B37D268D913600EF7544 /* Controllers */ = { + isa = PBXGroup; + children = ( + BF38B37E268D913600EF7544 /* StepController.swift */, + BF38B37F268D913600EF7544 /* OnboardingController.swift */, + BF38B380268D913600EF7544 /* PageViewController.swift */, + BF38B381268D913600EF7544 /* OnboardingView.swift */, + ); + path = Controllers; + sourceTree = ""; + }; + BF38B382268D913600EF7544 /* Home Flow */ = { + isa = PBXGroup; + children = ( + BF38B383268D913600EF7544 /* HomeController.swift */, + BF38B384268D913600EF7544 /* HomeView.swift */, + BF38B385268D913600EF7544 /* HomeCoordinator.swift */, + ); + path = "Home Flow"; + sourceTree = ""; + }; + BF38B386268D913600EF7544 /* MainTabbarFlow */ = { + isa = PBXGroup; + children = ( + BF38B387268D913600EF7544 /* TabbarCoordinator.swift */, + BF38B388268D913600EF7544 /* TabbarView.swift */, + BF38B389268D913600EF7544 /* TabbarController.swift */, + ); + path = MainTabbarFlow; + sourceTree = ""; + }; + BF38B38A268D913600EF7544 /* Settings flow */ = { + isa = PBXGroup; + children = ( + BF38B38B268D913600EF7544 /* SettingsView.swift */, + BF38B38C268D913600EF7544 /* SettingsController.swift */, + BF38B38D268D913600EF7544 /* Setting.swift */, + BF38B38E268D913600EF7544 /* SettingsCoordinator.swift */, + ); + path = "Settings flow"; + sourceTree = ""; + }; + BF38B38F268D913600EF7544 /* Storyboards */ = { + isa = PBXGroup; + children = ( + BF38B390268D913600EF7544 /* StoryboardsEnum.swift */, + BF38B391268D913600EF7544 /* Onboarding.storyboard */, + BF38B392268D913600EF7544 /* Home.storyboard */, + BF38B393268D913600EF7544 /* Main.storyboard */, + BF38B394268D913600EF7544 /* Auth.storyboard */, + BF38B395268D913600EF7544 /* Settings.storyboard */, + ); + path = Storyboards; + sourceTree = ""; + }; + BF38B396268D913600EF7544 /* Base */ = { + isa = PBXGroup; + children = ( + BF38B397268D913600EF7544 /* BaseCoordinator.swift */, + ); + path = Base; + sourceTree = ""; + }; + BF38B398268D913700EF7544 /* Factories */ = { + isa = PBXGroup; + children = ( + BF38B399268D913700EF7544 /* Imp */, + BF38B39C268D913700EF7544 /* OnboardingModuleFactory.swift */, + BF38B39D268D913700EF7544 /* HomeModuleFactory.swift */, + BF38B39E268D913700EF7544 /* SettingsModuleFactory.swift */, + BF38B39F268D913700EF7544 /* AuthModuleFactory.swift */, + BF38B3A0268D913700EF7544 /* CoordinatorFactory.swift */, + ); + path = Factories; + sourceTree = ""; + }; + BF38B399268D913700EF7544 /* Imp */ = { + isa = PBXGroup; + children = ( + BF38B39A268D913700EF7544 /* ModuleFactoryImp.swift */, + BF38B39B268D913700EF7544 /* CoordinatorFactoryImp.swift */, + ); + path = Imp; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + BF38B31D268D908600EF7544 /* DinkleBot */ = { + isa = PBXNativeTarget; + buildConfigurationList = BF38B348268D908900EF7544 /* Build configuration list for PBXNativeTarget "DinkleBot" */; + buildPhases = ( + BF38B31A268D908600EF7544 /* Sources */, + BF38B31B268D908600EF7544 /* Frameworks */, + BF38B31C268D908600EF7544 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DinkleBot; + productName = DinkleBot; + productReference = BF38B31E268D908600EF7544 /* DinkleBot.app */; + productType = "com.apple.product-type.application"; + }; + BF38B333268D908900EF7544 /* DinkleBotTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = BF38B34B268D908900EF7544 /* Build configuration list for PBXNativeTarget "DinkleBotTests" */; + buildPhases = ( + BF38B330268D908900EF7544 /* Sources */, + BF38B331268D908900EF7544 /* Frameworks */, + BF38B332268D908900EF7544 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + BF38B336268D908900EF7544 /* PBXTargetDependency */, + ); + name = DinkleBotTests; + productName = DinkleBotTests; + productReference = BF38B334268D908900EF7544 /* DinkleBotTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + BF38B33E268D908900EF7544 /* DinkleBotUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = BF38B34E268D908900EF7544 /* Build configuration list for PBXNativeTarget "DinkleBotUITests" */; + buildPhases = ( + BF38B33B268D908900EF7544 /* Sources */, + BF38B33C268D908900EF7544 /* Frameworks */, + BF38B33D268D908900EF7544 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + BF38B341268D908900EF7544 /* PBXTargetDependency */, + ); + name = DinkleBotUITests; + productName = DinkleBotUITests; + productReference = BF38B33F268D908900EF7544 /* DinkleBotUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BF38B316268D908600EF7544 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1240; + LastUpgradeCheck = 1240; + TargetAttributes = { + BF38B31D268D908600EF7544 = { + CreatedOnToolsVersion = 12.4; + }; + BF38B333268D908900EF7544 = { + CreatedOnToolsVersion = 12.4; + TestTargetID = BF38B31D268D908600EF7544; + }; + BF38B33E268D908900EF7544 = { + CreatedOnToolsVersion = 12.4; + TestTargetID = BF38B31D268D908600EF7544; + }; + }; + }; + buildConfigurationList = BF38B319268D908600EF7544 /* Build configuration list for PBXProject "DinkleBot" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BF38B315268D908600EF7544; + productRefGroup = BF38B31F268D908600EF7544 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BF38B31D268D908600EF7544 /* DinkleBot */, + BF38B333268D908900EF7544 /* DinkleBotTests */, + BF38B33E268D908900EF7544 /* DinkleBotUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + BF38B31C268D908600EF7544 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BF38B3AA268D913700EF7544 /* Assets.xcassets in Resources */, + BF38B3C9268D913700EF7544 /* Home.storyboard in Resources */, + BF38B3AB268D913700EF7544 /* LaunchScreen.storyboard in Resources */, + BF38B3CC268D913700EF7544 /* Settings.storyboard in Resources */, + BF38B3CA268D913700EF7544 /* Main.storyboard in Resources */, + BF38B3C8268D913700EF7544 /* Onboarding.storyboard in Resources */, + BF38B3CB268D913700EF7544 /* Auth.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BF38B332268D908900EF7544 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BF38B33D268D908900EF7544 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + BF38B31A268D908600EF7544 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BF38B3BE268D913700EF7544 /* HomeView.swift in Sources */, + BF38B3CF268D913700EF7544 /* CoordinatorFactoryImp.swift in Sources */, + BF38B3C7268D913700EF7544 /* StoryboardsEnum.swift in Sources */, + BF38B3AE268D913700EF7544 /* AppDelegate.swift in Sources */, + BF38B3A2268D913700EF7544 /* Router.swift in Sources */, + BF38B3A4268D913700EF7544 /* Presentable.swift in Sources */, + BF38B3B2268D913700EF7544 /* LoginView.swift in Sources */, + BF38B3C0268D913700EF7544 /* TabbarCoordinator.swift in Sources */, + BF38B3CE268D913700EF7544 /* ModuleFactoryImp.swift in Sources */, + BF38B3BF268D913700EF7544 /* HomeCoordinator.swift in Sources */, + BF38B3A8268D913700EF7544 /* UIViewExtensions.swift in Sources */, + BF38B3B6268D913700EF7544 /* SignUpView.swift in Sources */, + BF38B3BD268D913700EF7544 /* HomeController.swift in Sources */, + BF38B3C2268D913700EF7544 /* TabbarController.swift in Sources */, + BF38B3A6268D913700EF7544 /* Coordinator.swift in Sources */, + BF38B3A5268D913700EF7544 /* BaseView.swift in Sources */, + BF38B3AD268D913700EF7544 /* ApplicationCoordinator.swift in Sources */, + BF38B3D0268D913700EF7544 /* OnboardingModuleFactory.swift in Sources */, + BF38B3B7268D913700EF7544 /* OnboardingCoordinator.swift in Sources */, + BF38B3A9268D913700EF7544 /* NSObjectExtensions.swift in Sources */, + BF38B3B4268D913700EF7544 /* SignUpController.swift in Sources */, + BF38B3B5268D913700EF7544 /* TermsView.swift in Sources */, + BF38B3A3268D913700EF7544 /* DeepLinkOption.swift in Sources */, + BF38B3C1268D913700EF7544 /* TabbarView.swift in Sources */, + BF38B3B1268D913700EF7544 /* TermsController.swift in Sources */, + BF38B3BB268D913700EF7544 /* PageViewController.swift in Sources */, + BF38B3A7268D913700EF7544 /* UIViewControllerExtension.swift in Sources */, + BF38B3AF268D913700EF7544 /* AuthCoordinator.swift in Sources */, + BF38B3BC268D913700EF7544 /* OnboardingView.swift in Sources */, + BF38B3C6268D913700EF7544 /* SettingsCoordinator.swift in Sources */, + BF38B3C3268D913700EF7544 /* SettingsView.swift in Sources */, + BF38B3D4268D913700EF7544 /* CoordinatorFactory.swift in Sources */, + BF38B3B3268D913700EF7544 /* LoginController.swift in Sources */, + BF38B3CD268D913700EF7544 /* BaseCoordinator.swift in Sources */, + BF38B3C4268D913700EF7544 /* SettingsController.swift in Sources */, + BF38B3B8268D913700EF7544 /* OnboardingCoordinatorOutput.swift in Sources */, + BF38B3D2268D913700EF7544 /* SettingsModuleFactory.swift in Sources */, + BF38B3BA268D913700EF7544 /* OnboardingController.swift in Sources */, + BF38B3D1268D913700EF7544 /* HomeModuleFactory.swift in Sources */, + BF38B3B9268D913700EF7544 /* StepController.swift in Sources */, + BF38B3A1268D913700EF7544 /* RouterImp.swift in Sources */, + BF38B3D3268D913700EF7544 /* AuthModuleFactory.swift in Sources */, + BF38B3C5268D913700EF7544 /* Setting.swift in Sources */, + BF38B3B0268D913700EF7544 /* AuthCoordinatorOutput.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BF38B330268D908900EF7544 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BF38B339268D908900EF7544 /* DinkleBotTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BF38B33B268D908900EF7544 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BF38B344268D908900EF7544 /* DinkleBotUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + BF38B336268D908900EF7544 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BF38B31D268D908600EF7544 /* DinkleBot */; + targetProxy = BF38B335268D908900EF7544 /* PBXContainerItemProxy */; + }; + BF38B341268D908900EF7544 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BF38B31D268D908600EF7544 /* DinkleBot */; + targetProxy = BF38B340268D908900EF7544 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + BF38B368268D913600EF7544 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + BF38B369268D913600EF7544 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + BF38B346268D908900EF7544 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + BF38B347268D908900EF7544 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BF38B349268D908900EF7544 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 6KV9C8LXMT; + INFOPLIST_FILE = "$(SRCROOT)/DinkleBot/Resources/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.iainsmith.dinklebot.DinkleBot; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/$(PROJECT_NAME)/Resources/$(SWIFT_MODULE_NAME)-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BF38B34A268D908900EF7544 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 6KV9C8LXMT; + INFOPLIST_FILE = "$(SRCROOT)/DinkleBot/Resources/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.iainsmith.dinklebot.DinkleBot; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/$(PROJECT_NAME)/Resources/$(SWIFT_MODULE_NAME)-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + BF38B34C268D908900EF7544 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 6KV9C8LXMT; + INFOPLIST_FILE = DinkleBotTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.iainsmith.dinklebot.DinkleBotTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DinkleBot.app/DinkleBot"; + }; + name = Debug; + }; + BF38B34D268D908900EF7544 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 6KV9C8LXMT; + INFOPLIST_FILE = DinkleBotTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.iainsmith.dinklebot.DinkleBotTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DinkleBot.app/DinkleBot"; + }; + name = Release; + }; + BF38B34F268D908900EF7544 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 6KV9C8LXMT; + INFOPLIST_FILE = DinkleBotUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.iainsmith.dinklebot.DinkleBotUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = DinkleBot; + }; + name = Debug; + }; + BF38B350268D908900EF7544 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 6KV9C8LXMT; + INFOPLIST_FILE = DinkleBotUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.iainsmith.dinklebot.DinkleBotUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = DinkleBot; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BF38B319268D908600EF7544 /* Build configuration list for PBXProject "DinkleBot" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BF38B346268D908900EF7544 /* Debug */, + BF38B347268D908900EF7544 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BF38B348268D908900EF7544 /* Build configuration list for PBXNativeTarget "DinkleBot" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BF38B349268D908900EF7544 /* Debug */, + BF38B34A268D908900EF7544 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BF38B34B268D908900EF7544 /* Build configuration list for PBXNativeTarget "DinkleBotTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BF38B34C268D908900EF7544 /* Debug */, + BF38B34D268D908900EF7544 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BF38B34E268D908900EF7544 /* Build configuration list for PBXNativeTarget "DinkleBotUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BF38B34F268D908900EF7544 /* Debug */, + BF38B350268D908900EF7544 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BF38B316268D908600EF7544 /* Project object */; +} diff --git a/DinkleBot/DinkleBot.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/DinkleBot/DinkleBot.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/DinkleBot/DinkleBot.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/DinkleBot/DinkleBot.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/DinkleBot/DinkleBot.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/DinkleBot/DinkleBot.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/DinkleBot/DinkleBot/Application/AppDelegate.swift b/DinkleBot/DinkleBot/Application/AppDelegate.swift new file mode 100644 index 0000000..530476e --- /dev/null +++ b/DinkleBot/DinkleBot/Application/AppDelegate.swift @@ -0,0 +1,48 @@ +// +// AppDelegate.swift +// DinkleBot +// +// Created by Iain Smith on 13/06/2021. +// + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + var rootController: UINavigationController { + return self.window!.rootViewController as! UINavigationController + } + + private lazy var applicationCoordinator: Coordinator = self.makeCoordinator() + + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + let notification = launchOptions?[.remoteNotification] as? [String: AnyObject] + let deepLink = DeepLinkOption.build(with: notification) + applicationCoordinator.start(with: deepLink) + return true + } + + private func makeCoordinator() -> Coordinator { + return ApplicationCoordinator( + router: RouterImp(rootController: self.rootController), + coordinatorFactory: CoordinatorFactoryImp() + ) + } + + //MARK: Handle push notifications and deep links + func application(_ application: UIApplication, + didReceiveRemoteNotification userInfo: [AnyHashable : Any]) { + let dict = userInfo as? [String: AnyObject] + let deepLink = DeepLinkOption.build(with: dict) + applicationCoordinator.start(with: deepLink) + } + + func application(_ application: UIApplication, continue userActivity: NSUserActivity, + restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { + let deepLink = DeepLinkOption.build(with: userActivity) + applicationCoordinator.start(with: deepLink) + return true + } +} + diff --git a/DinkleBot/DinkleBot/Application/ApplicationCoordinator.swift b/DinkleBot/DinkleBot/Application/ApplicationCoordinator.swift new file mode 100644 index 0000000..02f456e --- /dev/null +++ b/DinkleBot/DinkleBot/Application/ApplicationCoordinator.swift @@ -0,0 +1,89 @@ +// +// AppCoordinator.swift +// DinkleBot +// +// Created by Iain Smith on 16/06/2021. +// + +// TODO Store these somewhere else +fileprivate var onboardingWasShown = false +fileprivate var isAutorized = false + +fileprivate enum LaunchInstructor { + case main, auth, onboarding + + static func configure( + tutorialWasShown: Bool = onboardingWasShown, + isAutorized: Bool = isAutorized) -> LaunchInstructor { + + switch (tutorialWasShown, isAutorized) { + case (true, false), (false, false): return .auth + case (false, true): return .onboarding + case (true, true): return .main + } + } +} + +final class ApplicationCoordinator: BaseCoordinator { + + private let coordinatorFactory: CoordinatorFactory + private let router: Router + + private var instructor: LaunchInstructor { + return LaunchInstructor.configure() + } + + init(router: Router, coordinatorFactory: CoordinatorFactory) { + self.router = router + self.coordinatorFactory = coordinatorFactory + } + + override func start(with option: DeepLinkOption?) { + //start with deepLink + if let option = option { + switch option { + case .onboarding: runOnboardingFlow() + case .signUp: runAuthFlow() + default: childCoordinators.forEach { coordinator in + coordinator.start(with: option) + } + } + // default start + } else { + switch instructor { + case .onboarding: runOnboardingFlow() + case .auth: runAuthFlow() + case .main: runMainFlow() + } + } + } + + private func runAuthFlow() { + let coordinator = coordinatorFactory.makeAuthCoordinatorBox(router: router) + coordinator.finishFlow = { [weak self, weak coordinator] in + isAutorized = true + self?.start() + self?.removeDependency(coordinator) + } + addDependency(coordinator) + coordinator.start() + } + + private func runOnboardingFlow() { + let coordinator = coordinatorFactory.makeOnboardingCoordinator(router: router) + coordinator.finishFlow = { [weak self, weak coordinator] in + onboardingWasShown = true + self?.start() + self?.removeDependency(coordinator) + } + addDependency(coordinator) + coordinator.start() + } + + private func runMainFlow() { + let (coordinator, module) = coordinatorFactory.makeTabbarCoordinator() + addDependency(coordinator) + router.setRootModule(module, hideBar: true) + coordinator.start() + } +} diff --git a/DinkleBot/DinkleBot/Base/BaseCoordinator.swift b/DinkleBot/DinkleBot/Base/BaseCoordinator.swift new file mode 100644 index 0000000..5747726 --- /dev/null +++ b/DinkleBot/DinkleBot/Base/BaseCoordinator.swift @@ -0,0 +1,34 @@ +class BaseCoordinator: Coordinator { + + var childCoordinators: [Coordinator] = [] + + func start() { + start(with: nil) + } + + func start(with option: DeepLinkOption?) { } + + // add only unique object + func addDependency(_ coordinator: Coordinator) { + guard !childCoordinators.contains(where: { $0 === coordinator }) else { return } + childCoordinators.append(coordinator) + } + + func removeDependency(_ coordinator: Coordinator?) { + guard + childCoordinators.isEmpty == false, + let coordinator = coordinator + else { return } + + // Clear child-coordinators recursively + if let coordinator = coordinator as? BaseCoordinator, !coordinator.childCoordinators.isEmpty { + coordinator.childCoordinators + .filter({ $0 !== coordinator }) + .forEach({ coordinator.removeDependency($0) }) + } + for (index, element) in childCoordinators.enumerated() where element === coordinator { + childCoordinators.remove(at: index) + break + } + } +} diff --git a/DinkleBot/DinkleBot/Extensions/NSObjectExtensions.swift b/DinkleBot/DinkleBot/Extensions/NSObjectExtensions.swift new file mode 100644 index 0000000..163c861 --- /dev/null +++ b/DinkleBot/DinkleBot/Extensions/NSObjectExtensions.swift @@ -0,0 +1,6 @@ +extension NSObject { + + class var nameOfClass: String { + return NSStringFromClass(self).components(separatedBy: ".").last! + } +} diff --git a/DinkleBot/DinkleBot/Extensions/UIViewControllerExtension.swift b/DinkleBot/DinkleBot/Extensions/UIViewControllerExtension.swift new file mode 100644 index 0000000..c149487 --- /dev/null +++ b/DinkleBot/DinkleBot/Extensions/UIViewControllerExtension.swift @@ -0,0 +1,18 @@ +extension UIViewController { + + private class func instantiateControllerInStoryboard(_ storyboard: UIStoryboard, identifier: String) -> T { + return storyboard.instantiateViewController(withIdentifier: identifier) as! T + } + + class func controllerInStoryboard(_ storyboard: UIStoryboard, identifier: String) -> Self { + return instantiateControllerInStoryboard(storyboard, identifier: identifier) + } + + class func controllerInStoryboard(_ storyboard: UIStoryboard) -> Self { + return controllerInStoryboard(storyboard, identifier: nameOfClass) + } + + class func controllerFromStoryboard(_ storyboard: Storyboards) -> Self { + return controllerInStoryboard(UIStoryboard(name: storyboard.rawValue, bundle: nil), identifier: nameOfClass) + } +} diff --git a/DinkleBot/DinkleBot/Extensions/UIViewExtensions.swift b/DinkleBot/DinkleBot/Extensions/UIViewExtensions.swift new file mode 100644 index 0000000..5473841 --- /dev/null +++ b/DinkleBot/DinkleBot/Extensions/UIViewExtensions.swift @@ -0,0 +1,17 @@ +extension UIView { + + private class func viewInNibNamed(_ nibNamed: String) -> T { + return Bundle.main.loadNibNamed(nibNamed, owner: nil, options: nil)!.first as! T + } + + class func nib() -> Self { + return viewInNibNamed(nameOfClass) + } + + class func nib(_ frame: CGRect) -> Self { + let view = nib() + view.frame = frame + view.layoutIfNeeded() + return view + } +} diff --git a/DinkleBot/DinkleBot/Factories/AuthModuleFactory.swift b/DinkleBot/DinkleBot/Factories/AuthModuleFactory.swift new file mode 100644 index 0000000..acc228e --- /dev/null +++ b/DinkleBot/DinkleBot/Factories/AuthModuleFactory.swift @@ -0,0 +1,5 @@ +protocol AuthModuleFactory { + func makeLoginOutput() -> LoginView + func makeSignUpHandler() -> SignUpView + func makeTermsOutput() -> TermsView +} diff --git a/DinkleBot/DinkleBot/Factories/CoordinatorFactory.swift b/DinkleBot/DinkleBot/Factories/CoordinatorFactory.swift new file mode 100644 index 0000000..784f165 --- /dev/null +++ b/DinkleBot/DinkleBot/Factories/CoordinatorFactory.swift @@ -0,0 +1,9 @@ +protocol CoordinatorFactory { + func makeTabbarCoordinator() -> (configurator: Coordinator, toPresent: Presentable?) + func makeAuthCoordinatorBox(router: Router) -> Coordinator & AuthCoordinatorOutput + func makeOnboardingCoordinator(router: Router) -> Coordinator & OnboardingCoordinatorOutput + func makeSettingsCoordinator() -> Coordinator + func makeSettingsCoordinator(navController: UINavigationController?) -> Coordinator + func makeHomeCoordinator() -> Coordinator + func makeHomeCoordinator(navController: UINavigationController?) -> Coordinator +} diff --git a/DinkleBot/DinkleBot/Factories/HomeModuleFactory.swift b/DinkleBot/DinkleBot/Factories/HomeModuleFactory.swift new file mode 100644 index 0000000..39b1df4 --- /dev/null +++ b/DinkleBot/DinkleBot/Factories/HomeModuleFactory.swift @@ -0,0 +1,3 @@ +protocol HomeModuleFactory { + func makeHomeOutput() -> HomeView +} diff --git a/DinkleBot/DinkleBot/Factories/Imp/CoordinatorFactoryImp.swift b/DinkleBot/DinkleBot/Factories/Imp/CoordinatorFactoryImp.swift new file mode 100644 index 0000000..84505d9 --- /dev/null +++ b/DinkleBot/DinkleBot/Factories/Imp/CoordinatorFactoryImp.swift @@ -0,0 +1,44 @@ +final class CoordinatorFactoryImp: CoordinatorFactory { + + func makeTabbarCoordinator() -> (configurator: Coordinator, toPresent: Presentable?) { + let controller = TabbarController.controllerFromStoryboard(.main) + let coordinator = TabbarCoordinator(tabbarView: controller, coordinatorFactory: CoordinatorFactoryImp()) + return (coordinator, controller) + } + + func makeAuthCoordinatorBox(router: Router) -> Coordinator & AuthCoordinatorOutput { + let coordinator = AuthCoordinator(router: router, factory: ModuleFactoryImp()) + return coordinator + } + + func makeOnboardingCoordinator(router: Router) -> Coordinator & OnboardingCoordinatorOutput { + return OnboardingCoordinator(with: ModuleFactoryImp(), router: router) + } + + func makeSettingsCoordinator() -> Coordinator { + return makeSettingsCoordinator(navController: nil) + } + + func makeSettingsCoordinator(navController: UINavigationController? = nil) -> Coordinator { + let coordinator = SettingsCoordinator(router: router(navController), factory: ModuleFactoryImp()) + return coordinator + } + + func makeHomeCoordinator() -> Coordinator { + return makeHomeCoordinator(navController: nil) + } + + func makeHomeCoordinator(navController: UINavigationController? = nil) -> Coordinator { + let coordinator = HomeCoordinator(router: router(navController), factory: ModuleFactoryImp()) + return coordinator + } + + private func router(_ navController: UINavigationController?) -> Router { + return RouterImp(rootController: navigationController(navController)) + } + + private func navigationController(_ navController: UINavigationController?) -> UINavigationController { + if let navController = navController { return navController } + else { return UINavigationController.controllerFromStoryboard(.main) } + } +} diff --git a/DinkleBot/DinkleBot/Factories/Imp/ModuleFactoryImp.swift b/DinkleBot/DinkleBot/Factories/Imp/ModuleFactoryImp.swift new file mode 100644 index 0000000..6607e59 --- /dev/null +++ b/DinkleBot/DinkleBot/Factories/Imp/ModuleFactoryImp.swift @@ -0,0 +1,30 @@ +final class ModuleFactoryImp: + AuthModuleFactory, + OnboardingModuleFactory, + SettingsModuleFactory, + HomeModuleFactory { + + func makeLoginOutput() -> LoginView { + return LoginController.controllerFromStoryboard(.auth) + } + + func makeSignUpHandler() -> SignUpView { + return SignUpController.controllerFromStoryboard(.auth) + } + + func makeTermsOutput() -> TermsView { + return TermsController.controllerFromStoryboard(.auth) + } + + func makeOnboardingModule() -> OnboardingView { + return OnboardingController.controllerFromStoryboard(.onboarding) + } + + func makeSettingsOutput() -> SettingsView { + return SettingsController.controllerFromStoryboard(.settings) + } + + func makeHomeOutput() -> HomeView { + return HomeController.controllerFromStoryboard(.home) + } +} diff --git a/DinkleBot/DinkleBot/Factories/OnboardingModuleFactory.swift b/DinkleBot/DinkleBot/Factories/OnboardingModuleFactory.swift new file mode 100644 index 0000000..8ed6770 --- /dev/null +++ b/DinkleBot/DinkleBot/Factories/OnboardingModuleFactory.swift @@ -0,0 +1,3 @@ +protocol OnboardingModuleFactory { + func makeOnboardingModule() -> OnboardingView +} diff --git a/DinkleBot/DinkleBot/Factories/SettingsModuleFactory.swift b/DinkleBot/DinkleBot/Factories/SettingsModuleFactory.swift new file mode 100644 index 0000000..3e243e4 --- /dev/null +++ b/DinkleBot/DinkleBot/Factories/SettingsModuleFactory.swift @@ -0,0 +1,3 @@ +protocol SettingsModuleFactory { + func makeSettingsOutput() -> SettingsView +} diff --git a/DinkleBot/DinkleBot/Flows/Home Flow/HomeController.swift b/DinkleBot/DinkleBot/Flows/Home Flow/HomeController.swift new file mode 100644 index 0000000..4653d23 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Home Flow/HomeController.swift @@ -0,0 +1,8 @@ +final class HomeController: UIViewController, HomeView { + + override func viewDidLoad() { + super.viewDidLoad() + + title = "Home" + } +} diff --git a/DinkleBot/DinkleBot/Flows/Home Flow/HomeCoordinator.swift b/DinkleBot/DinkleBot/Flows/Home Flow/HomeCoordinator.swift new file mode 100644 index 0000000..4071e9e --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Home Flow/HomeCoordinator.swift @@ -0,0 +1,21 @@ +final class HomeCoordinator: BaseCoordinator { + + private let factory: HomeModuleFactory + private let router: Router + + init(router: Router, factory: HomeModuleFactory) { + self.factory = factory + self.router = router + } + + override func start() { + showHome() + } + + //MARK: - Run current flow's controllers + + private func showHome() { + let homeFlowOutput = factory.makeHomeOutput() + router.setRootModule(homeFlowOutput) + } +} diff --git a/DinkleBot/DinkleBot/Flows/Home Flow/HomeView.swift b/DinkleBot/DinkleBot/Flows/Home Flow/HomeView.swift new file mode 100644 index 0000000..10f0b45 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Home Flow/HomeView.swift @@ -0,0 +1 @@ +protocol HomeView: BaseView { } diff --git a/DinkleBot/DinkleBot/Flows/Login flow/AuthCoordinator.swift b/DinkleBot/DinkleBot/Flows/Login flow/AuthCoordinator.swift new file mode 100644 index 0000000..1482b99 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Login flow/AuthCoordinator.swift @@ -0,0 +1,51 @@ +final class AuthCoordinator: BaseCoordinator, AuthCoordinatorOutput { + + var finishFlow: (() -> Void)? + + private let factory: AuthModuleFactory + private let router: Router + private weak var signUpView: SignUpView? + + init(router: Router, factory: AuthModuleFactory) { + self.factory = factory + self.router = router + } + + override func start() { + showLogin() + } + + //MARK: - Run current flow's controllers + + private func showLogin() { + let loginOutput = factory.makeLoginOutput() + loginOutput.onCompleteAuth = { [weak self] in + self?.finishFlow?() + } + loginOutput.onSignUpButtonTap = { [weak self] in + self?.showSignUp() + } + router.setRootModule(loginOutput) + } + + private func showSignUp() { + signUpView = factory.makeSignUpHandler() + signUpView?.onSignUpComplete = { [weak self] in + self?.finishFlow?() + } + signUpView?.onTermsButtonTap = { [weak self] in + self?.showTerms() + } + router.push(signUpView) + } + + private func showTerms() { + let termsOutput = factory.makeTermsOutput() + termsOutput.confirmed = self.signUpView?.confirmed ?? false + + termsOutput.onConfirmChanged = { [weak self] confirmed in + self?.signUpView?.conformTermsAgreement(confirmed) + } + router.push(termsOutput, animated: true) + } +} diff --git a/DinkleBot/DinkleBot/Flows/Login flow/AuthCoordinatorOutput.swift b/DinkleBot/DinkleBot/Flows/Login flow/AuthCoordinatorOutput.swift new file mode 100644 index 0000000..8da992e --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Login flow/AuthCoordinatorOutput.swift @@ -0,0 +1,3 @@ +protocol AuthCoordinatorOutput: class { + var finishFlow: (() -> Void)? { get set } +} diff --git a/DinkleBot/DinkleBot/Flows/Login flow/Controllers/LoginController.swift b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/LoginController.swift new file mode 100644 index 0000000..8b3b246 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/LoginController.swift @@ -0,0 +1,15 @@ +final class LoginController: UIViewController, LoginView { + + //controller handler + var onCompleteAuth: (() -> Void)? + var onSignUpButtonTap: (() -> Void)? + + @IBAction func loginButtonClicked(_ sender: AnyObject) { onCompleteAuth?() } + @IBAction func signUpClicked(_ sender: AnyObject) { onSignUpButtonTap?() } + + override func viewDidLoad() { + super.viewDidLoad() + + title = "Login" + } +} diff --git a/DinkleBot/DinkleBot/Flows/Login flow/Controllers/LoginView.swift b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/LoginView.swift new file mode 100644 index 0000000..0c08384 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/LoginView.swift @@ -0,0 +1,4 @@ +protocol LoginView: BaseView { + var onCompleteAuth: (() -> Void)? { get set } + var onSignUpButtonTap: (() -> Void)? { get set } +} diff --git a/DinkleBot/DinkleBot/Flows/Login flow/Controllers/SignUpController.swift b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/SignUpController.swift new file mode 100644 index 0000000..4f232f9 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/SignUpController.swift @@ -0,0 +1,38 @@ +final class SignUpController: UIViewController, SignUpView { + + //controller handler + var onSignUpComplete: (() -> Void)? + var onTermsButtonTap: (() -> Void)? + + @IBOutlet weak var termsLabel: UILabel! + @IBOutlet weak var signUpButton: UIButton! + + var confirmed = false { + didSet { + termsLabel.isHidden = !confirmed + signUpButton.isEnabled = confirmed + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + title = "SignUp" + termsLabel.isHidden = true + signUpButton.isEnabled = false + } + + @IBAction func signUpClicked(_ sender: AnyObject) { + if confirmed { + onSignUpComplete?() + } + } + + @IBAction func termsButtonClicked(_ sender: AnyObject) { + onTermsButtonTap?() + } + + func conformTermsAgreement(_ agree: Bool) { + confirmed = agree + } +} diff --git a/DinkleBot/DinkleBot/Flows/Login flow/Controllers/SignUpView.swift b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/SignUpView.swift new file mode 100644 index 0000000..ddd304f --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/SignUpView.swift @@ -0,0 +1,8 @@ +protocol SignUpView: BaseView { + + var confirmed: Bool { get set } + var onSignUpComplete: (() -> Void)? { get set } + var onTermsButtonTap: (() -> Void)? { get set } + + func conformTermsAgreement(_ agree: Bool) +} diff --git a/DinkleBot/DinkleBot/Flows/Login flow/Controllers/TermsController.swift b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/TermsController.swift new file mode 100644 index 0000000..d81e73a --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/TermsController.swift @@ -0,0 +1,12 @@ +class TermsController: UIViewController, TermsView { + + @IBOutlet weak var termsSwitch: UISwitch! { + didSet { termsSwitch.isOn = confirmed } + } + var confirmed = false + var onConfirmChanged: ((Bool) -> ())? + + @IBAction func termsSwitchValueChanged(_ sender: UISwitch) { + onConfirmChanged?(sender.isOn) + } +} diff --git a/DinkleBot/DinkleBot/Flows/Login flow/Controllers/TermsView.swift b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/TermsView.swift new file mode 100644 index 0000000..3deac8f --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Login flow/Controllers/TermsView.swift @@ -0,0 +1,5 @@ +protocol TermsView: BaseView { + + var confirmed: Bool { get set } + var onConfirmChanged: ((Bool) -> ())? { get set } +} diff --git a/DinkleBot/DinkleBot/Flows/MainTabbarFlow/TabbarController.swift b/DinkleBot/DinkleBot/Flows/MainTabbarFlow/TabbarController.swift new file mode 100644 index 0000000..69fa61b --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/MainTabbarFlow/TabbarController.swift @@ -0,0 +1,26 @@ +final class TabbarController: UITabBarController, UITabBarControllerDelegate, TabbarView { + + var onItemFlowSelect: ((UINavigationController) -> ())? + var onSettingsFlowSelect: ((UINavigationController) -> ())? + var onViewDidLoad: ((UINavigationController) -> ())? + + override func viewDidLoad() { + super.viewDidLoad() + + delegate = self + if let controller = customizableViewControllers?.first as? UINavigationController { + onViewDidLoad?(controller) + } + } + + func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { + guard let controller = viewControllers?[selectedIndex] as? UINavigationController else { return } + + if selectedIndex == 0 { + onItemFlowSelect?(controller) + } + else if selectedIndex == 1 { + onSettingsFlowSelect?(controller) + } + } +} diff --git a/DinkleBot/DinkleBot/Flows/MainTabbarFlow/TabbarCoordinator.swift b/DinkleBot/DinkleBot/Flows/MainTabbarFlow/TabbarCoordinator.swift new file mode 100644 index 0000000..d035f53 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/MainTabbarFlow/TabbarCoordinator.swift @@ -0,0 +1,36 @@ +class TabbarCoordinator: BaseCoordinator { + + private let tabbarView: TabbarView + private let coordinatorFactory: CoordinatorFactory + + init(tabbarView: TabbarView, coordinatorFactory: CoordinatorFactory) { + self.tabbarView = tabbarView + self.coordinatorFactory = coordinatorFactory + } + + override func start() { + tabbarView.onViewDidLoad = runItemFlow() + tabbarView.onItemFlowSelect = runItemFlow() + tabbarView.onSettingsFlowSelect = runSettingsFlow() + } + + private func runItemFlow() -> ((UINavigationController) -> ()) { + return { [unowned self] navController in + if navController.viewControllers.isEmpty == true { + let itemCoordinator = self.coordinatorFactory.makeHomeCoordinator(navController: navController) + self.addDependency(itemCoordinator) + itemCoordinator.start() + } + } + } + + private func runSettingsFlow() -> ((UINavigationController) -> ()) { + return { [unowned self] navController in + if navController.viewControllers.isEmpty == true { + let settingsCoordinator = self.coordinatorFactory.makeSettingsCoordinator(navController: navController) + self.addDependency(settingsCoordinator) + settingsCoordinator.start() + } + } + } +} diff --git a/DinkleBot/DinkleBot/Flows/MainTabbarFlow/TabbarView.swift b/DinkleBot/DinkleBot/Flows/MainTabbarFlow/TabbarView.swift new file mode 100644 index 0000000..85572a1 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/MainTabbarFlow/TabbarView.swift @@ -0,0 +1,5 @@ +protocol TabbarView: class { + var onItemFlowSelect: ((UINavigationController) -> ())? { get set } + var onSettingsFlowSelect: ((UINavigationController) -> ())? { get set } + var onViewDidLoad: ((UINavigationController) -> ())? { get set } +} diff --git a/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/OnboardingController.swift b/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/OnboardingController.swift new file mode 100644 index 0000000..a5a5b1f --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/OnboardingController.swift @@ -0,0 +1,12 @@ +class OnboardingController: UIViewController, OnboardingView { + + var onFinish: (() -> Void)? + + override func viewDidLoad() { + super.viewDidLoad() + } + + @IBAction func finishTapped(_ sender: Any) { + onFinish?() + } +} diff --git a/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/OnboardingView.swift b/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/OnboardingView.swift new file mode 100644 index 0000000..329fb98 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/OnboardingView.swift @@ -0,0 +1,3 @@ +protocol OnboardingView: BaseView { + var onFinish: (() -> Void)? { get set } +} diff --git a/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/PageViewController.swift b/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/PageViewController.swift new file mode 100755 index 0000000..a7249db --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/PageViewController.swift @@ -0,0 +1,38 @@ +class PageController: UIViewController { + + var pageViewController: UIPageViewController! + + override func viewDidLoad() { + super.viewDidLoad() + + pageViewController = UIPageViewController( + transitionStyle: .scroll, + navigationOrientation: .horizontal, + options: nil + ) + pageViewController.delegate = self + addChild(pageViewController) + view.addSubview(pageViewController.view) + } +} + +extension PageController: UIPageViewControllerDelegate, UIPageViewControllerDataSource { + + func pageViewController(_ pageViewController: UIPageViewController, + viewControllerBefore viewController: UIViewController) -> UIViewController? { + return UIViewController() + } + + func pageViewController(_ pageViewController: UIPageViewController, + viewControllerAfter viewController: UIViewController) -> UIViewController? { + return UIViewController() + } + + func presentationCount(for pageViewController: UIPageViewController) -> Int { + return 3 + } + + func presentationIndex(for pageViewController: UIPageViewController) -> Int { + return 2 + } +} diff --git a/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/StepController.swift b/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/StepController.swift new file mode 100644 index 0000000..c92e519 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/OnboardingFlow/Controllers/StepController.swift @@ -0,0 +1,18 @@ +class StepController: UIViewController { + + @IBOutlet weak var titleLabel: UILabel! + var titleText: String? { + get { return titleLabel.text } + set { titleLabel.text = newValue } + } + + override func viewDidLoad() { + super.viewDidLoad() + } + + @IBAction func skipTapped(_ sender: Any) { + } + + @IBAction func nextTapped(_ sender: Any) { + } +} diff --git a/DinkleBot/DinkleBot/Flows/OnboardingFlow/OnboardingCoordinator.swift b/DinkleBot/DinkleBot/Flows/OnboardingFlow/OnboardingCoordinator.swift new file mode 100644 index 0000000..41a896c --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/OnboardingFlow/OnboardingCoordinator.swift @@ -0,0 +1,24 @@ +class OnboardingCoordinator: BaseCoordinator, OnboardingCoordinatorOutput { + + var finishFlow: (() -> Void)? + + private let factory: OnboardingModuleFactory + private let router: Router + + init(with factory: OnboardingModuleFactory, router: Router) { + self.factory = factory + self.router = router + } + + override func start() { + showOnboarding() + } + + func showOnboarding() { + let onboardingModule = factory.makeOnboardingModule() + onboardingModule.onFinish = { [weak self] in + self?.finishFlow?() + } + router.setRootModule(onboardingModule.toPresent()) + } +} diff --git a/DinkleBot/DinkleBot/Flows/OnboardingFlow/OnboardingCoordinatorOutput.swift b/DinkleBot/DinkleBot/Flows/OnboardingFlow/OnboardingCoordinatorOutput.swift new file mode 100644 index 0000000..80cb931 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/OnboardingFlow/OnboardingCoordinatorOutput.swift @@ -0,0 +1,3 @@ +protocol OnboardingCoordinatorOutput: class { + var finishFlow: (() -> Void)? { get set } +} diff --git a/DinkleBot/DinkleBot/Flows/Settings flow/Setting.swift b/DinkleBot/DinkleBot/Flows/Settings flow/Setting.swift new file mode 100644 index 0000000..45847b4 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Settings flow/Setting.swift @@ -0,0 +1,5 @@ +struct Setting { + + let title: String + let subtitle: String +} diff --git a/DinkleBot/DinkleBot/Flows/Settings flow/SettingsController.swift b/DinkleBot/DinkleBot/Flows/Settings flow/SettingsController.swift new file mode 100644 index 0000000..a07b13c --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Settings flow/SettingsController.swift @@ -0,0 +1,43 @@ +final class SettingsController: UIViewController, SettingsView { + + //controller handler + + @IBOutlet weak var tableView: UITableView! + //mock datasource + var settings: [[Setting]] = [[]] + + override func viewDidLoad() { + super.viewDidLoad() + + title = "Settings" + makeMockData() + } + + func makeMockData() { + + let settings1 = (0...3).map { index in return Setting(title: "Setting № \(index)", subtitle: "Setting descripton") } + let settings2 = (0...5).map { index in return Setting(title: "Setting № \(index)", subtitle: "Setting descripton") } + settings.append(settings1) + settings.append(settings2) + } +} + +extension SettingsController: UITableViewDelegate, UITableViewDataSource { + + func numberOfSections(in tableView: UITableView) -> Int { + return settings.count + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return settings[section].count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) + + let setting = settings[(indexPath as NSIndexPath).section][(indexPath as NSIndexPath).row] + cell.textLabel?.text = setting.title + cell.detailTextLabel?.text = setting.subtitle + return cell + } +} diff --git a/DinkleBot/DinkleBot/Flows/Settings flow/SettingsCoordinator.swift b/DinkleBot/DinkleBot/Flows/Settings flow/SettingsCoordinator.swift new file mode 100644 index 0000000..36c1984 --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Settings flow/SettingsCoordinator.swift @@ -0,0 +1,21 @@ +final class SettingsCoordinator: BaseCoordinator { + + private let factory: SettingsModuleFactory + private let router: Router + + init(router: Router, factory: SettingsModuleFactory) { + self.factory = factory + self.router = router + } + + override func start() { + showSettings() + } + + //MARK: - Run current flow's controllers + + private func showSettings() { + let settingsFlowOutput = factory.makeSettingsOutput() + router.setRootModule(settingsFlowOutput) + } +} diff --git a/DinkleBot/DinkleBot/Flows/Settings flow/SettingsView.swift b/DinkleBot/DinkleBot/Flows/Settings flow/SettingsView.swift new file mode 100644 index 0000000..57e92af --- /dev/null +++ b/DinkleBot/DinkleBot/Flows/Settings flow/SettingsView.swift @@ -0,0 +1,2 @@ +protocol SettingsView: BaseView { } + diff --git a/DinkleBot/DinkleBot/Protocols/BaseView.swift b/DinkleBot/DinkleBot/Protocols/BaseView.swift new file mode 100644 index 0000000..2c1c3ba --- /dev/null +++ b/DinkleBot/DinkleBot/Protocols/BaseView.swift @@ -0,0 +1 @@ +protocol BaseView: NSObjectProtocol, Presentable { } diff --git a/DinkleBot/DinkleBot/Protocols/Coordinator.swift b/DinkleBot/DinkleBot/Protocols/Coordinator.swift new file mode 100644 index 0000000..183e898 --- /dev/null +++ b/DinkleBot/DinkleBot/Protocols/Coordinator.swift @@ -0,0 +1,4 @@ +protocol Coordinator: class { + func start() + func start(with option: DeepLinkOption?) +} diff --git a/DinkleBot/DinkleBot/Protocols/DeepLinkOption.swift b/DinkleBot/DinkleBot/Protocols/DeepLinkOption.swift new file mode 100644 index 0000000..0d80ccd --- /dev/null +++ b/DinkleBot/DinkleBot/Protocols/DeepLinkOption.swift @@ -0,0 +1,36 @@ +struct DeepLinkURLConstants { + static let Login = "login" + static let Terms = "terms" + static let SignUp = "signUp" +} + +enum DeepLinkOption { + + case onboarding + case items + case settings + case login + case terms + case signUp + case item(String?) + + static func build(with userActivity: NSUserActivity) -> DeepLinkOption? { + if userActivity.activityType == NSUserActivityTypeBrowsingWeb, + let url = userActivity.webpageURL, + let _ = URLComponents(url: url, resolvingAgainstBaseURL: true) { + //TODO: extract string and match with DeepLinkURLConstants + } + return nil + } + + static func build(with dict: [String : AnyObject]?) -> DeepLinkOption? { + guard let id = dict?["launch_id"] as? String else { return nil } + + switch id { + case DeepLinkURLConstants.Login: return .login + case DeepLinkURLConstants.Terms: return .terms + case DeepLinkURLConstants.SignUp: return .signUp + default: return nil + } + } +} diff --git a/DinkleBot/DinkleBot/Protocols/Presentable.swift b/DinkleBot/DinkleBot/Protocols/Presentable.swift new file mode 100644 index 0000000..72bf57d --- /dev/null +++ b/DinkleBot/DinkleBot/Protocols/Presentable.swift @@ -0,0 +1,10 @@ +protocol Presentable { + func toPresent() -> UIViewController? +} + +extension UIViewController: Presentable { + + func toPresent() -> UIViewController? { + return self + } +} diff --git a/DinkleBot/DinkleBot/Assets.xcassets/AccentColor.colorset/Contents.json b/DinkleBot/DinkleBot/Resources/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from DinkleBot/DinkleBot/Assets.xcassets/AccentColor.colorset/Contents.json rename to DinkleBot/DinkleBot/Resources/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/DinkleBot/DinkleBot/Assets.xcassets/AppIcon.appiconset/Contents.json b/DinkleBot/DinkleBot/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from DinkleBot/DinkleBot/Assets.xcassets/AppIcon.appiconset/Contents.json rename to DinkleBot/DinkleBot/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/DinkleBot/DinkleBot/Assets.xcassets/Contents.json b/DinkleBot/DinkleBot/Resources/Assets.xcassets/Contents.json similarity index 100% rename from DinkleBot/DinkleBot/Assets.xcassets/Contents.json rename to DinkleBot/DinkleBot/Resources/Assets.xcassets/Contents.json diff --git a/DinkleBot/DinkleBot/Base.lproj/LaunchScreen.storyboard b/DinkleBot/DinkleBot/Resources/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from DinkleBot/DinkleBot/Base.lproj/LaunchScreen.storyboard rename to DinkleBot/DinkleBot/Resources/Base.lproj/LaunchScreen.storyboard diff --git a/DinkleBot/DinkleBot/Resources/DinkleBot-Bridging-Header.h b/DinkleBot/DinkleBot/Resources/DinkleBot-Bridging-Header.h new file mode 100644 index 0000000..50a16a5 --- /dev/null +++ b/DinkleBot/DinkleBot/Resources/DinkleBot-Bridging-Header.h @@ -0,0 +1 @@ +@import UIKit; diff --git a/DinkleBot/DinkleBot/Info.plist b/DinkleBot/DinkleBot/Resources/Info.plist similarity index 98% rename from DinkleBot/DinkleBot/Info.plist rename to DinkleBot/DinkleBot/Resources/Info.plist index 27cda5f..af8868b 100644 --- a/DinkleBot/DinkleBot/Info.plist +++ b/DinkleBot/DinkleBot/Resources/Info.plist @@ -23,7 +23,7 @@ UILaunchStoryboardName LaunchScreen UIMainStoryboardFile - Home + Main UIRequiredDeviceCapabilities armv7 diff --git a/DinkleBot/DinkleBot/Routers/Router.swift b/DinkleBot/DinkleBot/Routers/Router.swift new file mode 100644 index 0000000..21784e0 --- /dev/null +++ b/DinkleBot/DinkleBot/Routers/Router.swift @@ -0,0 +1,22 @@ +protocol Router: Presentable { + + func present(_ module: Presentable?) + func present(_ module: Presentable?, animated: Bool) + + func push(_ module: Presentable?) + func push(_ module: Presentable?, hideBottomBar: Bool) + func push(_ module: Presentable?, animated: Bool) + func push(_ module: Presentable?, animated: Bool, completion: (() -> Void)?) + func push(_ module: Presentable?, animated: Bool, hideBottomBar: Bool, completion: (() -> Void)?) + + func popModule() + func popModule(animated: Bool) + + func dismissModule() + func dismissModule(animated: Bool, completion: (() -> Void)?) + + func setRootModule(_ module: Presentable?) + func setRootModule(_ module: Presentable?, hideBar: Bool) + + func popToRootModule(animated: Bool) +} diff --git a/DinkleBot/DinkleBot/Routers/RouterImp.swift b/DinkleBot/DinkleBot/Routers/RouterImp.swift new file mode 100644 index 0000000..4326250 --- /dev/null +++ b/DinkleBot/DinkleBot/Routers/RouterImp.swift @@ -0,0 +1,94 @@ +final class RouterImp: NSObject, Router { + + private weak var rootController: UINavigationController? + private var completions: [UIViewController : () -> Void] + + init(rootController: UINavigationController) { + self.rootController = rootController + completions = [:] + } + + func toPresent() -> UIViewController? { + return rootController + } + + func present(_ module: Presentable?) { + present(module, animated: true) + } + + func present(_ module: Presentable?, animated: Bool) { + guard let controller = module?.toPresent() else { return } + rootController?.present(controller, animated: animated, completion: nil) + } + + func dismissModule() { + dismissModule(animated: true, completion: nil) + } + + func dismissModule(animated: Bool, completion: (() -> Void)?) { + rootController?.dismiss(animated: animated, completion: completion) + } + + func push(_ module: Presentable?) { + push(module, animated: true) + } + + func push(_ module: Presentable?, hideBottomBar: Bool) { + push(module, animated: true, hideBottomBar: hideBottomBar, completion: nil) + } + + func push(_ module: Presentable?, animated: Bool) { + push(module, animated: animated, completion: nil) + } + + func push(_ module: Presentable?, animated: Bool, completion: (() -> Void)?) { + push(module, animated: animated, hideBottomBar: false, completion: completion) + } + + func push(_ module: Presentable?, animated: Bool, hideBottomBar: Bool, completion: (() -> Void)?) { + guard + let controller = module?.toPresent(), + (controller is UINavigationController == false) + else { assertionFailure("Deprecated push UINavigationController."); return } + + if let completion = completion { + completions[controller] = completion + } + controller.hidesBottomBarWhenPushed = hideBottomBar + rootController?.pushViewController(controller, animated: animated) + } + + func popModule() { + popModule(animated: true) + } + + func popModule(animated: Bool) { + if let controller = rootController?.popViewController(animated: animated) { + runCompletion(for: controller) + } + } + + func setRootModule(_ module: Presentable?) { + setRootModule(module, hideBar: false) + } + + func setRootModule(_ module: Presentable?, hideBar: Bool) { + guard let controller = module?.toPresent() else { return } + rootController?.setViewControllers([controller], animated: false) + rootController?.isNavigationBarHidden = hideBar + } + + func popToRootModule(animated: Bool) { + if let controllers = rootController?.popToRootViewController(animated: animated) { + controllers.forEach { controller in + runCompletion(for: controller) + } + } + } + + private func runCompletion(for controller: UIViewController) { + guard let completion = completions[controller] else { return } + completion() + completions.removeValue(forKey: controller) + } +} diff --git a/DinkleBot/DinkleBot/Storyboards/Auth.storyboard b/DinkleBot/DinkleBot/Storyboards/Auth.storyboard new file mode 100644 index 0000000..8cdae43 --- /dev/null +++ b/DinkleBot/DinkleBot/Storyboards/Auth.storyboard @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DinkleBot/DinkleBot/Storyboards/Home.storyboard b/DinkleBot/DinkleBot/Storyboards/Home.storyboard new file mode 100644 index 0000000..2440bf6 --- /dev/null +++ b/DinkleBot/DinkleBot/Storyboards/Home.storyboard @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DinkleBot/DinkleBot/Storyboards/Main.storyboard b/DinkleBot/DinkleBot/Storyboards/Main.storyboard new file mode 100644 index 0000000..c900352 --- /dev/null +++ b/DinkleBot/DinkleBot/Storyboards/Main.storyboard @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DinkleBot/DinkleBot/Storyboards/Onboarding.storyboard b/DinkleBot/DinkleBot/Storyboards/Onboarding.storyboard new file mode 100644 index 0000000..c21e948 --- /dev/null +++ b/DinkleBot/DinkleBot/Storyboards/Onboarding.storyboard @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DinkleBot/DinkleBot/Storyboards/Settings.storyboard b/DinkleBot/DinkleBot/Storyboards/Settings.storyboard new file mode 100644 index 0000000..5ac3747 --- /dev/null +++ b/DinkleBot/DinkleBot/Storyboards/Settings.storyboard @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DinkleBot/DinkleBot/Storyboards/StoryboardsEnum.swift b/DinkleBot/DinkleBot/Storyboards/StoryboardsEnum.swift new file mode 100644 index 0000000..7c21cd0 --- /dev/null +++ b/DinkleBot/DinkleBot/Storyboards/StoryboardsEnum.swift @@ -0,0 +1,7 @@ +enum Storyboards: String { + case main = "Main" + case auth = "Auth" + case onboarding = "Onboarding" + case settings = "Settings" + case home = "Home" +} diff --git a/DinkleBot/DinkleBot/Views/Other.storyboard b/DinkleBot/DinkleBot/Views/Other.storyboard deleted file mode 100644 index 70f2e07..0000000 --- a/DinkleBot/DinkleBot/Views/Other.storyboard +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -