├── .gitignore ├── FrogsGuideBook ├── FrogsGuideBook.xcodeproj │ └── project.pbxproj ├── FrogsGuideBook │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── blue-poison-dart-frog.imageset │ │ │ ├── Contents.json │ │ │ └── blue-poison-dart-frog.jpg │ │ ├── frog-logo.imageset │ │ │ ├── Contents.json │ │ │ └── frog-logo.png │ │ ├── red-eyed-tree-frog.imageset │ │ │ ├── Contents.json │ │ │ └── red-eyed-tree-frog.jpg │ │ └── toad.imageset │ │ │ ├── Contents.json │ │ │ └── toad.jpg │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Entities │ │ ├── AppState.swift │ │ └── Frog.swift │ ├── Info.plist │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── SceneDelegate.swift │ ├── Scenes │ │ ├── FrogsDetail │ │ │ ├── FrogDetailPresenter.swift │ │ │ └── FrogDetailView.swift │ │ ├── FrogsList │ │ │ ├── FrogsListPresenter.swift │ │ │ ├── FrogsListRouter.swift │ │ │ └── FrogsListView.swift │ │ ├── HomeTab │ │ │ └── HomeTabView.swift │ │ ├── Login │ │ │ ├── LoginPresenter.swift │ │ │ └── LoginView.swift │ │ ├── Root │ │ │ └── RootView.swift │ │ └── Setting │ │ │ ├── SettingPresenter.swift │ │ │ ├── SettingRouter.swift │ │ │ └── SettingView.swift │ └── ViewComponent │ │ ├── BlurView.swift │ │ ├── ImageCard.swift │ │ └── WebView.swift ├── FrogsGuideBookTests │ ├── FrogsGuideBookTests.swift │ └── Info.plist └── FrogsGuideBookUITests │ ├── FrogsGuideBookUITests.swift │ └── Info.plist ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 304D506224796103003BFFC4 /* ImageCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 304D506124796103003BFFC4 /* ImageCard.swift */; }; 11 | 304D5064247961C2003BFFC4 /* BlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 304D5063247961C2003BFFC4 /* BlurView.swift */; }; 12 | 304D5066247968F1003BFFC4 /* Frog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 304D5065247968F1003BFFC4 /* Frog.swift */; }; 13 | 304D5068247A1CD6003BFFC4 /* SettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 304D5067247A1CD6003BFFC4 /* SettingView.swift */; }; 14 | 304D506B247A210C003BFFC4 /* SettingPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 304D506A247A210C003BFFC4 /* SettingPresenter.swift */; }; 15 | 304D506D247A2223003BFFC4 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 304D506C247A2223003BFFC4 /* WebView.swift */; }; 16 | 304D506F247A26BE003BFFC4 /* SettingRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 304D506E247A26BE003BFFC4 /* SettingRouter.swift */; }; 17 | 308F9CA5247A6EDB0017C494 /* FrogDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308F9CA4247A6EDB0017C494 /* FrogDetailView.swift */; }; 18 | 308F9CA7247A79DD0017C494 /* FrogDetailPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308F9CA6247A79DD0017C494 /* FrogDetailPresenter.swift */; }; 19 | 308F9CAA247AA3740017C494 /* HomeTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 308F9CA9247AA3740017C494 /* HomeTabView.swift */; }; 20 | 30E239AF2478F5DA00FB9E5A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239AE2478F5DA00FB9E5A /* AppDelegate.swift */; }; 21 | 30E239B12478F5DA00FB9E5A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239B02478F5DA00FB9E5A /* SceneDelegate.swift */; }; 22 | 30E239B32478F5DA00FB9E5A /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239B22478F5DA00FB9E5A /* RootView.swift */; }; 23 | 30E239B52478F5DC00FB9E5A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 30E239B42478F5DC00FB9E5A /* Assets.xcassets */; }; 24 | 30E239B82478F5DC00FB9E5A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 30E239B72478F5DC00FB9E5A /* Preview Assets.xcassets */; }; 25 | 30E239BB2478F5DC00FB9E5A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 30E239B92478F5DC00FB9E5A /* LaunchScreen.storyboard */; }; 26 | 30E239C62478F5DC00FB9E5A /* FrogsGuideBookTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239C52478F5DC00FB9E5A /* FrogsGuideBookTests.swift */; }; 27 | 30E239D12478F5DC00FB9E5A /* FrogsGuideBookUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239D02478F5DC00FB9E5A /* FrogsGuideBookUITests.swift */; }; 28 | 30E239E12478FAAA00FB9E5A /* FrogsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239E02478FAAA00FB9E5A /* FrogsListView.swift */; }; 29 | 30E239E32478FABC00FB9E5A /* FrogsListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239E22478FABC00FB9E5A /* FrogsListPresenter.swift */; }; 30 | 30E239E52478FAD500FB9E5A /* FrogsListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239E42478FAD500FB9E5A /* FrogsListRouter.swift */; }; 31 | 30E239E92479166700FB9E5A /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239E82479166700FB9E5A /* LoginView.swift */; }; 32 | 30E239EB24791AFB00FB9E5A /* LoginPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239EA24791AFB00FB9E5A /* LoginPresenter.swift */; }; 33 | 30E239F024791D8A00FB9E5A /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E239EF24791D8A00FB9E5A /* AppState.swift */; }; 34 | /* End PBXBuildFile section */ 35 | 36 | /* Begin PBXContainerItemProxy section */ 37 | 30E239C22478F5DC00FB9E5A /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = 30E239A32478F5DA00FB9E5A /* Project object */; 40 | proxyType = 1; 41 | remoteGlobalIDString = 30E239AA2478F5DA00FB9E5A; 42 | remoteInfo = FrogsGuideBook; 43 | }; 44 | 30E239CD2478F5DC00FB9E5A /* PBXContainerItemProxy */ = { 45 | isa = PBXContainerItemProxy; 46 | containerPortal = 30E239A32478F5DA00FB9E5A /* Project object */; 47 | proxyType = 1; 48 | remoteGlobalIDString = 30E239AA2478F5DA00FB9E5A; 49 | remoteInfo = FrogsGuideBook; 50 | }; 51 | /* End PBXContainerItemProxy section */ 52 | 53 | /* Begin PBXFileReference section */ 54 | 304D506124796103003BFFC4 /* ImageCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCard.swift; sourceTree = ""; }; 55 | 304D5063247961C2003BFFC4 /* BlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurView.swift; sourceTree = ""; }; 56 | 304D5065247968F1003BFFC4 /* Frog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Frog.swift; sourceTree = ""; }; 57 | 304D5067247A1CD6003BFFC4 /* SettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingView.swift; sourceTree = ""; }; 58 | 304D506A247A210C003BFFC4 /* SettingPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingPresenter.swift; sourceTree = ""; }; 59 | 304D506C247A2223003BFFC4 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; 60 | 304D506E247A26BE003BFFC4 /* SettingRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingRouter.swift; sourceTree = ""; }; 61 | 308F9CA4247A6EDB0017C494 /* FrogDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrogDetailView.swift; sourceTree = ""; }; 62 | 308F9CA6247A79DD0017C494 /* FrogDetailPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrogDetailPresenter.swift; sourceTree = ""; }; 63 | 308F9CA9247AA3740017C494 /* HomeTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTabView.swift; sourceTree = ""; }; 64 | 30E239AB2478F5DA00FB9E5A /* FrogsGuideBook.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FrogsGuideBook.app; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 30E239AE2478F5DA00FB9E5A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 66 | 30E239B02478F5DA00FB9E5A /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 67 | 30E239B22478F5DA00FB9E5A /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = ""; }; 68 | 30E239B42478F5DC00FB9E5A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 69 | 30E239B72478F5DC00FB9E5A /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 70 | 30E239BA2478F5DC00FB9E5A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 71 | 30E239BC2478F5DC00FB9E5A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 72 | 30E239C12478F5DC00FB9E5A /* FrogsGuideBookTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FrogsGuideBookTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | 30E239C52478F5DC00FB9E5A /* FrogsGuideBookTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrogsGuideBookTests.swift; sourceTree = ""; }; 74 | 30E239C72478F5DC00FB9E5A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 75 | 30E239CC2478F5DC00FB9E5A /* FrogsGuideBookUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FrogsGuideBookUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 76 | 30E239D02478F5DC00FB9E5A /* FrogsGuideBookUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrogsGuideBookUITests.swift; sourceTree = ""; }; 77 | 30E239D22478F5DC00FB9E5A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 78 | 30E239E02478FAAA00FB9E5A /* FrogsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrogsListView.swift; sourceTree = ""; }; 79 | 30E239E22478FABC00FB9E5A /* FrogsListPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrogsListPresenter.swift; sourceTree = ""; }; 80 | 30E239E42478FAD500FB9E5A /* FrogsListRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrogsListRouter.swift; sourceTree = ""; }; 81 | 30E239E82479166700FB9E5A /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; 82 | 30E239EA24791AFB00FB9E5A /* LoginPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginPresenter.swift; sourceTree = ""; }; 83 | 30E239EF24791D8A00FB9E5A /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; 84 | /* End PBXFileReference section */ 85 | 86 | /* Begin PBXFrameworksBuildPhase section */ 87 | 30E239A82478F5DA00FB9E5A /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | 30E239BE2478F5DC00FB9E5A /* Frameworks */ = { 95 | isa = PBXFrameworksBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | 30E239C92478F5DC00FB9E5A /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | /* End PBXFrameworksBuildPhase section */ 109 | 110 | /* Begin PBXGroup section */ 111 | 304D506024796041003BFFC4 /* ViewComponent */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 304D506124796103003BFFC4 /* ImageCard.swift */, 115 | 304D5063247961C2003BFFC4 /* BlurView.swift */, 116 | 304D506C247A2223003BFFC4 /* WebView.swift */, 117 | ); 118 | path = ViewComponent; 119 | sourceTree = ""; 120 | }; 121 | 304D5069247A1CDB003BFFC4 /* Setting */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 304D5067247A1CD6003BFFC4 /* SettingView.swift */, 125 | 304D506A247A210C003BFFC4 /* SettingPresenter.swift */, 126 | 304D506E247A26BE003BFFC4 /* SettingRouter.swift */, 127 | ); 128 | path = Setting; 129 | sourceTree = ""; 130 | }; 131 | 308F9CA8247AA3610017C494 /* HomeTab */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 308F9CA9247AA3740017C494 /* HomeTabView.swift */, 135 | ); 136 | path = HomeTab; 137 | sourceTree = ""; 138 | }; 139 | 30E239A22478F5DA00FB9E5A = { 140 | isa = PBXGroup; 141 | children = ( 142 | 30E239AD2478F5DA00FB9E5A /* FrogsGuideBook */, 143 | 30E239C42478F5DC00FB9E5A /* FrogsGuideBookTests */, 144 | 30E239CF2478F5DC00FB9E5A /* FrogsGuideBookUITests */, 145 | 30E239AC2478F5DA00FB9E5A /* Products */, 146 | ); 147 | sourceTree = ""; 148 | }; 149 | 30E239AC2478F5DA00FB9E5A /* Products */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 30E239AB2478F5DA00FB9E5A /* FrogsGuideBook.app */, 153 | 30E239C12478F5DC00FB9E5A /* FrogsGuideBookTests.xctest */, 154 | 30E239CC2478F5DC00FB9E5A /* FrogsGuideBookUITests.xctest */, 155 | ); 156 | name = Products; 157 | sourceTree = ""; 158 | }; 159 | 30E239AD2478F5DA00FB9E5A /* FrogsGuideBook */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 30E239AE2478F5DA00FB9E5A /* AppDelegate.swift */, 163 | 30E239B02478F5DA00FB9E5A /* SceneDelegate.swift */, 164 | 30E239DE2478F8C800FB9E5A /* Scenes */, 165 | 304D506024796041003BFFC4 /* ViewComponent */, 166 | 30E239EE24791D5300FB9E5A /* Entities */, 167 | 30E239B42478F5DC00FB9E5A /* Assets.xcassets */, 168 | 30E239B92478F5DC00FB9E5A /* LaunchScreen.storyboard */, 169 | 30E239BC2478F5DC00FB9E5A /* Info.plist */, 170 | 30E239B62478F5DC00FB9E5A /* Preview Content */, 171 | ); 172 | path = FrogsGuideBook; 173 | sourceTree = ""; 174 | }; 175 | 30E239B62478F5DC00FB9E5A /* Preview Content */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 30E239B72478F5DC00FB9E5A /* Preview Assets.xcassets */, 179 | ); 180 | path = "Preview Content"; 181 | sourceTree = ""; 182 | }; 183 | 30E239C42478F5DC00FB9E5A /* FrogsGuideBookTests */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 30E239C52478F5DC00FB9E5A /* FrogsGuideBookTests.swift */, 187 | 30E239C72478F5DC00FB9E5A /* Info.plist */, 188 | ); 189 | path = FrogsGuideBookTests; 190 | sourceTree = ""; 191 | }; 192 | 30E239CF2478F5DC00FB9E5A /* FrogsGuideBookUITests */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | 30E239D02478F5DC00FB9E5A /* FrogsGuideBookUITests.swift */, 196 | 30E239D22478F5DC00FB9E5A /* Info.plist */, 197 | ); 198 | path = FrogsGuideBookUITests; 199 | sourceTree = ""; 200 | }; 201 | 30E239DE2478F8C800FB9E5A /* Scenes */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | 308F9CA8247AA3610017C494 /* HomeTab */, 205 | 304D5069247A1CDB003BFFC4 /* Setting */, 206 | 30E239F1247920DA00FB9E5A /* Root */, 207 | 30E239E72479165200FB9E5A /* Login */, 208 | 30E239DF2478F95B00FB9E5A /* FrogsList */, 209 | 30E239E62479114000FB9E5A /* FrogsDetail */, 210 | ); 211 | path = Scenes; 212 | sourceTree = ""; 213 | }; 214 | 30E239DF2478F95B00FB9E5A /* FrogsList */ = { 215 | isa = PBXGroup; 216 | children = ( 217 | 30E239E02478FAAA00FB9E5A /* FrogsListView.swift */, 218 | 30E239E22478FABC00FB9E5A /* FrogsListPresenter.swift */, 219 | 30E239E42478FAD500FB9E5A /* FrogsListRouter.swift */, 220 | ); 221 | path = FrogsList; 222 | sourceTree = ""; 223 | }; 224 | 30E239E62479114000FB9E5A /* FrogsDetail */ = { 225 | isa = PBXGroup; 226 | children = ( 227 | 308F9CA4247A6EDB0017C494 /* FrogDetailView.swift */, 228 | 308F9CA6247A79DD0017C494 /* FrogDetailPresenter.swift */, 229 | ); 230 | path = FrogsDetail; 231 | sourceTree = ""; 232 | }; 233 | 30E239E72479165200FB9E5A /* Login */ = { 234 | isa = PBXGroup; 235 | children = ( 236 | 30E239E82479166700FB9E5A /* LoginView.swift */, 237 | 30E239EA24791AFB00FB9E5A /* LoginPresenter.swift */, 238 | ); 239 | path = Login; 240 | sourceTree = ""; 241 | }; 242 | 30E239EE24791D5300FB9E5A /* Entities */ = { 243 | isa = PBXGroup; 244 | children = ( 245 | 30E239EF24791D8A00FB9E5A /* AppState.swift */, 246 | 304D5065247968F1003BFFC4 /* Frog.swift */, 247 | ); 248 | path = Entities; 249 | sourceTree = ""; 250 | }; 251 | 30E239F1247920DA00FB9E5A /* Root */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | 30E239B22478F5DA00FB9E5A /* RootView.swift */, 255 | ); 256 | path = Root; 257 | sourceTree = ""; 258 | }; 259 | /* End PBXGroup section */ 260 | 261 | /* Begin PBXNativeTarget section */ 262 | 30E239AA2478F5DA00FB9E5A /* FrogsGuideBook */ = { 263 | isa = PBXNativeTarget; 264 | buildConfigurationList = 30E239D52478F5DC00FB9E5A /* Build configuration list for PBXNativeTarget "FrogsGuideBook" */; 265 | buildPhases = ( 266 | 30E239A72478F5DA00FB9E5A /* Sources */, 267 | 30E239A82478F5DA00FB9E5A /* Frameworks */, 268 | 30E239A92478F5DA00FB9E5A /* Resources */, 269 | ); 270 | buildRules = ( 271 | ); 272 | dependencies = ( 273 | ); 274 | name = FrogsGuideBook; 275 | productName = FrogsGuideBook; 276 | productReference = 30E239AB2478F5DA00FB9E5A /* FrogsGuideBook.app */; 277 | productType = "com.apple.product-type.application"; 278 | }; 279 | 30E239C02478F5DC00FB9E5A /* FrogsGuideBookTests */ = { 280 | isa = PBXNativeTarget; 281 | buildConfigurationList = 30E239D82478F5DC00FB9E5A /* Build configuration list for PBXNativeTarget "FrogsGuideBookTests" */; 282 | buildPhases = ( 283 | 30E239BD2478F5DC00FB9E5A /* Sources */, 284 | 30E239BE2478F5DC00FB9E5A /* Frameworks */, 285 | 30E239BF2478F5DC00FB9E5A /* Resources */, 286 | ); 287 | buildRules = ( 288 | ); 289 | dependencies = ( 290 | 30E239C32478F5DC00FB9E5A /* PBXTargetDependency */, 291 | ); 292 | name = FrogsGuideBookTests; 293 | productName = FrogsGuideBookTests; 294 | productReference = 30E239C12478F5DC00FB9E5A /* FrogsGuideBookTests.xctest */; 295 | productType = "com.apple.product-type.bundle.unit-test"; 296 | }; 297 | 30E239CB2478F5DC00FB9E5A /* FrogsGuideBookUITests */ = { 298 | isa = PBXNativeTarget; 299 | buildConfigurationList = 30E239DB2478F5DC00FB9E5A /* Build configuration list for PBXNativeTarget "FrogsGuideBookUITests" */; 300 | buildPhases = ( 301 | 30E239C82478F5DC00FB9E5A /* Sources */, 302 | 30E239C92478F5DC00FB9E5A /* Frameworks */, 303 | 30E239CA2478F5DC00FB9E5A /* Resources */, 304 | ); 305 | buildRules = ( 306 | ); 307 | dependencies = ( 308 | 30E239CE2478F5DC00FB9E5A /* PBXTargetDependency */, 309 | ); 310 | name = FrogsGuideBookUITests; 311 | productName = FrogsGuideBookUITests; 312 | productReference = 30E239CC2478F5DC00FB9E5A /* FrogsGuideBookUITests.xctest */; 313 | productType = "com.apple.product-type.bundle.ui-testing"; 314 | }; 315 | /* End PBXNativeTarget section */ 316 | 317 | /* Begin PBXProject section */ 318 | 30E239A32478F5DA00FB9E5A /* Project object */ = { 319 | isa = PBXProject; 320 | attributes = { 321 | LastSwiftUpdateCheck = 1150; 322 | LastUpgradeCheck = 1150; 323 | ORGANIZATIONNAME = satoutakeshi; 324 | TargetAttributes = { 325 | 30E239AA2478F5DA00FB9E5A = { 326 | CreatedOnToolsVersion = 11.5; 327 | }; 328 | 30E239C02478F5DC00FB9E5A = { 329 | CreatedOnToolsVersion = 11.5; 330 | TestTargetID = 30E239AA2478F5DA00FB9E5A; 331 | }; 332 | 30E239CB2478F5DC00FB9E5A = { 333 | CreatedOnToolsVersion = 11.5; 334 | TestTargetID = 30E239AA2478F5DA00FB9E5A; 335 | }; 336 | }; 337 | }; 338 | buildConfigurationList = 30E239A62478F5DA00FB9E5A /* Build configuration list for PBXProject "FrogsGuideBook" */; 339 | compatibilityVersion = "Xcode 9.3"; 340 | developmentRegion = en; 341 | hasScannedForEncodings = 0; 342 | knownRegions = ( 343 | en, 344 | Base, 345 | ); 346 | mainGroup = 30E239A22478F5DA00FB9E5A; 347 | productRefGroup = 30E239AC2478F5DA00FB9E5A /* Products */; 348 | projectDirPath = ""; 349 | projectRoot = ""; 350 | targets = ( 351 | 30E239AA2478F5DA00FB9E5A /* FrogsGuideBook */, 352 | 30E239C02478F5DC00FB9E5A /* FrogsGuideBookTests */, 353 | 30E239CB2478F5DC00FB9E5A /* FrogsGuideBookUITests */, 354 | ); 355 | }; 356 | /* End PBXProject section */ 357 | 358 | /* Begin PBXResourcesBuildPhase section */ 359 | 30E239A92478F5DA00FB9E5A /* Resources */ = { 360 | isa = PBXResourcesBuildPhase; 361 | buildActionMask = 2147483647; 362 | files = ( 363 | 30E239BB2478F5DC00FB9E5A /* LaunchScreen.storyboard in Resources */, 364 | 30E239B82478F5DC00FB9E5A /* Preview Assets.xcassets in Resources */, 365 | 30E239B52478F5DC00FB9E5A /* Assets.xcassets in Resources */, 366 | ); 367 | runOnlyForDeploymentPostprocessing = 0; 368 | }; 369 | 30E239BF2478F5DC00FB9E5A /* Resources */ = { 370 | isa = PBXResourcesBuildPhase; 371 | buildActionMask = 2147483647; 372 | files = ( 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | 30E239CA2478F5DC00FB9E5A /* Resources */ = { 377 | isa = PBXResourcesBuildPhase; 378 | buildActionMask = 2147483647; 379 | files = ( 380 | ); 381 | runOnlyForDeploymentPostprocessing = 0; 382 | }; 383 | /* End PBXResourcesBuildPhase section */ 384 | 385 | /* Begin PBXSourcesBuildPhase section */ 386 | 30E239A72478F5DA00FB9E5A /* Sources */ = { 387 | isa = PBXSourcesBuildPhase; 388 | buildActionMask = 2147483647; 389 | files = ( 390 | 30E239EB24791AFB00FB9E5A /* LoginPresenter.swift in Sources */, 391 | 308F9CA5247A6EDB0017C494 /* FrogDetailView.swift in Sources */, 392 | 30E239F024791D8A00FB9E5A /* AppState.swift in Sources */, 393 | 30E239AF2478F5DA00FB9E5A /* AppDelegate.swift in Sources */, 394 | 30E239E92479166700FB9E5A /* LoginView.swift in Sources */, 395 | 308F9CAA247AA3740017C494 /* HomeTabView.swift in Sources */, 396 | 304D5064247961C2003BFFC4 /* BlurView.swift in Sources */, 397 | 30E239B12478F5DA00FB9E5A /* SceneDelegate.swift in Sources */, 398 | 304D506D247A2223003BFFC4 /* WebView.swift in Sources */, 399 | 304D506224796103003BFFC4 /* ImageCard.swift in Sources */, 400 | 304D506B247A210C003BFFC4 /* SettingPresenter.swift in Sources */, 401 | 304D5066247968F1003BFFC4 /* Frog.swift in Sources */, 402 | 308F9CA7247A79DD0017C494 /* FrogDetailPresenter.swift in Sources */, 403 | 304D5068247A1CD6003BFFC4 /* SettingView.swift in Sources */, 404 | 30E239E12478FAAA00FB9E5A /* FrogsListView.swift in Sources */, 405 | 30E239B32478F5DA00FB9E5A /* RootView.swift in Sources */, 406 | 304D506F247A26BE003BFFC4 /* SettingRouter.swift in Sources */, 407 | 30E239E52478FAD500FB9E5A /* FrogsListRouter.swift in Sources */, 408 | 30E239E32478FABC00FB9E5A /* FrogsListPresenter.swift in Sources */, 409 | ); 410 | runOnlyForDeploymentPostprocessing = 0; 411 | }; 412 | 30E239BD2478F5DC00FB9E5A /* Sources */ = { 413 | isa = PBXSourcesBuildPhase; 414 | buildActionMask = 2147483647; 415 | files = ( 416 | 30E239C62478F5DC00FB9E5A /* FrogsGuideBookTests.swift in Sources */, 417 | ); 418 | runOnlyForDeploymentPostprocessing = 0; 419 | }; 420 | 30E239C82478F5DC00FB9E5A /* Sources */ = { 421 | isa = PBXSourcesBuildPhase; 422 | buildActionMask = 2147483647; 423 | files = ( 424 | 30E239D12478F5DC00FB9E5A /* FrogsGuideBookUITests.swift in Sources */, 425 | ); 426 | runOnlyForDeploymentPostprocessing = 0; 427 | }; 428 | /* End PBXSourcesBuildPhase section */ 429 | 430 | /* Begin PBXTargetDependency section */ 431 | 30E239C32478F5DC00FB9E5A /* PBXTargetDependency */ = { 432 | isa = PBXTargetDependency; 433 | target = 30E239AA2478F5DA00FB9E5A /* FrogsGuideBook */; 434 | targetProxy = 30E239C22478F5DC00FB9E5A /* PBXContainerItemProxy */; 435 | }; 436 | 30E239CE2478F5DC00FB9E5A /* PBXTargetDependency */ = { 437 | isa = PBXTargetDependency; 438 | target = 30E239AA2478F5DA00FB9E5A /* FrogsGuideBook */; 439 | targetProxy = 30E239CD2478F5DC00FB9E5A /* PBXContainerItemProxy */; 440 | }; 441 | /* End PBXTargetDependency section */ 442 | 443 | /* Begin PBXVariantGroup section */ 444 | 30E239B92478F5DC00FB9E5A /* LaunchScreen.storyboard */ = { 445 | isa = PBXVariantGroup; 446 | children = ( 447 | 30E239BA2478F5DC00FB9E5A /* Base */, 448 | ); 449 | name = LaunchScreen.storyboard; 450 | sourceTree = ""; 451 | }; 452 | /* End PBXVariantGroup section */ 453 | 454 | /* Begin XCBuildConfiguration section */ 455 | 30E239D32478F5DC00FB9E5A /* Debug */ = { 456 | isa = XCBuildConfiguration; 457 | buildSettings = { 458 | ALWAYS_SEARCH_USER_PATHS = NO; 459 | CLANG_ANALYZER_NONNULL = YES; 460 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 461 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 462 | CLANG_CXX_LIBRARY = "libc++"; 463 | CLANG_ENABLE_MODULES = YES; 464 | CLANG_ENABLE_OBJC_ARC = YES; 465 | CLANG_ENABLE_OBJC_WEAK = YES; 466 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 467 | CLANG_WARN_BOOL_CONVERSION = YES; 468 | CLANG_WARN_COMMA = YES; 469 | CLANG_WARN_CONSTANT_CONVERSION = YES; 470 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 471 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 472 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 473 | CLANG_WARN_EMPTY_BODY = YES; 474 | CLANG_WARN_ENUM_CONVERSION = YES; 475 | CLANG_WARN_INFINITE_RECURSION = YES; 476 | CLANG_WARN_INT_CONVERSION = YES; 477 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 478 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 479 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 480 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 481 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 482 | CLANG_WARN_STRICT_PROTOTYPES = YES; 483 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 484 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 485 | CLANG_WARN_UNREACHABLE_CODE = YES; 486 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 487 | COPY_PHASE_STRIP = NO; 488 | DEBUG_INFORMATION_FORMAT = dwarf; 489 | ENABLE_STRICT_OBJC_MSGSEND = YES; 490 | ENABLE_TESTABILITY = YES; 491 | GCC_C_LANGUAGE_STANDARD = gnu11; 492 | GCC_DYNAMIC_NO_PIC = NO; 493 | GCC_NO_COMMON_BLOCKS = YES; 494 | GCC_OPTIMIZATION_LEVEL = 0; 495 | GCC_PREPROCESSOR_DEFINITIONS = ( 496 | "DEBUG=1", 497 | "$(inherited)", 498 | ); 499 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 500 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 501 | GCC_WARN_UNDECLARED_SELECTOR = YES; 502 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 503 | GCC_WARN_UNUSED_FUNCTION = YES; 504 | GCC_WARN_UNUSED_VARIABLE = YES; 505 | IPHONEOS_DEPLOYMENT_TARGET = 13.5; 506 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 507 | MTL_FAST_MATH = YES; 508 | ONLY_ACTIVE_ARCH = YES; 509 | SDKROOT = iphoneos; 510 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 511 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 512 | }; 513 | name = Debug; 514 | }; 515 | 30E239D42478F5DC00FB9E5A /* Release */ = { 516 | isa = XCBuildConfiguration; 517 | buildSettings = { 518 | ALWAYS_SEARCH_USER_PATHS = NO; 519 | CLANG_ANALYZER_NONNULL = YES; 520 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 521 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 522 | CLANG_CXX_LIBRARY = "libc++"; 523 | CLANG_ENABLE_MODULES = YES; 524 | CLANG_ENABLE_OBJC_ARC = YES; 525 | CLANG_ENABLE_OBJC_WEAK = YES; 526 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 527 | CLANG_WARN_BOOL_CONVERSION = YES; 528 | CLANG_WARN_COMMA = YES; 529 | CLANG_WARN_CONSTANT_CONVERSION = YES; 530 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 531 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 532 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 533 | CLANG_WARN_EMPTY_BODY = YES; 534 | CLANG_WARN_ENUM_CONVERSION = YES; 535 | CLANG_WARN_INFINITE_RECURSION = YES; 536 | CLANG_WARN_INT_CONVERSION = YES; 537 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 538 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 539 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 540 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 541 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 542 | CLANG_WARN_STRICT_PROTOTYPES = YES; 543 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 544 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 545 | CLANG_WARN_UNREACHABLE_CODE = YES; 546 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 547 | COPY_PHASE_STRIP = NO; 548 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 549 | ENABLE_NS_ASSERTIONS = NO; 550 | ENABLE_STRICT_OBJC_MSGSEND = YES; 551 | GCC_C_LANGUAGE_STANDARD = gnu11; 552 | GCC_NO_COMMON_BLOCKS = YES; 553 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 554 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 555 | GCC_WARN_UNDECLARED_SELECTOR = YES; 556 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 557 | GCC_WARN_UNUSED_FUNCTION = YES; 558 | GCC_WARN_UNUSED_VARIABLE = YES; 559 | IPHONEOS_DEPLOYMENT_TARGET = 13.5; 560 | MTL_ENABLE_DEBUG_INFO = NO; 561 | MTL_FAST_MATH = YES; 562 | SDKROOT = iphoneos; 563 | SWIFT_COMPILATION_MODE = wholemodule; 564 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 565 | VALIDATE_PRODUCT = YES; 566 | }; 567 | name = Release; 568 | }; 569 | 30E239D62478F5DC00FB9E5A /* Debug */ = { 570 | isa = XCBuildConfiguration; 571 | buildSettings = { 572 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 573 | CODE_SIGN_STYLE = Automatic; 574 | DEVELOPMENT_ASSET_PATHS = "\"FrogsGuideBook/Preview Content\""; 575 | DEVELOPMENT_TEAM = WNEUDLL4LF; 576 | ENABLE_PREVIEWS = YES; 577 | INFOPLIST_FILE = FrogsGuideBook/Info.plist; 578 | LD_RUNPATH_SEARCH_PATHS = ( 579 | "$(inherited)", 580 | "@executable_path/Frameworks", 581 | ); 582 | PRODUCT_BUNDLE_IDENTIFIER = "com.Personal-Factory.FrogsGuideBook"; 583 | PRODUCT_NAME = "$(TARGET_NAME)"; 584 | SWIFT_VERSION = 5.0; 585 | TARGETED_DEVICE_FAMILY = "1,2"; 586 | }; 587 | name = Debug; 588 | }; 589 | 30E239D72478F5DC00FB9E5A /* Release */ = { 590 | isa = XCBuildConfiguration; 591 | buildSettings = { 592 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 593 | CODE_SIGN_STYLE = Automatic; 594 | DEVELOPMENT_ASSET_PATHS = "\"FrogsGuideBook/Preview Content\""; 595 | DEVELOPMENT_TEAM = WNEUDLL4LF; 596 | ENABLE_PREVIEWS = YES; 597 | INFOPLIST_FILE = FrogsGuideBook/Info.plist; 598 | LD_RUNPATH_SEARCH_PATHS = ( 599 | "$(inherited)", 600 | "@executable_path/Frameworks", 601 | ); 602 | PRODUCT_BUNDLE_IDENTIFIER = "com.Personal-Factory.FrogsGuideBook"; 603 | PRODUCT_NAME = "$(TARGET_NAME)"; 604 | SWIFT_VERSION = 5.0; 605 | TARGETED_DEVICE_FAMILY = "1,2"; 606 | }; 607 | name = Release; 608 | }; 609 | 30E239D92478F5DC00FB9E5A /* Debug */ = { 610 | isa = XCBuildConfiguration; 611 | buildSettings = { 612 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 613 | BUNDLE_LOADER = "$(TEST_HOST)"; 614 | CODE_SIGN_STYLE = Automatic; 615 | DEVELOPMENT_TEAM = WNEUDLL4LF; 616 | INFOPLIST_FILE = FrogsGuideBookTests/Info.plist; 617 | IPHONEOS_DEPLOYMENT_TARGET = 13.5; 618 | LD_RUNPATH_SEARCH_PATHS = ( 619 | "$(inherited)", 620 | "@executable_path/Frameworks", 621 | "@loader_path/Frameworks", 622 | ); 623 | PRODUCT_BUNDLE_IDENTIFIER = "com.Personal-Factory.FrogsGuideBookTests"; 624 | PRODUCT_NAME = "$(TARGET_NAME)"; 625 | SWIFT_VERSION = 5.0; 626 | TARGETED_DEVICE_FAMILY = "1,2"; 627 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FrogsGuideBook.app/FrogsGuideBook"; 628 | }; 629 | name = Debug; 630 | }; 631 | 30E239DA2478F5DC00FB9E5A /* Release */ = { 632 | isa = XCBuildConfiguration; 633 | buildSettings = { 634 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 635 | BUNDLE_LOADER = "$(TEST_HOST)"; 636 | CODE_SIGN_STYLE = Automatic; 637 | DEVELOPMENT_TEAM = WNEUDLL4LF; 638 | INFOPLIST_FILE = FrogsGuideBookTests/Info.plist; 639 | IPHONEOS_DEPLOYMENT_TARGET = 13.5; 640 | LD_RUNPATH_SEARCH_PATHS = ( 641 | "$(inherited)", 642 | "@executable_path/Frameworks", 643 | "@loader_path/Frameworks", 644 | ); 645 | PRODUCT_BUNDLE_IDENTIFIER = "com.Personal-Factory.FrogsGuideBookTests"; 646 | PRODUCT_NAME = "$(TARGET_NAME)"; 647 | SWIFT_VERSION = 5.0; 648 | TARGETED_DEVICE_FAMILY = "1,2"; 649 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FrogsGuideBook.app/FrogsGuideBook"; 650 | }; 651 | name = Release; 652 | }; 653 | 30E239DC2478F5DC00FB9E5A /* Debug */ = { 654 | isa = XCBuildConfiguration; 655 | buildSettings = { 656 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 657 | CODE_SIGN_STYLE = Automatic; 658 | DEVELOPMENT_TEAM = WNEUDLL4LF; 659 | INFOPLIST_FILE = FrogsGuideBookUITests/Info.plist; 660 | LD_RUNPATH_SEARCH_PATHS = ( 661 | "$(inherited)", 662 | "@executable_path/Frameworks", 663 | "@loader_path/Frameworks", 664 | ); 665 | PRODUCT_BUNDLE_IDENTIFIER = "com.Personal-Factory.FrogsGuideBookUITests"; 666 | PRODUCT_NAME = "$(TARGET_NAME)"; 667 | SWIFT_VERSION = 5.0; 668 | TARGETED_DEVICE_FAMILY = "1,2"; 669 | TEST_TARGET_NAME = FrogsGuideBook; 670 | }; 671 | name = Debug; 672 | }; 673 | 30E239DD2478F5DC00FB9E5A /* Release */ = { 674 | isa = XCBuildConfiguration; 675 | buildSettings = { 676 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 677 | CODE_SIGN_STYLE = Automatic; 678 | DEVELOPMENT_TEAM = WNEUDLL4LF; 679 | INFOPLIST_FILE = FrogsGuideBookUITests/Info.plist; 680 | LD_RUNPATH_SEARCH_PATHS = ( 681 | "$(inherited)", 682 | "@executable_path/Frameworks", 683 | "@loader_path/Frameworks", 684 | ); 685 | PRODUCT_BUNDLE_IDENTIFIER = "com.Personal-Factory.FrogsGuideBookUITests"; 686 | PRODUCT_NAME = "$(TARGET_NAME)"; 687 | SWIFT_VERSION = 5.0; 688 | TARGETED_DEVICE_FAMILY = "1,2"; 689 | TEST_TARGET_NAME = FrogsGuideBook; 690 | }; 691 | name = Release; 692 | }; 693 | /* End XCBuildConfiguration section */ 694 | 695 | /* Begin XCConfigurationList section */ 696 | 30E239A62478F5DA00FB9E5A /* Build configuration list for PBXProject "FrogsGuideBook" */ = { 697 | isa = XCConfigurationList; 698 | buildConfigurations = ( 699 | 30E239D32478F5DC00FB9E5A /* Debug */, 700 | 30E239D42478F5DC00FB9E5A /* Release */, 701 | ); 702 | defaultConfigurationIsVisible = 0; 703 | defaultConfigurationName = Release; 704 | }; 705 | 30E239D52478F5DC00FB9E5A /* Build configuration list for PBXNativeTarget "FrogsGuideBook" */ = { 706 | isa = XCConfigurationList; 707 | buildConfigurations = ( 708 | 30E239D62478F5DC00FB9E5A /* Debug */, 709 | 30E239D72478F5DC00FB9E5A /* Release */, 710 | ); 711 | defaultConfigurationIsVisible = 0; 712 | defaultConfigurationName = Release; 713 | }; 714 | 30E239D82478F5DC00FB9E5A /* Build configuration list for PBXNativeTarget "FrogsGuideBookTests" */ = { 715 | isa = XCConfigurationList; 716 | buildConfigurations = ( 717 | 30E239D92478F5DC00FB9E5A /* Debug */, 718 | 30E239DA2478F5DC00FB9E5A /* Release */, 719 | ); 720 | defaultConfigurationIsVisible = 0; 721 | defaultConfigurationName = Release; 722 | }; 723 | 30E239DB2478F5DC00FB9E5A /* Build configuration list for PBXNativeTarget "FrogsGuideBookUITests" */ = { 724 | isa = XCConfigurationList; 725 | buildConfigurations = ( 726 | 30E239DC2478F5DC00FB9E5A /* Debug */, 727 | 30E239DD2478F5DC00FB9E5A /* Release */, 728 | ); 729 | defaultConfigurationIsVisible = 0; 730 | defaultConfigurationName = Release; 731 | }; 732 | /* End XCConfigurationList section */ 733 | }; 734 | rootObject = 30E239A32478F5DA00FB9E5A /* Project object */; 735 | } 736 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 15 | // Override point for customization after application launch. 16 | return true 17 | } 18 | 19 | // MARK: UISceneSession Lifecycle 20 | 21 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 22 | // Called when a new scene session is being created. 23 | // Use this method to select a configuration to create the new scene with. 24 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 25 | } 26 | 27 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 28 | // Called when the user discards a scene session. 29 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 30 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/blue-poison-dart-frog.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "blue-poison-dart-frog.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/blue-poison-dart-frog.imageset/blue-poison-dart-frog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SatoTakeshiX/SwiftUI-VIPER-Architecture-Pattern/de81895baed8af5d427af19b6139ec2d46204651/FrogsGuideBook/FrogsGuideBook/Assets.xcassets/blue-poison-dart-frog.imageset/blue-poison-dart-frog.jpg -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/frog-logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "frog-logo.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/frog-logo.imageset/frog-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SatoTakeshiX/SwiftUI-VIPER-Architecture-Pattern/de81895baed8af5d427af19b6139ec2d46204651/FrogsGuideBook/FrogsGuideBook/Assets.xcassets/frog-logo.imageset/frog-logo.png -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/red-eyed-tree-frog.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "red-eyed-tree-frog.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/red-eyed-tree-frog.imageset/red-eyed-tree-frog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SatoTakeshiX/SwiftUI-VIPER-Architecture-Pattern/de81895baed8af5d427af19b6139ec2d46204651/FrogsGuideBook/FrogsGuideBook/Assets.xcassets/red-eyed-tree-frog.imageset/red-eyed-tree-frog.jpg -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/toad.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "toad.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Assets.xcassets/toad.imageset/toad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SatoTakeshiX/SwiftUI-VIPER-Architecture-Pattern/de81895baed8af5d427af19b6139ec2d46204651/FrogsGuideBook/FrogsGuideBook/Assets.xcassets/toad.imageset/toad.jpg -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Entities/AppState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppState.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import Combine 10 | 11 | final class AppState: ObservableObject { 12 | @Published var isLogin = false 13 | } 14 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Entities/Frog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Frog.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Frog: Identifiable { 12 | let id = UUID() 13 | let imageName: String 14 | let name: String 15 | let location: String 16 | } 17 | 18 | let mockFrogs: [Frog] = [ 19 | Frog(imageName: "blue-poison-dart-frog", name: "blue poison dart frog", location: "Brazil"), 20 | Frog(imageName: "red-eyed-tree-frog", name: "red eyed tree frog", location: "Mexico"), 21 | Frog(imageName: "toad", name: "toad", location: "Anywhere") 22 | ] 23 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | 37 | 38 | 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UISupportedInterfaceOrientations~ipad 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationPortraitUpsideDown 56 | UIInterfaceOrientationLandscapeLeft 57 | UIInterfaceOrientationLandscapeRight 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftUI 11 | 12 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 13 | var window: UIWindow? 14 | let appState = AppState() 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | let rootView = RootView().environmentObject(appState) 17 | if let windowScene = scene as? UIWindowScene { 18 | let window = UIWindow(windowScene: windowScene) 19 | window.rootViewController = UIHostingController(rootView: rootView) 20 | self.window = window 21 | window.makeKeyAndVisible() 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/FrogsDetail/FrogDetailPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FrogDetailPresenter.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/24. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import Combine 11 | 12 | final class FrogDetailPresenter: ObservableObject { 13 | @Published var isShowError = false 14 | let frog: Frog 15 | 16 | init(frog: Frog) { 17 | self.frog = frog 18 | } 19 | func alertBuilder() -> Alert { 20 | let alertButton = Alert.Button.default(Text("OK")) { 21 | print("did tap alert OK button") 22 | } 23 | let alert = Alert(title: Text("This feature is out of service"), message: Text("Please wait a little longer for service to begin. It may take a few days."), dismissButton: alertButton) 24 | return alert 25 | } 26 | 27 | func makeAskTheProfessorButton() -> some View { 28 | Button(action: didTapAskButton) { 29 | HStack { 30 | Text("Ask the Professor") 31 | Spacer() 32 | Image(systemName: "chevron.right") 33 | .renderingMode(.template) 34 | .resizable() 35 | .aspectRatio(contentMode: .fit) 36 | .foregroundColor(.gray) 37 | .frame(width: 20, height: 20) 38 | } 39 | } 40 | } 41 | 42 | // Mark: - Private 43 | private func didTapAskButton() { 44 | isShowError = true 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/FrogsDetail/FrogDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FrogDetailView.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/24. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct FrogDetailView: View { 12 | @ObservedObject var presenter: FrogDetailPresenter 13 | var body: some View { 14 | List { 15 | HStack(alignment: .center) { 16 | Spacer() 17 | Image(self.presenter.frog.imageName) 18 | Spacer() 19 | } 20 | Section(header: Text("Info")) { 21 | HStack { 22 | Text("location") 23 | .frame(width: 70, alignment: .leading) 24 | Text(self.presenter.frog.location) 25 | } 26 | } 27 | 28 | Section(header: Text("Feature")) { 29 | self.presenter.makeAskTheProfessorButton() 30 | } 31 | } 32 | .alert(isPresented: $presenter.isShowError, content: presenter.alertBuilder) 33 | .navigationBarTitle(Text(self.presenter.frog.name), displayMode: .inline) 34 | } 35 | } 36 | 37 | struct FrogDetailView_Previews: PreviewProvider { 38 | static var previews: some View { 39 | let frog = mockFrogs[0] 40 | return NavigationView{ 41 | FrogDetailView(presenter: FrogDetailPresenter(frog: frog)) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/FrogsList/FrogsListPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FrogsListPresenter.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import Combine 11 | 12 | final class FrogsListPresenter: ObservableObject { 13 | struct Parameter { 14 | let frogs: [Frog] 15 | } 16 | enum Inputs { 17 | case didTapAboutButton 18 | } 19 | private let router = FrogsListRouter() 20 | let params: Parameter 21 | @Published var isShowAbout = false 22 | init(params: Parameter) { 23 | self.params = params 24 | } 25 | 26 | func apply(inputs: Inputs) { 27 | switch inputs { 28 | case .didTapAboutButton: 29 | isShowAbout = true 30 | } 31 | } 32 | 33 | func linkBuilder(frog: Frog, @ViewBuilder content: () -> Content) -> some View { 34 | NavigationLink(destination: router.makeDetailView(frog: frog)) { 35 | content() 36 | } 37 | } 38 | 39 | func makeAboutButton() -> some View { 40 | Button(action: goToAbout) { 41 | Image(systemName: "questionmark.circle") 42 | } 43 | } 44 | 45 | func makeAboutWebView() -> some View { 46 | let url = URL(string: "https://github.com/SatoTakeshiX/SwiftUI-VIPER-Architecture-Pattern")! 47 | let webView = WebView(url: url) 48 | return webView 49 | } 50 | 51 | // MARK: - Private 52 | private func goToAbout() { 53 | isShowAbout = true 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/FrogsList/FrogsListRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FrogsListRouter.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | final class FrogsListRouter { 12 | func makeDetailView(frog: Frog) -> some View { 13 | let presenter = FrogDetailPresenter(frog: frog) 14 | let detail = FrogDetailView(presenter: presenter) 15 | return detail 16 | } 17 | 18 | func makeAboutWebView() -> some View { 19 | let url = URL(string: "https://github.com/SatoTakeshiX/SwiftUI-VIPER-Architecture-Pattern")! 20 | let webView = WebView(url: url) 21 | return webView 22 | } 23 | } 24 | 25 | struct FrogsListRouter_Previews: PreviewProvider { 26 | static var previews: some View { 27 | FrogsListRouter().makeDetailView(frog: mockFrogs[0]) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/FrogsList/FrogsListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FrogsListView.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct FrogsListView: View { 12 | @ObservedObject var presenter: FrogsListPresenter 13 | var body: some View { 14 | List { 15 | ForEach(presenter.params.frogs, id: \.id) { frog in 16 | self.presenter.linkBuilder(frog: frog) { 17 | ImageCard(imageName: frog.imageName, frogName: frog.name) 18 | .frame(height: 240) 19 | } 20 | } 21 | } 22 | .sheet(isPresented: $presenter.isShowAbout) { 23 | self.presenter.makeAboutWebView() 24 | } 25 | .navigationBarTitle("Frogs Guide Book", displayMode: .inline) 26 | .navigationBarItems(trailing: presenter.makeAboutButton()) 27 | } 28 | } 29 | 30 | struct FrogsListView_Previews: PreviewProvider { 31 | static var previews: some View { 32 | let presenter = FrogsListPresenter(params: .init(frogs: mockFrogs)) 33 | let list = FrogsListView(presenter: presenter) 34 | return Group { 35 | NavigationView { 36 | list 37 | } 38 | presenter.makeAboutButton() 39 | .previewLayout(.fixed(width: 50, height: 50)) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/HomeTab/HomeTabView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HomeTabView.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/24. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct HomeTabView: View { 12 | @EnvironmentObject var appState: AppState 13 | var body: some View { 14 | TabView { 15 | NavigationView { 16 | FrogsListView(presenter: FrogsListPresenter(params: .init(frogs: mockFrogs))) 17 | } 18 | .tabItem { 19 | VStack { 20 | Image(systemName: "house.fill") 21 | Text("Frogs Guide") 22 | } 23 | } 24 | .tag(1) 25 | 26 | NavigationView { 27 | SettingView(presenter: SettingPresenter(appState: appState)) 28 | } 29 | .tabItem { 30 | VStack { 31 | Image(systemName: "gear") 32 | Text("Setting") 33 | } 34 | } 35 | .tag(2) 36 | } 37 | } 38 | } 39 | 40 | struct HomeTabView_Previews: PreviewProvider { 41 | static var previews: some View { 42 | HomeTabView().environmentObject(AppState()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/Login/LoginPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginPresenter.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import Combine 11 | 12 | final class LoginPresenter: ObservableObject { 13 | enum Inputs { 14 | case didTapLoginButton 15 | } 16 | init(appState: AppState) { 17 | self.appState = appState 18 | } 19 | func apply(inputs: Inputs) { 20 | switch inputs { 21 | case .didTapLoginButton: 22 | appState.isLogin = true 23 | } 24 | } 25 | // Private 26 | private let appState: AppState 27 | } 28 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/Login/LoginView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginView.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct LoginView: View { 12 | @State var inputEmail: String = "" 13 | @State var inputPassword: String = "" 14 | @ObservedObject var presenter: LoginPresenter 15 | init(appState: AppState) { 16 | self.presenter = LoginPresenter(appState: appState) 17 | } 18 | var body: some View { 19 | ScrollView { 20 | Image("frog-logo") 21 | .renderingMode(.template) 22 | .foregroundColor(.green) 23 | Text("Frogs Guid Book") 24 | .font(.largeTitle) 25 | VStack(alignment: .leading) { 26 | Text("Account Name") 27 | TextField("input your e-mail", text: $inputEmail) 28 | .textFieldStyle(RoundedBorderTextFieldStyle()) 29 | } 30 | .padding() 31 | 32 | VStack(alignment: .leading) { 33 | Text("Password") 34 | TextField("input your password", text: $inputPassword) 35 | .textFieldStyle(RoundedBorderTextFieldStyle()) 36 | 37 | } 38 | .padding() 39 | 40 | Button(action: { 41 | self.presenter.apply(inputs: .didTapLoginButton) 42 | }, label: { 43 | ZStack { 44 | RoundedRectangle(cornerRadius: 10) 45 | .frame(height: 70) 46 | .padding() 47 | .foregroundColor(.green) 48 | Text("Login") 49 | .font(.title) 50 | .foregroundColor(.white) 51 | } 52 | }) 53 | } 54 | .padding(.top) 55 | } 56 | } 57 | 58 | struct LoginView_Previews: PreviewProvider { 59 | static var previews: some View { 60 | LoginView(appState: AppState()) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/Root/RootView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RootView.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | // RootView 12 | struct RootView: View { 13 | @EnvironmentObject var appState: AppState 14 | var body: some View { 15 | ZStack { 16 | if appState.isLogin { 17 | HomeTabView() 18 | } else { 19 | LoginView(appState: self.appState) 20 | } 21 | } 22 | } 23 | } 24 | 25 | struct ContentView_Previews: PreviewProvider { 26 | static var previews: some View { 27 | RootView().environmentObject(AppState()) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/Setting/SettingPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingPresenter.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/24. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import Combine 11 | 12 | final class SettingPresenter: ObservableObject { 13 | 14 | @Published var isShowAbout = false 15 | 16 | init(appState: AppState) { 17 | self.appState = appState 18 | } 19 | 20 | func makeAboutButton() -> some View { 21 | Button(action: goToAbout) { 22 | Text("About Frogs Guide Book") 23 | } 24 | } 25 | 26 | func makeLogoutButton() -> some View { 27 | Button(action: logout) { 28 | Text("Logout") 29 | .foregroundColor(.red) 30 | } 31 | } 32 | 33 | func goToAbout() { 34 | isShowAbout = true 35 | } 36 | 37 | func logout() { 38 | appState.isLogin = false 39 | } 40 | 41 | func makeAboutWebView() -> some View { 42 | return router.makeAboutWebView() 43 | } 44 | 45 | // Private 46 | private let router = SettingRouter() 47 | private let appState: AppState 48 | } 49 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/Setting/SettingRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingRouter.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/24. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | final class SettingRouter { 12 | func makeAboutWebView() -> some View { 13 | let url = URL(string: "https://github.com/SatoTakeshiX/SwiftUI-VIPER-Architecture-Pattern")! 14 | let webView = WebView(url: url) 15 | return webView 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/Scenes/Setting/SettingView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingView.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/24. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct SettingView: View { 12 | @ObservedObject var presenter: SettingPresenter 13 | @EnvironmentObject var appState: AppState 14 | var body: some View { 15 | List { 16 | self.presenter.makeAboutButton() 17 | self.presenter.makeLogoutButton() 18 | } 19 | .sheet(isPresented: $presenter.isShowAbout) { 20 | self.presenter.makeAboutWebView() 21 | } 22 | .navigationBarTitle("Setting", displayMode: .inline) 23 | } 24 | } 25 | 26 | struct SettingView_Previews: PreviewProvider { 27 | static var previews: some View { 28 | let appState = AppState() 29 | let presenter = SettingPresenter(appState: appState) 30 | return NavigationView { 31 | SettingView(presenter: presenter) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/ViewComponent/BlurView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BlurView.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct BlurView: UIViewRepresentable { 12 | typealias UIViewType = UIView 13 | 14 | func makeUIView(context: Context) -> UIView { 15 | let view = UIView() 16 | view.backgroundColor = .clear 17 | let blurEffect = UIBlurEffect(style: .systemUltraThinMaterial) 18 | let blurView = UIVisualEffectView(effect: blurEffect) 19 | blurView.translatesAutoresizingMaskIntoConstraints = false 20 | view.addSubview(blurView) 21 | blurView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true 22 | blurView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true 23 | blurView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true 24 | blurView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true 25 | return view 26 | } 27 | 28 | func updateUIView(_ uiView: UIView, context: Context) {} 29 | } 30 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/ViewComponent/ImageCard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageCard.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct ImageCard: View { 12 | let imageName: String 13 | let frogName: String 14 | var body: some View { 15 | GeometryReader { geometry in 16 | ZStack(alignment: .bottomLeading) { 17 | Image(self.imageName) 18 | .resizable() 19 | .aspectRatio(contentMode: .fill) 20 | .frame(width: geometry.size.width, height: geometry.size.height) 21 | BlurView() 22 | .frame(width: geometry.size.width, height: 42) 23 | Text(self.frogName) 24 | .font(.system(size: 32)) 25 | .fontWeight(.bold) 26 | .foregroundColor(.white) 27 | .padding(EdgeInsets(top: 0, leading: 8, bottom: 4, trailing: 8)) 28 | } 29 | } 30 | .cornerRadius(12) 31 | } 32 | } 33 | 34 | struct ImageCard_Previews: PreviewProvider { 35 | static var previews: some View { 36 | ImageCard(imageName: "red-eyed-tree-frog", frogName: "red eyed tree frog") 37 | .frame(height: 240) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBook/ViewComponent/WebView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WebView.swift 3 | // FrogsGuideBook 4 | // 5 | // Created by satoutakeshi on 2020/05/24. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import SafariServices 11 | 12 | struct WebView: UIViewControllerRepresentable { 13 | typealias UIViewControllerType = SFSafariViewController 14 | 15 | private let url: URL 16 | 17 | init(url: URL) { 18 | self.url = url 19 | } 20 | 21 | func makeUIViewController(context: Context) -> SFSafariViewController { 22 | let safariVC = SFSafariViewController(url: url) 23 | return safariVC 24 | } 25 | 26 | func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBookTests/FrogsGuideBookTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FrogsGuideBookTests.swift 3 | // FrogsGuideBookTests 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import FrogsGuideBook 11 | 12 | class FrogsGuideBookTests: XCTestCase { 13 | 14 | override func setUpWithError() throws { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDownWithError() throws { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() throws { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() throws { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBookTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBookUITests/FrogsGuideBookUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FrogsGuideBookUITests.swift 3 | // FrogsGuideBookUITests 4 | // 5 | // Created by satoutakeshi on 2020/05/23. 6 | // Copyright © 2020 satoutakeshi. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class FrogsGuideBookUITests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | 16 | // In UI tests it is usually best to stop immediately when a failure occurs. 17 | continueAfterFailure = false 18 | 19 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 20 | } 21 | 22 | override func tearDownWithError() throws { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | } 25 | 26 | func testExample() throws { 27 | // UI tests must launch the application that they test. 28 | let app = XCUIApplication() 29 | app.launch() 30 | 31 | // Use recording to get started writing UI tests. 32 | // Use XCTAssert and related functions to verify your tests produce the correct results. 33 | } 34 | 35 | func testLaunchPerformance() throws { 36 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 37 | // This measures how long it takes to launch your application. 38 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { 39 | XCUIApplication().launch() 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /FrogsGuideBook/FrogsGuideBookUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 佐藤剛士 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FrogsGuideBook 2 | FrogsGuideBook 3 | 4 | 5 | CouleurによるPixabayからの画像 6 | 7 | Susanne Jutzeler, suju-fotoによるPixabayからの画像 8 | 9 | 10 | 11 | 272447によるPixabayからの画像 12 | --------------------------------------------------------------------------------