diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dffc1ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,140 @@ + +# Created by https://www.gitignore.io/api/osx,swift,xcode,cocoapods +# Edit at https://www.gitignore.io/?templates=osx,swift,xcode,cocoapods + +### CocoaPods ### +## CocoaPods GitIgnore Template + +# CocoaPods - Only use to conserve bandwidth / Save time on Pushing +# - Also handy if you have a large number of dependant pods +# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE +Pods/ + +### OSX ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Swift ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +.build/ +# Add this line if you want to avoid checking in Xcode SPM integration. +# .swiftpm/xcode + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + +### Xcode ### +# Xcode +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) + +## Xcode Patch +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno + +### Xcode Patch ### +**/xcshareddata/WorkspaceSettings.xcsettings + +# End of https://www.gitignore.io/api/osx,swift,xcode,cocoapods diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10.xcodeproj/project.pbxproj b/Fakestagram-Xcode10/Fakestagram-Xcode10.xcodeproj/project.pbxproj index 01d56d3..d3c7b85 100644 --- a/Fakestagram-Xcode10/Fakestagram-Xcode10.xcodeproj/project.pbxproj +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10.xcodeproj/project.pbxproj @@ -3,16 +3,43 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ + 42ADD56BE4D4255623EA9AEC /* Pods_Fakestagram_Xcode10Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CC485714B1528A06F25D0EB3 /* Pods_Fakestagram_Xcode10Tests.framework */; }; 7701BEB1233F1B1B0004C30D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7701BEB0233F1B1B0004C30D /* AppDelegate.swift */; }; 7701BEB6233F1B1B0004C30D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7701BEB4233F1B1B0004C30D /* Main.storyboard */; }; 7701BEB8233F1B1C0004C30D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7701BEB7233F1B1C0004C30D /* Assets.xcassets */; }; 7701BEBB233F1B1C0004C30D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7701BEB9233F1B1C0004C30D /* LaunchScreen.storyboard */; }; 7701BEC6233F1B1C0004C30D /* Fakestagram_Xcode10Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7701BEC5233F1B1C0004C30D /* Fakestagram_Xcode10Tests.swift */; }; - 7701BED1233F1B540004C30D /* PostsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7701BED0233F1B540004C30D /* PostsTableViewController.swift */; }; + 7706D144235B583000290A16 /* UIDevice+models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7706D143235B583000290A16 /* UIDevice+models.swift */; }; + 7706D146235B679900290A16 /* CameraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7706D145235B679900290A16 /* CameraViewController.swift */; }; + 7706D148235B6DCA00290A16 /* UIImage+Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7706D147235B6DCA00290A16 /* UIImage+Base64.swift */; }; + 7909C65A23521FEC000B0380 /* Credentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C65923521FEC000B0380 /* Credentials.swift */; }; + 7909C65C23522002000B0380 /* PostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C65B23522002000B0380 /* PostViewController.swift */; }; + 7909C65E23522061000B0380 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C65D23522061000B0380 /* Client.swift */; }; + 7909C66023522082000B0380 /* HttpResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C65F23522082000B0380 /* HttpResponse.swift */; }; + 7909C66223522091000B0380 /* RequestBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C66123522091000B0380 /* RequestBuilder.swift */; }; + 7909C666235220BC000B0380 /* StatusCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C665235220BC000B0380 /* StatusCode.swift */; }; + 7909C6682352214C000B0380 /* CodableSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C6672352214C000B0380 /* CodableSerializer.swift */; }; + 7909C66A2352216E000B0380 /* RestClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C6692352216E000B0380 /* RestClient.swift */; }; + 7909C66C2352218A000B0380 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C66B2352218A000B0380 /* Account.swift */; }; + 7909C66E235221A3000B0380 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C66D235221A3000B0380 /* Post.swift */; }; + 7909C67023522287000B0380 /* RequestBuilderTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C66F23522287000B0380 /* RequestBuilderTest.swift */; }; + 7909C672235222CC000B0380 /* RestClientTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C671235222CC000B0380 /* RestClientTest.swift */; }; + 7909C6752352232F000B0380 /* posts.successful.json in Resources */ = {isa = PBXBuildFile; fileRef = 7909C6742352232F000B0380 /* posts.successful.json */; }; + 7909C67723522339000B0380 /* show_post.successful.json in Resources */ = {isa = PBXBuildFile; fileRef = 7909C67623522339000B0380 /* show_post.successful.json */; }; + 7909C67B23523BE3000B0380 /* PostXIBViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C67923523BE3000B0380 /* PostXIBViewController.swift */; }; + 7909C67C23523BE3000B0380 /* PostXIBViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7909C67A23523BE3000B0380 /* PostXIBViewController.xib */; }; + 7909C67E23524566000B0380 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C67D23524566000B0380 /* Comment.swift */; }; + 7909C68023524576000B0380 /* Like.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C67F23524576000B0380 /* Like.swift */; }; + 7909C6822352458A000B0380 /* Author.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C6812352458A000B0380 /* Author.swift */; }; + 7909C686235246FE000B0380 /* AuthorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7909C685235246FE000B0380 /* AuthorView.swift */; }; + 79762857235A787300055EC7 /* PostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79762856235A787300055EC7 /* PostsViewController.swift */; }; + 7976285A235A80F500055EC7 /* PostCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79762858235A80F500055EC7 /* PostCollectionViewCell.swift */; }; + 7976285B235A80F500055EC7 /* PostCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 79762859235A80F500055EC7 /* PostCollectionViewCell.xib */; }; + F2AD903247DD33845EA3C7FB /* Pods_Fakestagram_Xcode10.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F32B394EBB804D9C3E14052 /* Pods_Fakestagram_Xcode10.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -26,6 +53,9 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0FF38D441F0DD6993050E737 /* Pods-Fakestagram-Xcode10Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fakestagram-Xcode10Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Fakestagram-Xcode10Tests/Pods-Fakestagram-Xcode10Tests.release.xcconfig"; sourceTree = ""; }; + 4C3E60F528DFC01A73C34495 /* Pods-Fakestagram-Xcode10.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fakestagram-Xcode10.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Fakestagram-Xcode10/Pods-Fakestagram-Xcode10.debug.xcconfig"; sourceTree = ""; }; + 658CC8D2CB4B6BE6E65EE461 /* Pods-Fakestagram-Xcode10.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fakestagram-Xcode10.release.xcconfig"; path = "Pods/Target Support Files/Pods-Fakestagram-Xcode10/Pods-Fakestagram-Xcode10.release.xcconfig"; sourceTree = ""; }; 7701BEAD233F1B1B0004C30D /* Fakestagram-Xcode10.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Fakestagram-Xcode10.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 7701BEB0233F1B1B0004C30D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7701BEB5233F1B1B0004C30D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -35,7 +65,35 @@ 7701BEC1233F1B1C0004C30D /* Fakestagram-Xcode10Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Fakestagram-Xcode10Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 7701BEC5233F1B1C0004C30D /* Fakestagram_Xcode10Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fakestagram_Xcode10Tests.swift; sourceTree = ""; }; 7701BEC7233F1B1C0004C30D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7701BED0233F1B540004C30D /* PostsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsTableViewController.swift; sourceTree = ""; }; + 7706D143235B583000290A16 /* UIDevice+models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+models.swift"; sourceTree = ""; }; + 7706D145235B679900290A16 /* CameraViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraViewController.swift; sourceTree = ""; }; + 7706D147235B6DCA00290A16 /* UIImage+Base64.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Base64.swift"; sourceTree = ""; }; + 7909C65923521FEC000B0380 /* Credentials.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Credentials.swift; sourceTree = ""; }; + 7909C65B23522002000B0380 /* PostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostViewController.swift; sourceTree = ""; }; + 7909C65D23522061000B0380 /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; + 7909C65F23522082000B0380 /* HttpResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpResponse.swift; sourceTree = ""; }; + 7909C66123522091000B0380 /* RequestBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestBuilder.swift; sourceTree = ""; }; + 7909C665235220BC000B0380 /* StatusCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusCode.swift; sourceTree = ""; }; + 7909C6672352214C000B0380 /* CodableSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableSerializer.swift; sourceTree = ""; }; + 7909C6692352216E000B0380 /* RestClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestClient.swift; sourceTree = ""; }; + 7909C66B2352218A000B0380 /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; + 7909C66D235221A3000B0380 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = ""; }; + 7909C66F23522287000B0380 /* RequestBuilderTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestBuilderTest.swift; sourceTree = ""; }; + 7909C671235222CC000B0380 /* RestClientTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestClientTest.swift; sourceTree = ""; }; + 7909C6742352232F000B0380 /* posts.successful.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = posts.successful.json; path = ../../../fakestagramTests/casettes/posts.successful.json; sourceTree = ""; }; + 7909C67623522339000B0380 /* show_post.successful.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = show_post.successful.json; path = ../../../fakestagramTests/casettes/show_post.successful.json; sourceTree = ""; }; + 7909C67923523BE3000B0380 /* PostXIBViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostXIBViewController.swift; sourceTree = ""; }; + 7909C67A23523BE3000B0380 /* PostXIBViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PostXIBViewController.xib; sourceTree = ""; }; + 7909C67D23524566000B0380 /* Comment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; + 7909C67F23524576000B0380 /* Like.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Like.swift; sourceTree = ""; }; + 7909C6812352458A000B0380 /* Author.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Author.swift; sourceTree = ""; }; + 7909C685235246FE000B0380 /* AuthorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorView.swift; sourceTree = ""; }; + 79762856235A787300055EC7 /* PostsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsViewController.swift; sourceTree = ""; }; + 79762858235A80F500055EC7 /* PostCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PostCollectionViewCell.swift; path = "Fakestagram-Xcode10/Views/PostCollectionViewCell.swift"; sourceTree = SOURCE_ROOT; }; + 79762859235A80F500055EC7 /* PostCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = PostCollectionViewCell.xib; path = "Fakestagram-Xcode10/Views/PostCollectionViewCell.xib"; sourceTree = SOURCE_ROOT; }; + 7F32B394EBB804D9C3E14052 /* Pods_Fakestagram_Xcode10.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Fakestagram_Xcode10.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CC485714B1528A06F25D0EB3 /* Pods_Fakestagram_Xcode10Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Fakestagram_Xcode10Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + DCED9AC22B8D6D07928F1A67 /* Pods-Fakestagram-Xcode10Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fakestagram-Xcode10Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Fakestagram-Xcode10Tests/Pods-Fakestagram-Xcode10Tests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -43,6 +101,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F2AD903247DD33845EA3C7FB /* Pods_Fakestagram_Xcode10.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -50,18 +109,41 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 42ADD56BE4D4255623EA9AEC /* Pods_Fakestagram_Xcode10Tests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1E8E3DAADB2EC5DBC6F876A2 /* Pods */ = { + isa = PBXGroup; + children = ( + 4C3E60F528DFC01A73C34495 /* Pods-Fakestagram-Xcode10.debug.xcconfig */, + 658CC8D2CB4B6BE6E65EE461 /* Pods-Fakestagram-Xcode10.release.xcconfig */, + DCED9AC22B8D6D07928F1A67 /* Pods-Fakestagram-Xcode10Tests.debug.xcconfig */, + 0FF38D441F0DD6993050E737 /* Pods-Fakestagram-Xcode10Tests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 669AAED6AAD6DCBC5277E44C /* Frameworks */ = { + isa = PBXGroup; + children = ( + 7F32B394EBB804D9C3E14052 /* Pods_Fakestagram_Xcode10.framework */, + CC485714B1528A06F25D0EB3 /* Pods_Fakestagram_Xcode10Tests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 7701BEA4233F1B1B0004C30D = { isa = PBXGroup; children = ( 7701BEAF233F1B1B0004C30D /* Fakestagram-Xcode10 */, 7701BEC4233F1B1C0004C30D /* Fakestagram-Xcode10Tests */, 7701BEAE233F1B1B0004C30D /* Products */, + 1E8E3DAADB2EC5DBC6F876A2 /* Pods */, + 669AAED6AAD6DCBC5277E44C /* Frameworks */, ); sourceTree = ""; }; @@ -77,12 +159,21 @@ 7701BEAF233F1B1B0004C30D /* Fakestagram-Xcode10 */ = { isa = PBXGroup; children = ( + 7909C67823523B52000B0380 /* Views */, + 7909C65823521FD9000B0380 /* Network */, + 7909C65723521FD3000B0380 /* DataSource */, + 7909C65623521FCD000B0380 /* Model */, 7701BEB0233F1B1B0004C30D /* AppDelegate.swift */, - 7701BED0233F1B540004C30D /* PostsTableViewController.swift */, - 7701BEB4233F1B1B0004C30D /* Main.storyboard */, 7701BEB7233F1B1C0004C30D /* Assets.xcassets */, - 7701BEB9233F1B1C0004C30D /* LaunchScreen.storyboard */, 7701BEBC233F1B1C0004C30D /* Info.plist */, + 7701BEB4233F1B1B0004C30D /* Main.storyboard */, + 7706D145235B679900290A16 /* CameraViewController.swift */, + 7706D147235B6DCA00290A16 /* UIImage+Base64.swift */, + 7701BEB9233F1B1C0004C30D /* LaunchScreen.storyboard */, + 79762856235A787300055EC7 /* PostsViewController.swift */, + 7909C65923521FEC000B0380 /* Credentials.swift */, + 7909C65B23522002000B0380 /* PostViewController.swift */, + 7706D143235B583000290A16 /* UIDevice+models.swift */, ); path = "Fakestagram-Xcode10"; sourceTree = ""; @@ -90,12 +181,68 @@ 7701BEC4233F1B1C0004C30D /* Fakestagram-Xcode10Tests */ = { isa = PBXGroup; children = ( + 7909C673235222E9000B0380 /* casettes */, 7701BEC5233F1B1C0004C30D /* Fakestagram_Xcode10Tests.swift */, 7701BEC7233F1B1C0004C30D /* Info.plist */, + 7909C66F23522287000B0380 /* RequestBuilderTest.swift */, + 7909C671235222CC000B0380 /* RestClientTest.swift */, ); path = "Fakestagram-Xcode10Tests"; sourceTree = ""; }; + 7909C65623521FCD000B0380 /* Model */ = { + isa = PBXGroup; + children = ( + 7909C66B2352218A000B0380 /* Account.swift */, + 7909C66D235221A3000B0380 /* Post.swift */, + 7909C67D23524566000B0380 /* Comment.swift */, + 7909C67F23524576000B0380 /* Like.swift */, + 7909C6812352458A000B0380 /* Author.swift */, + ); + path = Model; + sourceTree = ""; + }; + 7909C65723521FD3000B0380 /* DataSource */ = { + isa = PBXGroup; + children = ( + 7909C6672352214C000B0380 /* CodableSerializer.swift */, + 7909C6692352216E000B0380 /* RestClient.swift */, + ); + path = DataSource; + sourceTree = ""; + }; + 7909C65823521FD9000B0380 /* Network */ = { + isa = PBXGroup; + children = ( + 7909C65D23522061000B0380 /* Client.swift */, + 7909C65F23522082000B0380 /* HttpResponse.swift */, + 7909C66123522091000B0380 /* RequestBuilder.swift */, + 7909C665235220BC000B0380 /* StatusCode.swift */, + ); + path = Network; + sourceTree = ""; + }; + 7909C673235222E9000B0380 /* casettes */ = { + isa = PBXGroup; + children = ( + 7909C67623522339000B0380 /* show_post.successful.json */, + 7909C6742352232F000B0380 /* posts.successful.json */, + ); + path = casettes; + sourceTree = ""; + }; + 7909C67823523B52000B0380 /* Views */ = { + isa = PBXGroup; + children = ( + 7909C67923523BE3000B0380 /* PostXIBViewController.swift */, + 7909C67A23523BE3000B0380 /* PostXIBViewController.xib */, + 79762858235A80F500055EC7 /* PostCollectionViewCell.swift */, + 79762859235A80F500055EC7 /* PostCollectionViewCell.xib */, + 7909C685235246FE000B0380 /* AuthorView.swift */, + ); + path = Views; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -103,6 +250,7 @@ isa = PBXNativeTarget; buildConfigurationList = 7701BECA233F1B1C0004C30D /* Build configuration list for PBXNativeTarget "Fakestagram-Xcode10" */; buildPhases = ( + 02C45B087AA30EC392B7E149 /* [CP] Check Pods Manifest.lock */, 7701BEA9233F1B1B0004C30D /* Sources */, 7701BEAA233F1B1B0004C30D /* Frameworks */, 7701BEAB233F1B1B0004C30D /* Resources */, @@ -120,9 +268,11 @@ isa = PBXNativeTarget; buildConfigurationList = 7701BECD233F1B1C0004C30D /* Build configuration list for PBXNativeTarget "Fakestagram-Xcode10Tests" */; buildPhases = ( + 476D3405109D2C9C30434EAD /* [CP] Check Pods Manifest.lock */, 7701BEBD233F1B1C0004C30D /* Sources */, 7701BEBE233F1B1C0004C30D /* Frameworks */, 7701BEBF233F1B1C0004C30D /* Resources */, + BA0879C76D711A1732B47837 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -179,7 +329,9 @@ files = ( 7701BEBB233F1B1C0004C30D /* LaunchScreen.storyboard in Resources */, 7701BEB8233F1B1C0004C30D /* Assets.xcassets in Resources */, + 7909C67C23523BE3000B0380 /* PostXIBViewController.xib in Resources */, 7701BEB6233F1B1B0004C30D /* Main.storyboard in Resources */, + 7976285B235A80F500055EC7 /* PostCollectionViewCell.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -187,18 +339,103 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 7909C6752352232F000B0380 /* posts.successful.json in Resources */, + 7909C67723522339000B0380 /* show_post.successful.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 02C45B087AA30EC392B7E149 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Fakestagram-Xcode10-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 476D3405109D2C9C30434EAD /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Fakestagram-Xcode10Tests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + BA0879C76D711A1732B47837 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Fakestagram-Xcode10Tests/Pods-Fakestagram-Xcode10Tests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Fakestagram-Xcode10Tests/Pods-Fakestagram-Xcode10Tests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Fakestagram-Xcode10Tests/Pods-Fakestagram-Xcode10Tests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 7701BEA9233F1B1B0004C30D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7701BED1233F1B540004C30D /* PostsTableViewController.swift in Sources */, + 7909C66223522091000B0380 /* RequestBuilder.swift in Sources */, + 7706D146235B679900290A16 /* CameraViewController.swift in Sources */, + 7909C66C2352218A000B0380 /* Account.swift in Sources */, + 7909C66023522082000B0380 /* HttpResponse.swift in Sources */, + 7909C67E23524566000B0380 /* Comment.swift in Sources */, + 7909C67B23523BE3000B0380 /* PostXIBViewController.swift in Sources */, + 7909C66E235221A3000B0380 /* Post.swift in Sources */, + 7909C666235220BC000B0380 /* StatusCode.swift in Sources */, + 7909C65C23522002000B0380 /* PostViewController.swift in Sources */, + 7909C65A23521FEC000B0380 /* Credentials.swift in Sources */, + 7909C68023524576000B0380 /* Like.swift in Sources */, + 7909C6822352458A000B0380 /* Author.swift in Sources */, + 79762857235A787300055EC7 /* PostsViewController.swift in Sources */, + 7909C65E23522061000B0380 /* Client.swift in Sources */, + 7976285A235A80F500055EC7 /* PostCollectionViewCell.swift in Sources */, + 7706D144235B583000290A16 /* UIDevice+models.swift in Sources */, + 7909C6682352214C000B0380 /* CodableSerializer.swift in Sources */, + 7909C686235246FE000B0380 /* AuthorView.swift in Sources */, + 7909C66A2352216E000B0380 /* RestClient.swift in Sources */, 7701BEB1233F1B1B0004C30D /* AppDelegate.swift in Sources */, + 7706D148235B6DCA00290A16 /* UIImage+Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -207,6 +444,8 @@ buildActionMask = 2147483647; files = ( 7701BEC6233F1B1C0004C30D /* Fakestagram_Xcode10Tests.swift in Sources */, + 7909C672235222CC000B0380 /* RestClientTest.swift in Sources */, + 7909C67023522287000B0380 /* RequestBuilderTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -358,16 +597,17 @@ }; 7701BECB233F1B1C0004C30D /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4C3E60F528DFC01A73C34495 /* Pods-Fakestagram-Xcode10.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = F2BL68NTA5; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "Fakestagram-Xcode10/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = "unam.Fakestagram-Xcode10"; + PRODUCT_BUNDLE_IDENTIFIER = unam.Fakestagram; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -376,16 +616,17 @@ }; 7701BECC233F1B1C0004C30D /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 658CC8D2CB4B6BE6E65EE461 /* Pods-Fakestagram-Xcode10.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = F2BL68NTA5; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "Fakestagram-Xcode10/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = "unam.Fakestagram-Xcode10"; + PRODUCT_BUNDLE_IDENTIFIER = unam.Fakestagram; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -394,6 +635,7 @@ }; 7701BECE233F1B1C0004C30D /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = DCED9AC22B8D6D07928F1A67 /* Pods-Fakestagram-Xcode10Tests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -415,6 +657,7 @@ }; 7701BECF233F1B1C0004C30D /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 0FF38D441F0DD6993050E737 /* Pods-Fakestagram-Xcode10Tests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10.xcodeproj/xcuserdata/richard_ohg.xcuserdatad/xcschemes/xcschememanagement.plist b/Fakestagram-Xcode10/Fakestagram-Xcode10.xcodeproj/xcuserdata/richard_ohg.xcuserdatad/xcschemes/xcschememanagement.plist index 117850a..08505b2 100644 --- a/Fakestagram-Xcode10/Fakestagram-Xcode10.xcodeproj/xcuserdata/richard_ohg.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10.xcodeproj/xcuserdata/richard_ohg.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ Fakestagram-Xcode10.xcscheme_^#shared#^_ orderHint - 0 + 3 diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10.xcworkspace/contents.xcworkspacedata b/Fakestagram-Xcode10/Fakestagram-Xcode10.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..962f334 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Fakestagram-Xcode10/Fakestagram-Xcode10.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/ay-papantla-tus.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/ay-papantla-tus.imageset/Contents.json new file mode 100644 index 0000000..b964475 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/ay-papantla-tus.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ay-papantla-tus.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/ay-papantla-tus.imageset/ay-papantla-tus.jpg b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/ay-papantla-tus.imageset/ay-papantla-tus.jpg new file mode 100644 index 0000000..7221906 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/ay-papantla-tus.imageset/ay-papantla-tus.jpg differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/cloud-download.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/cloud-download.imageset/Contents.json new file mode 100644 index 0000000..f291573 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/cloud-download.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "cloud-download.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/cloud-download.imageset/cloud-download.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/cloud-download.imageset/cloud-download.png new file mode 100644 index 0000000..332a19e Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/cloud-download.imageset/cloud-download.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments.imageset/Contents.json new file mode 100644 index 0000000..09b1d73 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "com.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments.imageset/com.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments.imageset/com.png new file mode 100644 index 0000000..62a1f2f Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments.imageset/com.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments1.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments1.imageset/Contents.json new file mode 100644 index 0000000..9d60554 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "comments1.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments1.imageset/comments1.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments1.imageset/comments1.png new file mode 100644 index 0000000..d9b97e9 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/comments1.imageset/comments1.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/harina.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/harina.imageset/Contents.json new file mode 100644 index 0000000..dfe0317 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/harina.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "harina.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/harina.imageset/harina.jpg b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/harina.imageset/harina.jpg new file mode 100644 index 0000000..6ebfe76 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/harina.imageset/harina.jpg differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home.imageset/Contents.json new file mode 100644 index 0000000..08ef703 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "home.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home.imageset/home.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home.imageset/home.png new file mode 100644 index 0000000..eb329b2 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home.imageset/home.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home1.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home1.imageset/Contents.json new file mode 100644 index 0000000..a35ebe3 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "home1.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home1.imageset/home1.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home1.imageset/home1.png new file mode 100644 index 0000000..c3f4a73 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/home1.imageset/home1.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like.imageset/Contents.json new file mode 100644 index 0000000..5126149 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "like.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like.imageset/like.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like.imageset/like.png new file mode 100644 index 0000000..de129f2 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like.imageset/like.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like1.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like1.imageset/Contents.json new file mode 100644 index 0000000..c8e33f4 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "like1.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like1.imageset/like1.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like1.imageset/like1.png new file mode 100644 index 0000000..575f103 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/like1.imageset/like1.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/loading.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/loading.imageset/Contents.json new file mode 100644 index 0000000..e3a1385 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/loading.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "loading.jpeg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/loading.imageset/loading.jpeg b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/loading.imageset/loading.jpeg new file mode 100644 index 0000000..e8e6b2b Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/loading.imageset/loading.jpeg differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus.imageset/Contents.json new file mode 100644 index 0000000..efcc220 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "plus.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus.imageset/plus.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus.imageset/plus.png new file mode 100644 index 0000000..cdfde97 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus.imageset/plus.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus1.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus1.imageset/Contents.json new file mode 100644 index 0000000..47ee2a9 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "plus1.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus1.imageset/plus1.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus1.imageset/plus1.png new file mode 100644 index 0000000..d9b3803 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/plus1.imageset/plus1.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile-2.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile-2.imageset/Contents.json new file mode 100644 index 0000000..a9c185a --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile-2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "profile-2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile-2.imageset/profile-2.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile-2.imageset/profile-2.png new file mode 100644 index 0000000..bb9e4cf Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile-2.imageset/profile-2.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile.imageset/Contents.json new file mode 100644 index 0000000..b199aaa --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "profile.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile.imageset/profile.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile.imageset/profile.png new file mode 100644 index 0000000..6960c37 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile.imageset/profile.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile1.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile1.imageset/Contents.json new file mode 100644 index 0000000..aea01e4 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "profile1.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile1.imageset/profile1.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile1.imageset/profile1.png new file mode 100644 index 0000000..76393ed Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile1.imageset/profile1.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile_default.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile_default.imageset/Contents.json new file mode 100644 index 0000000..fb9d0b8 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile_default.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "profile_default.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile_default.imageset/profile_default.png b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile_default.imageset/profile_default.png new file mode 100644 index 0000000..0dcfeb0 Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/profile_default.imageset/profile_default.png differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/space_cat.imageset/Contents.json b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/space_cat.imageset/Contents.json new file mode 100644 index 0000000..cc9c083 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/space_cat.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "space_cat.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/space_cat.imageset/space_cat.jpg b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/space_cat.imageset/space_cat.jpg new file mode 100644 index 0000000..fd13aaf Binary files /dev/null and b/Fakestagram-Xcode10/Fakestagram-Xcode10/Assets.xcassets/space_cat.imageset/space_cat.jpg differ diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Base.lproj/Main.storyboard b/Fakestagram-Xcode10/Fakestagram-Xcode10/Base.lproj/Main.storyboard index e29aa1a..75a5c6c 100644 --- a/Fakestagram-Xcode10/Fakestagram-Xcode10/Base.lproj/Main.storyboard +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Base.lproj/Main.storyboard @@ -1,57 +1,131 @@ - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/CameraViewController.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/CameraViewController.swift new file mode 100644 index 0000000..69598a5 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/CameraViewController.swift @@ -0,0 +1,42 @@ +// +// CameraViewController.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernández González on 10/19/19. +// Copyright © 2019 unam. All rights reserved. +// + +import UIKit + +class CameraViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + let client = RestClient(client: Client.fakestagram, basePath: "/api/v1/posts/") + + @IBAction func createPostBtn(_ sender: UIButton) { + let image = UIImage(named: "ay-papantla-tus")! + let newPost = CreatePost(title: "Es harina!!! - \(UUID().uuidString)", imageData: image.toBase64()) + + client.create(newPost) { (post) in + print("Aqueso") + } + + + } + +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Credentials.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Credentials.swift new file mode 100644 index 0000000..8e1f642 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Credentials.swift @@ -0,0 +1,24 @@ +// +// Credentials.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +enum Credentials { + case apiToken + + func get() -> String? { + switch self { + case .apiToken: + return "f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e" + } + } + + func set(value: String) -> Bool { + return true + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/DataSource/CodableSerializer.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/DataSource/CodableSerializer.swift new file mode 100644 index 0000000..afe03d7 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/DataSource/CodableSerializer.swift @@ -0,0 +1,35 @@ +// +// CodableSerializer.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +class CodableSerializer { + let data: Data? + let decoder: JSONDecoder = { + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + return decoder + }() + + init(data: Data?) { + self.data = data + } + + func async(result: @escaping (T?) -> Void) { + guard let data = data else { + DispatchQueue.main.async { result(nil) } + return + } + do { + let json = try decoder.decode(T.self, from: data) + DispatchQueue.main.async { result(json) } + } catch let err { + print("Invalid JSON format: \(err.localizedDescription)") + } + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/DataSource/RestClient.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/DataSource/RestClient.swift new file mode 100644 index 0000000..2e9b6b2 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/DataSource/RestClient.swift @@ -0,0 +1,58 @@ +// +// RestClient.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +class RestClient { + private let client: Client + let basePath: String + let encoder: JSONEncoder = { + let encoder = JSONEncoder() + encoder.keyEncodingStrategy = .convertToSnakeCase + return encoder + }() + + init(client: Client, basePath: String) { + self.client = client + self.basePath = basePath + } + + // eg. POST /posts/ + func create(_ data: T, success: @escaping (T?) -> Void) { + let payload = try? encoder.encode(data) + client.post(path: basePath, body: payload) { data in + CodableSerializer(data: data).async(result: success) + } + } + + // eg. GET /posts/ + // eg. GET /posts/:id + func show(id: String? = nil, success: @escaping (T?) -> Void) { + var path = basePath + if let uid = id { + path += "/\(uid)" + } + client.get(path: path) { data in + CodableSerializer(data: data).async(result: success) + } + } + // eg. PUT /posts/:id + func update(id: String, data: T, success: @escaping (T?) -> Void) { + let payload = try? encoder.encode(data) + client.put(path: "\(basePath)/\(id)", body: payload) { data in + CodableSerializer(data: data).async(result: success) + } + } + + // eg. DELETE /posts/:id + func delete(id: String, success: @escaping (T?) -> Void) { + client.delete(path: "\(basePath)/\(id)") { data in + CodableSerializer(data: data).async(result: success) + } + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Account.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Account.swift new file mode 100644 index 0000000..e5f806d --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Account.swift @@ -0,0 +1,16 @@ +// +// Account.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +struct Account: Codable { + let id: String? + let name: String + let deviceNumber: String + let deviceModel: String +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Author.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Author.swift new file mode 100644 index 0000000..072a4ce --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Author.swift @@ -0,0 +1,13 @@ +// +// Author.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +struct Author: Codable { + let name: String +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Comment.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Comment.swift new file mode 100644 index 0000000..9bc5a31 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Comment.swift @@ -0,0 +1,14 @@ +// +// Comment.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +struct Comment: Codable { + let content: String + let author: Author? +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Like.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Like.swift new file mode 100644 index 0000000..e259cff --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Like.swift @@ -0,0 +1,13 @@ +// +// Like.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +struct Like: Codable { + let author: Author +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Post.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Post.swift new file mode 100644 index 0000000..59e75cd --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Model/Post.swift @@ -0,0 +1,44 @@ +// +// Post.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation +import UIKit + +struct CreatePost: Codable { + let title: String + let imageData: String? +} + +struct Post: Codable { + let id: Int? + let title: String + let imageUrl: String? + var likesCount: Int + var commentsCount: Int + let createdAt: String + var liked: Bool + let location: String + let author: Author? + + func likesCountText() -> String { + return "\(likesCount) likes" + } + + func commentsCountText() -> String { + return "\(commentsCount) comments" + } + + func load(_ image: @escaping (UIImage) -> Void) { + guard let urlString = imageUrl, let url = URL(string: urlString) else { return } + DispatchQueue.global(qos: .background).async { + if let data = try? Data(contentsOf: url), let img = UIImage(data: data) { + DispatchQueue.main.async { image(img) } + } + } + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/Client.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/Client.swift new file mode 100644 index 0000000..b248b6b --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/Client.swift @@ -0,0 +1,68 @@ +// +// Client.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +class Client { + static let fakestagram = Client(session: URLSession.shared, baseUrl: "https://fakestagram-api.herokuapp.com") + let session: URLSession + let baseUrl: String + + init(session: URLSession, baseUrl: String) { + self.session = session + self.baseUrl = baseUrl + } + + typealias successfulResponse = (Data?) -> Void + + func get(path: String, success: @escaping successfulResponse) { + request(method: "get", path: path, body: nil, success: success) + } + + func post(path: String, body: Data?, success: @escaping successfulResponse) { + request(method: "post", path: path, body: body, success: success) + } + + func put(path: String, body: Data?, success: @escaping successfulResponse) { + request(method: "put", path: path, body: body, success: success) + } + + func delete(path: String, success: @escaping successfulResponse) { + request(method: "delete", path: path, body: nil, success: success) + } + + private func request(method: String, path: String, body: Data?, success: @escaping successfulResponse) { + guard let req = buildRequest(method: method, path: path, body: body) else { + debugPrint("Invalid request") + return + } + + session.dataTask(with: req) { (data, response, error) in + if let error = error { + debugPrint(error) + return + } + + let response = HttpResponse(response: response) + if response.isSuccessful() { + success(data) + } + }.resume() + } + + private func buildRequest(method: String, path: String, body: Data?) -> URLRequest? { + var builder = RequestBuilder(baseUrl: self.baseUrl) + builder.method = method + builder.path = path + builder.body = body + if let token = Credentials.apiToken.get() { + builder.headers = ["Authorization": "Bearer \(token)"] + } + return builder.request() + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/HttpResponse.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/HttpResponse.swift new file mode 100644 index 0000000..d8d6f32 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/HttpResponse.swift @@ -0,0 +1,25 @@ +// +// HttpResponse.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +class HttpResponse { + let httpUrlResponse: HTTPURLResponse + + init(response: URLResponse?) { + self.httpUrlResponse = response as! HTTPURLResponse + } + + lazy var status: StatusCode = { + return StatusCode(rawValue: self.httpUrlResponse.statusCode) + }() + + func isSuccessful() -> Bool { + return status == StatusCode.success + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/RequestBuilder.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/RequestBuilder.swift new file mode 100644 index 0000000..32f5f22 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/RequestBuilder.swift @@ -0,0 +1,62 @@ +// +// RequestBuilder.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +struct RequestBuilder { + enum ContentMode { + case jsonApp + + func accept() -> String { + switch self { + case .jsonApp: + return "application/json" + } + } + + func contentType() -> String { + switch self { + case .jsonApp: + return "application/json" + } + } + } + private let urlComponents: URLComponents + public var scheme: String = "https" + public var method: String = "get" + public var path: String = "/" + public var body: Data? + public var headers: [String: String]? + public var contentMode: ContentMode = .jsonApp + + init(baseUrl: String) { + self.urlComponents = URLComponents(string: baseUrl)! + } + + func url() -> URL? { + var comps = self.urlComponents + comps.scheme = scheme + comps.path = path + return comps.url + } + + func request() -> URLRequest? { + guard let url = url() else { return nil } + var req = URLRequest(url: url) + req.httpMethod = method + req.httpBody = body + req.addValue(contentMode.accept(), forHTTPHeaderField: "Accept") + req.addValue(contentMode.contentType(), forHTTPHeaderField: "Content-Type") + if let headers = self.headers { + for (key, value) in headers { + req.addValue(value, forHTTPHeaderField: key) + } + } + return req + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/Sat.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/Sat.swift new file mode 100644 index 0000000..b1f3686 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/Sat.swift @@ -0,0 +1,10 @@ + +// +// Sat.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/StatusCode.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/StatusCode.swift new file mode 100644 index 0000000..87b9b12 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Network/StatusCode.swift @@ -0,0 +1,36 @@ +// +// StatusCode.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation + +enum StatusCode: Int { + case unkown = 0 + case info + case success + case redirection + case clientError + case serverError + + public init(rawValue: Int) { + switch rawValue { + case 100, 101, 102: + self = .info + case 200, 201, 202, 203, 204, 205, 206, 207, 208, 226: + self = .success + case 300, 301, 302, 303, 304, 305, 306, 307, 308: + self = .redirection + case 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 421, 422, 423, 424, 426, 428, 429, 431, 451: + self = .clientError + case 500, 501, 502, 503, 504, 505, 506, 507, 510, 511: + self = .serverError + default: + self = .unkown + } + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/PostViewController.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/PostViewController.swift new file mode 100644 index 0000000..da9ee7f --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/PostViewController.swift @@ -0,0 +1,98 @@ +// +// PostViewController.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import UIKit + +class PostViewController: UIViewController { + var post: Post? { + didSet { + updatePostView() + } + } + @IBOutlet weak var imageView: UIImageView! + + override func viewDidLoad() { + super.viewDidLoad() + updatePostView() + loadComments { comments in + debugPrint(comments) + } + + // Do any additional setup after loading the view. + } + + func updatePostView() { + guard let post = post else { return } + post.load { img in + DispatchQueue.main.async { + self.imageView.image = img + } + } + } + + /* + // MARK: - Navigation + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + func loadComments(successful: @escaping ([Comment]) -> Void) { + guard let uwrappedPost = post, let postId = uwrappedPost.id else { return } + let url = URL(string: "https://fakestagram-api.herokuapp.com/api/v1/posts/\(postId)/comments")! + var request = URLRequest(url: url) + request.setValue("application/json", forHTTPHeaderField: "Accept") + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.httpMethod = "get" + request.addValue("Bearer f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e", forHTTPHeaderField: "Authorization") + + let task = URLSession.shared.dataTask(with: request) { (data, _, error) in + if error != nil || data == nil { + return + } + // get status code + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + do { + guard let data = data else { print("Empty response"); return } + let json = try decoder.decode([Comment].self, from: data) + successful(json) + } catch let err { + print("Unable to parse successfull response: \(err.localizedDescription)") + } + } + task.resume() + } + + func loadLikes(successful: @escaping ([Like]) -> Void) { + guard let uwrappedPost = post, let postId = uwrappedPost.id else { return } + let url = URL(string: "https://fakestagram-api.herokuapp.com/api/v1/posts/\(postId)/likes")! + var request = URLRequest(url: url) + request.setValue("application/json", forHTTPHeaderField: "Accept") + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.httpMethod = "get" + request.addValue("Bearer f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e", forHTTPHeaderField: "Authorization") + + let task = URLSession.shared.dataTask(with: request) { (data, _, error) in + if error != nil || data == nil { + return + } + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + do { + guard let data = data else { print("Empty response"); return } + let json = try decoder.decode([Like].self, from: data) + successful(json) + } catch let err { + print("Unable to parse successfull response: \(err.localizedDescription)") + } + } + task.resume() + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/PostsTableViewController.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/PostsTableViewController.swift deleted file mode 100644 index a54149b..0000000 --- a/Fakestagram-Xcode10/Fakestagram-Xcode10/PostsTableViewController.swift +++ /dev/null @@ -1,149 +0,0 @@ -// -// PostsTableViewController.swift -// fakestagram -// -// Created by LuisE on 9/24/19. -// Copyright © 2019 3zcurdia. All rights reserved. -// - -import UIKit - -struct Post: Codable { - let id: Int? - let title: String - let imageUrl: String? - var likesCount: Int - var commentsCount: Int - let createdAt: String - var liked: Bool - let location: String - - func likesCountText() -> String { - return "\(likesCount) likes" - } - - func commentsCountText() -> String { - return "\(commentsCount) comments" - } - - func load(_ image: @escaping (UIImage) -> Void) { - guard let urlString = imageUrl, let url = URL(string: urlString) else { return } - DispatchQueue.global(qos: .background).async { - if let data = try? Data(contentsOf: url), let img = UIImage(data: data) { - DispatchQueue.main.async { image(img) } - } - } - } -} - -class PostsTableViewController: UITableViewController { - static let cellId = "PostCell" - var posts = [Post]() - - override func viewDidLoad() { - super.viewDidLoad() - loadPosts { data in - DispatchQueue.main.async { - self.posts = data - self.tableView.reloadData() - } - } - - // Uncomment the following line to preserve selection between presentations - // self.clearsSelectionOnViewWillAppear = false - - // Uncomment the following line to display an Edit button in the navigation bar for this view controller. - // self.navigationItem.rightBarButtonItem = self.editButtonItem - } - - // MARK: - Table view data source - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return posts.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: PostsTableViewController.cellId, for: indexPath) - posts[indexPath.row].load { img in - cell.imageView?.contentMode = .scaleAspectFit - cell.imageView?.image = img - } - cell.textLabel?.text = posts[indexPath.row].title - cell.detailTextLabel?.text = posts[indexPath.row].location - - return cell - } - - /* - // Override to support conditional editing of the table view. - override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - // Return false if you do not want the specified item to be editable. - return true - } - */ - - /* - // Override to support editing the table view. - override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .delete { - // Delete the row from the data source - tableView.deleteRows(at: [indexPath], with: .fade) - } else if editingStyle == .insert { - // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view - } - } - */ - - /* - // Override to support rearranging the table view. - override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) { - - } - */ - - /* - // Override to support conditional rearranging of the table view. - override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { - // Return false if you do not want the item to be re-orderable. - return true - } - */ - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ - - func loadPosts(successful: @escaping ([Post]) -> Void) { - var request = URLRequest(url: URL(string: "https://fakestagram-api.herokuapp.com/api/v1/posts")!) - request.setValue("application/json", forHTTPHeaderField: "Accept") - request.setValue("application/json", forHTTPHeaderField: "Content-Type") - request.httpMethod = "get" - request.addValue("Bearer f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e", forHTTPHeaderField: "Authorization") - - let task = URLSession.shared.dataTask(with: request) { (data, _, error) in - if error != nil || data == nil { - return - } - let decoder = JSONDecoder() - decoder.keyDecodingStrategy = .convertFromSnakeCase - do { - guard let data = data else { print("Empty response"); return } - let json = try decoder.decode([Post].self, from: data) - successful(json) - } catch let err { - print("Unable to parse successfull response: \(err.localizedDescription)") - } - } - task.resume() - } -} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/PostsViewController.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/PostsViewController.swift new file mode 100644 index 0000000..e922384 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/PostsViewController.swift @@ -0,0 +1,75 @@ +// +// PostsViewController.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/18/19. +// Copyright © 2019 unam. All rights reserved. +// + +import UIKit + +class PostsViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { + + var posts: [Post]? { + didSet{ + self.postsCollection.reloadData() + } + } + + let client = RestClient<[Post]>(client: Client.fakestagram, basePath: "/api/v1/posts") + let refreshControl = UIRefreshControl() + + @IBOutlet weak var postsCollection: UICollectionView! + + override func viewDidLoad() { + super.viewDidLoad() + + postsCollection.delegate = self + postsCollection.dataSource = self + let nib = UINib(nibName: "PostCollectionViewCell", bundle: nil) +// let nib = UINib(nibName: String(describing: PostCollectionViewCell.self), bundle: nil) + postsCollection.register(nib, forCellWithReuseIdentifier: PostCollectionViewCell.identifier) + refreshControl.addTarget(self, action: #selector(reloadData), for: UIControl.Event.valueChanged) + + // Do any additional setup after loading the view. + } + + @objc func reloadData(){ + client.show { [unowned self] data in + self.posts = data + sleep(1) + self.refreshControl.endRefreshing() + } + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + + // MARK: - UICollection View Delegates + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return posts?.count ?? 0 + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PostCollectionViewCell.identifier, for: indexPath) as! PostCollectionViewCell + guard let posts = self.posts else { return cell } + cell.post = posts[indexPath.row] + return cell + + } + + // MARK: - Flow Layout Delegates + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: self.view.frame.width , height: 650) + } + + +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/UIDevice+models.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/UIDevice+models.swift new file mode 100644 index 0000000..d74d4d5 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/UIDevice+models.swift @@ -0,0 +1,88 @@ +// +// UIDevice+models.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernández González on 10/19/19. +// Copyright © 2019 unam. All rights reserved. +// + +import UIKit + +public extension UIDevice { + + static let modelName: String = { + var systemInfo = utsname() + uname(&systemInfo) + let machineMirror = Mirror(reflecting: systemInfo.machine) + let identifier = machineMirror.children.reduce("") { identifier, element in + guard let value = element.value as? Int8, value != 0 else { return identifier } + return identifier + String(UnicodeScalar(UInt8(value))) + } + + func mapToDevice(identifier: String) -> String { // swiftlint:disable:this cyclomatic_complexity + #if os(iOS) + switch identifier { + case "iPod5,1": return "iPod touch (5th generation)" + case "iPod7,1": return "iPod touch (6th generation)" + case "iPod9,1": return "iPod touch (7th generation)" + case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4" + case "iPhone4,1": return "iPhone 4s" + case "iPhone5,1", "iPhone5,2": return "iPhone 5" + case "iPhone5,3", "iPhone5,4": return "iPhone 5c" + case "iPhone6,1", "iPhone6,2": return "iPhone 5s" + case "iPhone7,2": return "iPhone 6" + case "iPhone7,1": return "iPhone 6 Plus" + case "iPhone8,1": return "iPhone 6s" + case "iPhone8,2": return "iPhone 6s Plus" + case "iPhone9,1", "iPhone9,3": return "iPhone 7" + case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus" + case "iPhone8,4": return "iPhone SE" + case "iPhone10,1", "iPhone10,4": return "iPhone 8" + case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus" + case "iPhone10,3", "iPhone10,6": return "iPhone X" + case "iPhone11,2": return "iPhone XS" + case "iPhone11,4", "iPhone11,6": return "iPhone XS Max" + case "iPhone11,8": return "iPhone XR" + case "iPhone12,1": return "iPhone 11" + case "iPhone12,3": return "iPhone 11 Pro" + case "iPhone12,5": return "iPhone 11 Pro Max" + case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2" + case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad (3rd generation)" + case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad (4th generation)" + case "iPad6,11", "iPad6,12": return "iPad (5th generation)" + case "iPad7,5", "iPad7,6": return "iPad (6th generation)" + case "iPad7,11", "iPad7,12": return "iPad (7th generation)" + case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air" + case "iPad5,3", "iPad5,4": return "iPad Air 2" + case "iPad11,4", "iPad11,5": return "iPad Air (3rd generation)" + case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad mini" + case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad mini 2" + case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad mini 3" + case "iPad5,1", "iPad5,2": return "iPad mini 4" + case "iPad11,1", "iPad11,2": return "iPad mini (5th generation)" + case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)" + case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch)" + case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch) (2nd generation)" + case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)" + case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4":return "iPad Pro (11-inch)" + case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8":return "iPad Pro (12.9-inch) (3rd generation)" + case "AppleTV5,3": return "Apple TV" + case "AppleTV6,2": return "Apple TV 4K" + case "AudioAccessory1,1": return "HomePod" + case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))" + default: return identifier + } + #elseif os(tvOS) + switch identifier { + case "AppleTV5,3": return "Apple TV 4" + case "AppleTV6,2": return "Apple TV 4K" + case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))" + default: return identifier + } + #endif + } + + return mapToDevice(identifier: identifier) + }() + +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/UIImage+Base64.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/UIImage+Base64.swift new file mode 100644 index 0000000..a4e6f3e --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/UIImage+Base64.swift @@ -0,0 +1,17 @@ +// +// UIImage+Base64.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernández González on 10/19/19. +// Copyright © 2019 unam. All rights reserved. +// + +import UIKit + +extension UIImage{ + func toBase64() -> String{ + let data = self.jpegData(compressionQuality: 90)! + let encoded = data.base64EncodedString(options: .lineLength64Characters) + return "data:image/jpg;base64,\(encoded)" + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/AuthorView.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/AuthorView.swift new file mode 100644 index 0000000..010dfaa --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/AuthorView.swift @@ -0,0 +1,72 @@ +// +// AuthorView.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import UIKit + +@IBDesignable +class AuthorView: UIView{ + var author: Author? { + didSet { updateContent() } + } + + private let avatar: UIImageView = { + let iv = UIImageView() + iv.image = UIImage(named: "profile-2") +// iv.backgroundColor = + iv.contentMode = .scaleToFill + iv.translatesAutoresizingMaskIntoConstraints = false + return iv + }() + + private let nameLbl: UILabel = { + let lbl = UILabel() + lbl.text = "Lorem ipsum" + lbl.font = UIFont.systemFont(ofSize: 32) + lbl.translatesAutoresizingMaskIntoConstraints = false + return lbl + }() + + convenience init() { + self.init(frame: .zero) + } + + override init(frame: CGRect) { + super.init(frame: frame) + setupConstraints() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupConstraints() + } + + func setupConstraints(){ + addSubview(avatar) +// avatar.topAnchor.constraint(equalTo: self.topAnchor, constant: 3).isActive = true +// Para evitar estar haciendo isActive por cada constraint utilizamos NSLayoutConstraint.activate + NSLayoutConstraint.activate([ + avatar.topAnchor.constraint(equalTo: self.topAnchor, constant: 5), + avatar.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5), + avatar.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -5), + avatar.widthAnchor.constraint(equalToConstant: 90) +// avatar.heightAnchor.constraint(equalToConstant: self.frame.height-6) + ]) + + addSubview(nameLbl) + NSLayoutConstraint.activate([ + nameLbl.leadingAnchor.constraint(equalTo: avatar.trailingAnchor, constant: 5), + nameLbl.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -5), + nameLbl.centerYAnchor.constraint(equalTo: self.centerYAnchor) + ]) + } + + func updateContent() { + guard let uauthor = author else { return } + nameLbl.text = uauthor.name + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/File.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/File.swift new file mode 100644 index 0000000..d9cb0c6 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/File.swift @@ -0,0 +1,9 @@ +// +// File.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import Foundation diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostCollectionViewCell.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostCollectionViewCell.swift new file mode 100644 index 0000000..85ace9e --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostCollectionViewCell.swift @@ -0,0 +1,49 @@ +// +// PostCollectionViewCell.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/18/19. +// Copyright © 2019 unam. All rights reserved. +// + +import UIKit + +class PostCollectionViewCell: UICollectionViewCell { + + static let identifier = "PostCell" + var post: Post? { + didSet{ + updateView() + } + } + + @IBOutlet weak var authorView: AuthorView! + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var likeCounter: UILabel! + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var likeBttn: UIButton! + @IBOutlet weak var commentBttn: UIButton! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + func reset(){ + self.imageView.image = UIImage(named: "loading") + self.likeCounter.text = "" + self.titleLabel.text = "" + } + + func updateView(){ + reset() + guard let post = self.post else { return } + self.authorView.author = post.author + self.titleLabel?.text = post.title + self.likeCounter.text = post.likesCountText() + post.load { [unowned self] img in + self.imageView.image = img + } + } + +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostCollectionViewCell.xib b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostCollectionViewCell.xib new file mode 100644 index 0000000..64439c2 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostCollectionViewCell.xib @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostXIBViewController.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostXIBViewController.swift new file mode 100644 index 0000000..50d81d9 --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostXIBViewController.swift @@ -0,0 +1,47 @@ +// +// PostXIBViewController.swift +// Fakestagram-Xcode10 +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import UIKit + +class PostXIBViewController: UIViewController { + + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var likeCounter: UILabel! + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var likeBttn: UIButton! + @IBOutlet weak var commentBttn: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + @IBAction func onTapLike(_ sender: Any){ + print("Like") + } + + @IBAction func onTapCreateComment(_ sender: Any){ + print("Comment") + } + + @IBAction func onTapShowComments(_ sender: Any){ + print("Show comment") + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostXIBViewController.xib b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostXIBViewController.xib new file mode 100644 index 0000000..66f188b --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10/Views/PostXIBViewController.xib @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10Tests/RequestBuilderTest.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10Tests/RequestBuilderTest.swift new file mode 100644 index 0000000..3d9229c --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10Tests/RequestBuilderTest.swift @@ -0,0 +1,65 @@ +// +// RequestBuilderTest.swift +// Fakestagram-Xcode10Tests +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import XCTest +@testable import Fakestagram_Xcode10 + +class RequestBuilderTests: XCTestCase { + func testBuildValidURL() { + var builder = RequestBuilder(baseUrl: "https://example.com/") + builder.path = "/api/v1/accounts" + XCTAssertEqual(builder.scheme, "https") + XCTAssertEqual(builder.method, "get") + XCTAssertEqual(builder.url(), URL(string: "https://example.com/api/v1/accounts")!) + } + + func testBuildInvalidURL() { + var builder = RequestBuilder(baseUrl: "example.com") + builder.path = "//@3`-" + XCTAssertNil(builder.url()) + } + + func testBuildForceSchemeURL() { + let builder = RequestBuilder(baseUrl: "http://example.com/") + XCTAssertEqual(builder.url(), URL(string: "https://example.com/")!) + } + + func testBuildOverrideSchemeURL() { + var builder = RequestBuilder(baseUrl: "http://example.com/") + builder.scheme = "ftp" + XCTAssertEqual(builder.url(), URL(string: "ftp://example.com/")!) + } + + func testBuildInvalidRequest() { + var builder = RequestBuilder(baseUrl: "example.com") + builder.path = "//@3`-" + XCTAssertNil(builder.request()) + } + + func testBuildValidRequest() { + var builder = RequestBuilder(baseUrl: "https://example.com/") + builder.path = "/api/v1/accounts" + builder.method = "post" + builder.body = "{\"a\": 1}".data(using: .utf8) + builder.headers = ["test": "example"] + + let result = builder.request() + XCTAssertNotNil(result) + XCTAssertEqual(result!.httpMethod!, "POST") + XCTAssertEqual(result!.httpBody!, "{\"a\": 1}".data(using: .utf8)) + XCTAssertEqual(result!.allHTTPHeaderFields!, ["Accept": "application/json", "Content-Type": "application/json", "test": "example"]) + } + + func testBuildValidRequestWithDefaults() { + let result = RequestBuilder(baseUrl: "https://example.com/").request() + XCTAssertNotNil(result) + XCTAssertEqual(result!.httpMethod!, "GET") + XCTAssertNil(result!.httpBody) + XCTAssertEqual(result!.allHTTPHeaderFields!, ["Accept": "application/json", "Content-Type": "application/json"]) + } +} diff --git a/Fakestagram-Xcode10/Fakestagram-Xcode10Tests/RestClientTest.swift b/Fakestagram-Xcode10/Fakestagram-Xcode10Tests/RestClientTest.swift new file mode 100644 index 0000000..d6a9aaf --- /dev/null +++ b/Fakestagram-Xcode10/Fakestagram-Xcode10Tests/RestClientTest.swift @@ -0,0 +1,47 @@ +// +// RestClientTest.swift +// Fakestagram-Xcode10Tests +// +// Created by Ricardo Hernandez D4 on 10/12/19. +// Copyright © 2019 unam. All rights reserved. +// + +import XCTest +import DVR +@testable import Fakestagram_Xcode10 + +class RestClientTest: XCTestCase { + func testShowPosts() { + let session = Session(cassetteName: "posts.successful") + let client = Client(session: session, baseUrl: "https://fakestagram-api.herokuapp.com") + let restClient = RestClient<[Post]>(client: client, basePath: "/api/v1/posts") + let exp = expectation(description: "Successfull index posts") + + restClient.show { posts in + exp.fulfill() + XCTAssertNotNil(posts) + XCTAssertEqual(posts!.count, 25) + XCTAssertEqual(posts!.first!.id, 228) + XCTAssertEqual(posts!.first!.title, "Example") + } + + waitForExpectations(timeout: 2, handler: nil) + } + + func testShowPost() { + let session = Session(cassetteName: "show_post.successful") + let client = Client(session: session, baseUrl: "https://fakestagram-api.herokuapp.com") + + let restClient = RestClient(client: client, basePath: "/api/v1/posts") + let exp = expectation(description: "Successfull index posts") + + restClient.show(id: "228") { post in + exp.fulfill() + XCTAssertNotNil(post) + XCTAssertEqual(post!.id, 228) + XCTAssertEqual(post!.title, "Example") + } + + waitForExpectations(timeout: 2, handler: nil) + } +} diff --git a/Fakestagram-Xcode10/Podfile b/Fakestagram-Xcode10/Podfile new file mode 100644 index 0000000..84483e5 --- /dev/null +++ b/Fakestagram-Xcode10/Podfile @@ -0,0 +1,16 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'Fakestagram-Xcode10' do + # Comment the next line if you're not using Swift and don't want to use dynamic frameworks + use_frameworks! + + # Pods for Fakestagram-Xcode10 + + target 'Fakestagram-Xcode10Tests' do + inherit! :search_paths + # Pods for testing +pod 'DVR' + end + +end diff --git a/Fakestagram-Xcode10/Podfile.lock b/Fakestagram-Xcode10/Podfile.lock new file mode 100644 index 0000000..63bf30c --- /dev/null +++ b/Fakestagram-Xcode10/Podfile.lock @@ -0,0 +1,16 @@ +PODS: + - DVR (2.0.0) + +DEPENDENCIES: + - DVR + +SPEC REPOS: + https://github.com/cocoapods/specs.git: + - DVR + +SPEC CHECKSUMS: + DVR: 062c287b9dc613a84120e44640176e4ef3ecf943 + +PODFILE CHECKSUM: d9d5d9d01e457a56ba65f895a35d12a493621452 + +COCOAPODS: 1.7.5 diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..77cfa72 --- /dev/null +++ b/Podfile @@ -0,0 +1,14 @@ +# Uncomment the next line to define a global platform for your project +platform :ios, '13.0' + +target 'fakestagram' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + # Pods for fakestagram + pod 'SAMKeychain' + + target 'fakestagramTests' do + inherit! :search_paths + pod 'DVR' + end +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..b5bd883 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,20 @@ +PODS: + - DVR (2.0.0) + - SAMKeychain (1.5.3) + +DEPENDENCIES: + - DVR + - SAMKeychain + +SPEC REPOS: + trunk: + - DVR + - SAMKeychain + +SPEC CHECKSUMS: + DVR: 062c287b9dc613a84120e44640176e4ef3ecf943 + SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c + +PODFILE CHECKSUM: 02c21c317ba9be4fdecdfff242f3fa20e9b269bd + +COCOAPODS: 1.8.4 diff --git a/fakestagram.xcodeproj/project.pbxproj b/fakestagram.xcodeproj/project.pbxproj index e876e02..fabb45d 100644 --- a/fakestagram.xcodeproj/project.pbxproj +++ b/fakestagram.xcodeproj/project.pbxproj @@ -3,18 +3,56 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ + 05D8E963168944918FFCC7FF /* Pods_fakestagram.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFAA8B9133CEE464C903FDF5 /* Pods_fakestagram.framework */; }; + 773F6A542389BFF700AF7090 /* CreateLikeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773F6A532389BFF700AF7090 /* CreateLikeService.swift */; }; + 77840D5E239F0C4000EDC651 /* PreviewImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77840D5C239F0C4000EDC651 /* PreviewImageViewController.swift */; }; + 77840D5F239F0C4000EDC651 /* PreviewImageViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 77840D5D239F0C4000EDC651 /* PreviewImageViewController.xib */; }; + D3D164DC7444072103DE027D /* Pods_fakestagramTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E669E31C92D68155914FC99D /* Pods_fakestagramTests.framework */; }; + E023A5542380859200B13B7D /* NotificationKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = E023A5532380859200B13B7D /* NotificationKeys.swift */; }; E038FCED233FC78600E28571 /* PostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E038FCEC233FC78600E28571 /* PostViewController.swift */; }; + E045844923762E10006574FA /* CreatePostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E045844823762E10006574FA /* CreatePostService.swift */; }; + E045844B237652DD006574FA /* StorageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E045844A237652DD006574FA /* StorageType.swift */; }; + E045844D23765677006574FA /* DataContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E045844C23765677006574FA /* DataContainer.swift */; }; + E045844F23765B0F006574FA /* ImageStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E045844E23765B0F006574FA /* ImageStore.swift */; }; + E045845123766203006574FA /* CacheImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E045845023766203006574FA /* CacheImage.swift */; }; + E0458454237721F5006574FA /* CheckSum.m in Sources */ = {isa = PBXBuildFile; fileRef = E0458453237721F5006574FA /* CheckSum.m */; }; + E0458457237725B9006574FA /* IndexService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0458456237725B9006574FA /* IndexService.swift */; }; + E0458459237727D8006574FA /* CheckSumTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0458458237727D8006574FA /* CheckSumTest.swift */; }; E084FADA233A8734009AC50D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E084FAD9233A8734009AC50D /* AppDelegate.swift */; }; E084FADC233A8734009AC50D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E084FADB233A8734009AC50D /* SceneDelegate.swift */; }; E084FAE1233A8734009AC50D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E084FADF233A8734009AC50D /* Main.storyboard */; }; E084FAE3233A8735009AC50D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E084FAE2233A8735009AC50D /* Assets.xcassets */; }; E084FAE6233A8735009AC50D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E084FAE4233A8735009AC50D /* LaunchScreen.storyboard */; }; - E084FAF1233A8735009AC50D /* fakestagramTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E084FAF0233A8735009AC50D /* fakestagramTests.swift */; }; - E084FAFC233A8888009AC50D /* PostsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E084FAFB233A8888009AC50D /* PostsTableViewController.swift */; }; + E084FAF1233A8735009AC50D /* RequestBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E084FAF0233A8735009AC50D /* RequestBuilderTests.swift */; }; + E0A9ED51235A782F00A0527E /* PostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0A9ED50235A782F00A0527E /* PostsViewController.swift */; }; + E0A9ED54235A7FF300A0527E /* PostCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0A9ED52235A7FF300A0527E /* PostCollectionViewCell.swift */; }; + E0A9ED55235A7FF300A0527E /* PostCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = E0A9ED53235A7FF300A0527E /* PostCollectionViewCell.xib */; }; + E0C185F0237F92C700AD9983 /* PreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C185EF237F92C700AD9983 /* PreviewView.swift */; }; + E0C93E942351435100FD330C /* RestClientTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C93E932351435100FD330C /* RestClientTest.swift */; }; + E0C93E9923514D8800FD330C /* posts.successful.json in Resources */ = {isa = PBXBuildFile; fileRef = E0C93E9823514D8800FD330C /* posts.successful.json */; }; + E0C93E9B23515A0400FD330C /* show_post.successful.json in Resources */ = {isa = PBXBuildFile; fileRef = E0C93E9A23515A0400FD330C /* show_post.successful.json */; }; + E0C93E9D23515CEE00FD330C /* CodableSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C93E9C23515CEE00FD330C /* CodableSerializer.swift */; }; + E0C93EA123523B7C00FD330C /* ShowPostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C93E9F23523B7C00FD330C /* ShowPostViewController.swift */; }; + E0C93EA223523B7C00FD330C /* ShowPostViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E0C93EA023523B7C00FD330C /* ShowPostViewController.xib */; }; + E0C93EA42352452900FD330C /* AuthorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C93EA32352452900FD330C /* AuthorView.swift */; }; + E0C93EA62352454E00FD330C /* Author.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C93EA52352454E00FD330C /* Author.swift */; }; + E0C93EA82352455C00FD330C /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C93EA72352455C00FD330C /* Comment.swift */; }; + E0C93EAA2352457200FD330C /* Like.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C93EA92352457200FD330C /* Like.swift */; }; + E0E2545F235A9F3A00C55767 /* UIDevice+models.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E2545E235A9F3A00C55767 /* UIDevice+models.swift */; }; + E0E25463235B675100C55767 /* CameraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E25462235B675100C55767 /* CameraViewController.swift */; }; + E0E25465235B6C0500C55767 /* UIImage+Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E25464235B6C0500C55767 /* UIImage+Base64.swift */; }; + E0E8B9652348018200DA9D1A /* Credentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E8B9642348018200DA9D1A /* Credentials.swift */; }; + E0E8B9682348036D00DA9D1A /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E8B9672348036D00DA9D1A /* Client.swift */; }; + E0E8B96A23481D5A00DA9D1A /* StatusCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E8B96923481D5A00DA9D1A /* StatusCode.swift */; }; + E0E8B96C23481E1700DA9D1A /* HttpResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E8B96B23481E1700DA9D1A /* HttpResponse.swift */; }; + E0E8B96E2348203B00DA9D1A /* RequestBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E8B96D2348203B00DA9D1A /* RequestBuilder.swift */; }; + E0E8B971234916D100DA9D1A /* RestClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E8B970234916D100DA9D1A /* RestClient.swift */; }; + E0E8B974234918FF00DA9D1A /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E8B973234918FF00DA9D1A /* Account.swift */; }; + E0E8B9762349197100DA9D1A /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0E8B9752349197100DA9D1A /* Post.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -28,7 +66,25 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5E0AE2BFBF9C8D81E583E1BE /* Pods-fakestagramTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fakestagramTests.release.xcconfig"; path = "Target Support Files/Pods-fakestagramTests/Pods-fakestagramTests.release.xcconfig"; sourceTree = ""; }; + 66342726A6BCEEEF6289B1AA /* Pods-fakestagramTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fakestagramTests.debug.xcconfig"; path = "Target Support Files/Pods-fakestagramTests/Pods-fakestagramTests.debug.xcconfig"; sourceTree = ""; }; + 773F6A532389BFF700AF7090 /* CreateLikeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateLikeService.swift; sourceTree = ""; }; + 77840D5C239F0C4000EDC651 /* PreviewImageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewImageViewController.swift; sourceTree = ""; }; + 77840D5D239F0C4000EDC651 /* PreviewImageViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PreviewImageViewController.xib; sourceTree = ""; }; + CCC6C6EA9D17CA169951A745 /* Pods-fakestagram.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fakestagram.release.xcconfig"; path = "Target Support Files/Pods-fakestagram/Pods-fakestagram.release.xcconfig"; sourceTree = ""; }; + DB68F7FEC717545506064663 /* Pods-fakestagram.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fakestagram.debug.xcconfig"; path = "Target Support Files/Pods-fakestagram/Pods-fakestagram.debug.xcconfig"; sourceTree = ""; }; + E023A5532380859200B13B7D /* NotificationKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationKeys.swift; sourceTree = ""; }; E038FCEC233FC78600E28571 /* PostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostViewController.swift; sourceTree = ""; }; + E045844823762E10006574FA /* CreatePostService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePostService.swift; sourceTree = ""; }; + E045844A237652DD006574FA /* StorageType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageType.swift; sourceTree = ""; }; + E045844C23765677006574FA /* DataContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataContainer.swift; sourceTree = ""; }; + E045844E23765B0F006574FA /* ImageStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageStore.swift; sourceTree = ""; }; + E045845023766203006574FA /* CacheImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheImage.swift; sourceTree = ""; }; + E0458452237721F5006574FA /* fakestagram-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "fakestagram-Bridging-Header.h"; sourceTree = ""; }; + E0458453237721F5006574FA /* CheckSum.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CheckSum.m; sourceTree = ""; }; + E045845523772360006574FA /* CheckSum.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CheckSum.h; sourceTree = ""; }; + E0458456237725B9006574FA /* IndexService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndexService.swift; sourceTree = ""; }; + E0458458237727D8006574FA /* CheckSumTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckSumTest.swift; sourceTree = ""; }; E084FAD6233A8734009AC50D /* fakestagram.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = fakestagram.app; sourceTree = BUILT_PRODUCTS_DIR; }; E084FAD9233A8734009AC50D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; E084FADB233A8734009AC50D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -37,9 +93,35 @@ E084FAE5233A8735009AC50D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; E084FAE7233A8735009AC50D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E084FAEC233A8735009AC50D /* fakestagramTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = fakestagramTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - E084FAF0233A8735009AC50D /* fakestagramTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = fakestagramTests.swift; sourceTree = ""; }; + E084FAF0233A8735009AC50D /* RequestBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestBuilderTests.swift; sourceTree = ""; }; E084FAF2233A8735009AC50D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E084FAFB233A8888009AC50D /* PostsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsTableViewController.swift; sourceTree = ""; }; + E0A9ED50235A782F00A0527E /* PostsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsViewController.swift; sourceTree = ""; }; + E0A9ED52235A7FF300A0527E /* PostCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostCollectionViewCell.swift; sourceTree = ""; }; + E0A9ED53235A7FF300A0527E /* PostCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PostCollectionViewCell.xib; sourceTree = ""; }; + E0C185EF237F92C700AD9983 /* PreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewView.swift; sourceTree = ""; }; + E0C93E932351435100FD330C /* RestClientTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestClientTest.swift; sourceTree = ""; }; + E0C93E9823514D8800FD330C /* posts.successful.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = posts.successful.json; sourceTree = ""; }; + E0C93E9A23515A0400FD330C /* show_post.successful.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = show_post.successful.json; sourceTree = ""; }; + E0C93E9C23515CEE00FD330C /* CodableSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableSerializer.swift; sourceTree = ""; }; + E0C93E9F23523B7C00FD330C /* ShowPostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowPostViewController.swift; sourceTree = ""; }; + E0C93EA023523B7C00FD330C /* ShowPostViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShowPostViewController.xib; sourceTree = ""; }; + E0C93EA32352452900FD330C /* AuthorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorView.swift; sourceTree = ""; }; + E0C93EA52352454E00FD330C /* Author.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Author.swift; sourceTree = ""; }; + E0C93EA72352455C00FD330C /* Comment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; + E0C93EA92352457200FD330C /* Like.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Like.swift; sourceTree = ""; }; + E0E2545E235A9F3A00C55767 /* UIDevice+models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+models.swift"; sourceTree = ""; }; + E0E25462235B675100C55767 /* CameraViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraViewController.swift; sourceTree = ""; }; + E0E25464235B6C0500C55767 /* UIImage+Base64.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Base64.swift"; sourceTree = ""; }; + E0E8B9642348018200DA9D1A /* Credentials.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Credentials.swift; sourceTree = ""; }; + E0E8B9672348036D00DA9D1A /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; + E0E8B96923481D5A00DA9D1A /* StatusCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusCode.swift; sourceTree = ""; }; + E0E8B96B23481E1700DA9D1A /* HttpResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpResponse.swift; sourceTree = ""; }; + E0E8B96D2348203B00DA9D1A /* RequestBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestBuilder.swift; sourceTree = ""; }; + E0E8B970234916D100DA9D1A /* RestClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestClient.swift; sourceTree = ""; }; + E0E8B973234918FF00DA9D1A /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; + E0E8B9752349197100DA9D1A /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = ""; }; + E669E31C92D68155914FC99D /* Pods_fakestagramTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_fakestagramTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FFAA8B9133CEE464C903FDF5 /* Pods_fakestagram.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_fakestagram.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -47,6 +129,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 05D8E963168944918FFCC7FF /* Pods_fakestagram.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -54,18 +137,42 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D3D164DC7444072103DE027D /* Pods_fakestagramTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 01A08896D7765C060714CF7E /* Pods */ = { + isa = PBXGroup; + children = ( + DB68F7FEC717545506064663 /* Pods-fakestagram.debug.xcconfig */, + CCC6C6EA9D17CA169951A745 /* Pods-fakestagram.release.xcconfig */, + 66342726A6BCEEEF6289B1AA /* Pods-fakestagramTests.debug.xcconfig */, + 5E0AE2BFBF9C8D81E583E1BE /* Pods-fakestagramTests.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + E045844723762DF8006574FA /* Services */ = { + isa = PBXGroup; + children = ( + E045844823762E10006574FA /* CreatePostService.swift */, + E0458456237725B9006574FA /* IndexService.swift */, + 773F6A532389BFF700AF7090 /* CreateLikeService.swift */, + ); + path = Services; + sourceTree = ""; + }; E084FACD233A8734009AC50D = { isa = PBXGroup; children = ( E084FAD8233A8734009AC50D /* fakestagram */, E084FAEF233A8735009AC50D /* fakestagramTests */, E084FAD7233A8734009AC50D /* Products */, + 01A08896D7765C060714CF7E /* Pods */, + E59E91806B162F48B9F21B96 /* Frameworks */, ); sourceTree = ""; }; @@ -81,14 +188,22 @@ E084FAD8233A8734009AC50D /* fakestagram */ = { isa = PBXGroup; children = ( + E045844723762DF8006574FA /* Services */, + E0E25466235B7BCE00C55767 /* ViewControllers */, + E0C93E9E23523B4700FD330C /* Views */, + E0E8B972234918ED00DA9D1A /* Models */, + E0E8B96F234916AA00DA9D1A /* Network */, + E0E8B9662348035800DA9D1A /* DataSource */, + E0E25467235B7BE500C55767 /* Utils */, E084FAD9233A8734009AC50D /* AppDelegate.swift */, E084FADB233A8734009AC50D /* SceneDelegate.swift */, - E084FAFB233A8888009AC50D /* PostsTableViewController.swift */, E084FADF233A8734009AC50D /* Main.storyboard */, - E038FCEC233FC78600E28571 /* PostViewController.swift */, E084FAE2233A8735009AC50D /* Assets.xcassets */, E084FAE4233A8735009AC50D /* LaunchScreen.storyboard */, E084FAE7233A8735009AC50D /* Info.plist */, + E0458453237721F5006574FA /* CheckSum.m */, + E045845523772360006574FA /* CheckSum.h */, + E0458452237721F5006574FA /* fakestagram-Bridging-Header.h */, ); path = fakestagram; sourceTree = ""; @@ -96,12 +211,105 @@ E084FAEF233A8735009AC50D /* fakestagramTests */ = { isa = PBXGroup; children = ( - E084FAF0233A8735009AC50D /* fakestagramTests.swift */, + E0C93E952351472A00FD330C /* casettes */, + E084FAF0233A8735009AC50D /* RequestBuilderTests.swift */, + E0C93E932351435100FD330C /* RestClientTest.swift */, + E0458458237727D8006574FA /* CheckSumTest.swift */, E084FAF2233A8735009AC50D /* Info.plist */, ); path = fakestagramTests; sourceTree = ""; }; + E0C93E952351472A00FD330C /* casettes */ = { + isa = PBXGroup; + children = ( + E0C93E9A23515A0400FD330C /* show_post.successful.json */, + E0C93E9823514D8800FD330C /* posts.successful.json */, + ); + path = casettes; + sourceTree = ""; + }; + E0C93E9E23523B4700FD330C /* Views */ = { + isa = PBXGroup; + children = ( + E0C185EF237F92C700AD9983 /* PreviewView.swift */, + E0A9ED52235A7FF300A0527E /* PostCollectionViewCell.swift */, + E0A9ED53235A7FF300A0527E /* PostCollectionViewCell.xib */, + E0C93E9F23523B7C00FD330C /* ShowPostViewController.swift */, + E0C93EA023523B7C00FD330C /* ShowPostViewController.xib */, + E0C93EA32352452900FD330C /* AuthorView.swift */, + 77840D5C239F0C4000EDC651 /* PreviewImageViewController.swift */, + 77840D5D239F0C4000EDC651 /* PreviewImageViewController.xib */, + ); + path = Views; + sourceTree = ""; + }; + E0E25466235B7BCE00C55767 /* ViewControllers */ = { + isa = PBXGroup; + children = ( + E0A9ED50235A782F00A0527E /* PostsViewController.swift */, + E038FCEC233FC78600E28571 /* PostViewController.swift */, + E0E25462235B675100C55767 /* CameraViewController.swift */, + ); + path = ViewControllers; + sourceTree = ""; + }; + E0E25467235B7BE500C55767 /* Utils */ = { + isa = PBXGroup; + children = ( + E0E8B9642348018200DA9D1A /* Credentials.swift */, + E0E2545E235A9F3A00C55767 /* UIDevice+models.swift */, + E0E25464235B6C0500C55767 /* UIImage+Base64.swift */, + E023A5532380859200B13B7D /* NotificationKeys.swift */, + ); + path = Utils; + sourceTree = ""; + }; + E0E8B9662348035800DA9D1A /* DataSource */ = { + isa = PBXGroup; + children = ( + E0E8B970234916D100DA9D1A /* RestClient.swift */, + E0C93E9C23515CEE00FD330C /* CodableSerializer.swift */, + E045845023766203006574FA /* CacheImage.swift */, + E045844E23765B0F006574FA /* ImageStore.swift */, + E045844C23765677006574FA /* DataContainer.swift */, + E045844A237652DD006574FA /* StorageType.swift */, + ); + path = DataSource; + sourceTree = ""; + }; + E0E8B96F234916AA00DA9D1A /* Network */ = { + isa = PBXGroup; + children = ( + E0E8B9672348036D00DA9D1A /* Client.swift */, + E0E8B96923481D5A00DA9D1A /* StatusCode.swift */, + E0E8B96B23481E1700DA9D1A /* HttpResponse.swift */, + E0E8B96D2348203B00DA9D1A /* RequestBuilder.swift */, + ); + path = Network; + sourceTree = ""; + }; + E0E8B972234918ED00DA9D1A /* Models */ = { + isa = PBXGroup; + children = ( + E0E8B973234918FF00DA9D1A /* Account.swift */, + E0E8B9752349197100DA9D1A /* Post.swift */, + E0C93EA52352454E00FD330C /* Author.swift */, + E0C93EA72352455C00FD330C /* Comment.swift */, + E0C93EA92352457200FD330C /* Like.swift */, + ); + path = Models; + sourceTree = ""; + }; + E59E91806B162F48B9F21B96 /* Frameworks */ = { + isa = PBXGroup; + children = ( + FFAA8B9133CEE464C903FDF5 /* Pods_fakestagram.framework */, + E669E31C92D68155914FC99D /* Pods_fakestagramTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -109,9 +317,11 @@ isa = PBXNativeTarget; buildConfigurationList = E084FAF5233A8735009AC50D /* Build configuration list for PBXNativeTarget "fakestagram" */; buildPhases = ( + 4AE804DBB1C330BBDB1A4587 /* [CP] Check Pods Manifest.lock */, E084FAD2233A8734009AC50D /* Sources */, E084FAD3233A8734009AC50D /* Frameworks */, E084FAD4233A8734009AC50D /* Resources */, + BA44E9C49B033049A720850E /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -126,9 +336,11 @@ isa = PBXNativeTarget; buildConfigurationList = E084FAF8233A8735009AC50D /* Build configuration list for PBXNativeTarget "fakestagramTests" */; buildPhases = ( + 9C7D5FC48E01207A73A3C357 /* [CP] Check Pods Manifest.lock */, E084FAE8233A8735009AC50D /* Sources */, E084FAE9233A8735009AC50D /* Frameworks */, E084FAEA233A8735009AC50D /* Resources */, + 7AA77609E4963F9B91BB29FB /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -152,6 +364,7 @@ TargetAttributes = { E084FAD5233A8734009AC50D = { CreatedOnToolsVersion = 11.0; + LastSwiftMigration = 1120; }; E084FAEB233A8735009AC50D = { CreatedOnToolsVersion = 11.0; @@ -183,9 +396,12 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + E0C93EA223523B7C00FD330C /* ShowPostViewController.xib in Resources */, + 77840D5F239F0C4000EDC651 /* PreviewImageViewController.xib in Resources */, E084FAE6233A8735009AC50D /* LaunchScreen.storyboard in Resources */, E084FAE3233A8735009AC50D /* Assets.xcassets in Resources */, E084FAE1233A8734009AC50D /* Main.storyboard in Resources */, + E0A9ED55235A7FF300A0527E /* PostCollectionViewCell.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -193,19 +409,131 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + E0C93E9923514D8800FD330C /* posts.successful.json in Resources */, + E0C93E9B23515A0400FD330C /* show_post.successful.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 4AE804DBB1C330BBDB1A4587 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-fakestagram-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 7AA77609E4963F9B91BB29FB /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fakestagramTests/Pods-fakestagramTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fakestagramTests/Pods-fakestagramTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-fakestagramTests/Pods-fakestagramTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9C7D5FC48E01207A73A3C357 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-fakestagramTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + BA44E9C49B033049A720850E /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fakestagram/Pods-fakestagram-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fakestagram/Pods-fakestagram-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-fakestagram/Pods-fakestagram-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ E084FAD2233A8734009AC50D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 77840D5E239F0C4000EDC651 /* PreviewImageViewController.swift in Sources */, + E0C93EA42352452900FD330C /* AuthorView.swift in Sources */, + E0E2545F235A9F3A00C55767 /* UIDevice+models.swift in Sources */, + E0E8B96A23481D5A00DA9D1A /* StatusCode.swift in Sources */, + E045845123766203006574FA /* CacheImage.swift in Sources */, + E045844B237652DD006574FA /* StorageType.swift in Sources */, + E023A5542380859200B13B7D /* NotificationKeys.swift in Sources */, + E0C185F0237F92C700AD9983 /* PreviewView.swift in Sources */, + E0E8B974234918FF00DA9D1A /* Account.swift in Sources */, + E0C93EA123523B7C00FD330C /* ShowPostViewController.swift in Sources */, + E0E25463235B675100C55767 /* CameraViewController.swift in Sources */, + E0458457237725B9006574FA /* IndexService.swift in Sources */, E038FCED233FC78600E28571 /* PostViewController.swift in Sources */, + E0C93EA82352455C00FD330C /* Comment.swift in Sources */, + E0C93EAA2352457200FD330C /* Like.swift in Sources */, + E0C93E9D23515CEE00FD330C /* CodableSerializer.swift in Sources */, + E0458454237721F5006574FA /* CheckSum.m in Sources */, + E0E25465235B6C0500C55767 /* UIImage+Base64.swift in Sources */, + E0E8B9762349197100DA9D1A /* Post.swift in Sources */, E084FADA233A8734009AC50D /* AppDelegate.swift in Sources */, - E084FAFC233A8888009AC50D /* PostsTableViewController.swift in Sources */, + E0E8B96E2348203B00DA9D1A /* RequestBuilder.swift in Sources */, + E0E8B9682348036D00DA9D1A /* Client.swift in Sources */, + E0A9ED51235A782F00A0527E /* PostsViewController.swift in Sources */, + E045844923762E10006574FA /* CreatePostService.swift in Sources */, + E0C93EA62352454E00FD330C /* Author.swift in Sources */, + E0A9ED54235A7FF300A0527E /* PostCollectionViewCell.swift in Sources */, + E0E8B96C23481E1700DA9D1A /* HttpResponse.swift in Sources */, + E045844F23765B0F006574FA /* ImageStore.swift in Sources */, + E045844D23765677006574FA /* DataContainer.swift in Sources */, + 773F6A542389BFF700AF7090 /* CreateLikeService.swift in Sources */, + E0E8B9652348018200DA9D1A /* Credentials.swift in Sources */, + E0E8B971234916D100DA9D1A /* RestClient.swift in Sources */, E084FADC233A8734009AC50D /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -214,7 +542,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E084FAF1233A8735009AC50D /* fakestagramTests.swift in Sources */, + E0C93E942351435100FD330C /* RestClientTest.swift in Sources */, + E084FAF1233A8735009AC50D /* RequestBuilderTests.swift in Sources */, + E0458459237727D8006574FA /* CheckSumTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -304,6 +634,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; @@ -357,6 +688,7 @@ MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; @@ -364,17 +696,21 @@ }; E084FAF6233A8735009AC50D /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = DB68F7FEC717545506064663 /* Pods-fakestagram.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = D3XL2U7DQC; + DEVELOPMENT_TEAM = F2BL68NTA5; INFOPLIST_FILE = fakestagram/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.3zcurdia.fakestagram; + PRODUCT_BUNDLE_IDENTIFIER = com.ricardo.fakestagram; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "fakestagram/fakestagram-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -382,17 +718,20 @@ }; E084FAF7233A8735009AC50D /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = CCC6C6EA9D17CA169951A745 /* Pods-fakestagram.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = D3XL2U7DQC; + DEVELOPMENT_TEAM = F2BL68NTA5; INFOPLIST_FILE = fakestagram/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.3zcurdia.fakestagram; + PRODUCT_BUNDLE_IDENTIFIER = com.ricardo.fakestagram; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "fakestagram/fakestagram-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -400,6 +739,7 @@ }; E084FAF9233A8735009AC50D /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 66342726A6BCEEEF6289B1AA /* Pods-fakestagramTests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -422,6 +762,7 @@ }; E084FAFA233A8735009AC50D /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 5E0AE2BFBF9C8D81E583E1BE /* Pods-fakestagramTests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; diff --git a/fakestagram.xcodeproj/xcshareddata/xcbaselines/E084FAEB233A8735009AC50D.xcbaseline/4B2163FF-53B3-4A2D-B0E0-0AF6257FC48D.plist b/fakestagram.xcodeproj/xcshareddata/xcbaselines/E084FAEB233A8735009AC50D.xcbaseline/4B2163FF-53B3-4A2D-B0E0-0AF6257FC48D.plist new file mode 100644 index 0000000..0648835 --- /dev/null +++ b/fakestagram.xcodeproj/xcshareddata/xcbaselines/E084FAEB233A8735009AC50D.xcbaseline/4B2163FF-53B3-4A2D-B0E0-0AF6257FC48D.plist @@ -0,0 +1,22 @@ + + + + + classNames + + CheckSumTest + + testPerformanceExample() + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 6.55e-05 + baselineIntegrationDisplayName + Local Baseline + + + + + + diff --git a/fakestagram.xcodeproj/xcshareddata/xcbaselines/E084FAEB233A8735009AC50D.xcbaseline/Info.plist b/fakestagram.xcodeproj/xcshareddata/xcbaselines/E084FAEB233A8735009AC50D.xcbaseline/Info.plist new file mode 100644 index 0000000..fc16441 --- /dev/null +++ b/fakestagram.xcodeproj/xcshareddata/xcbaselines/E084FAEB233A8735009AC50D.xcbaseline/Info.plist @@ -0,0 +1,40 @@ + + + + + runDestinationsByUUID + + 4B2163FF-53B3-4A2D-B0E0-0AF6257FC48D + + localComputer + + busSpeedInMHz + 100 + cpuCount + 1 + cpuKind + Intel Core i7 + cpuSpeedInMHz + 2900 + logicalCPUCoresPerPackage + 8 + modelCode + MacBookPro14,3 + physicalCPUCoresPerPackage + 4 + platformIdentifier + com.apple.platform.macosx + + targetArchitecture + x86_64 + targetDevice + + modelCode + iPhone12,1 + platformIdentifier + com.apple.platform.iphonesimulator + + + + + diff --git a/fakestagram.xcodeproj/xcuserdata/luise.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/fakestagram.xcodeproj/xcuserdata/luise.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..d88cf55 --- /dev/null +++ b/fakestagram.xcodeproj/xcuserdata/luise.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/fakestagram.xcodeproj/xcuserdata/luise.xcuserdatad/xcschemes/xcschememanagement.plist b/fakestagram.xcodeproj/xcuserdata/luise.xcuserdatad/xcschemes/xcschememanagement.plist index 53f76f5..5378346 100644 --- a/fakestagram.xcodeproj/xcuserdata/luise.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/fakestagram.xcodeproj/xcuserdata/luise.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ fakestagram.xcscheme_^#shared#^_ orderHint - 0 + 4 diff --git a/fakestagram.xcodeproj/xcuserdata/richard_ohg.xcuserdatad/xcschemes/xcschememanagement.plist b/fakestagram.xcodeproj/xcuserdata/richard_ohg.xcuserdatad/xcschemes/xcschememanagement.plist index 53f76f5..5378346 100644 --- a/fakestagram.xcodeproj/xcuserdata/richard_ohg.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/fakestagram.xcodeproj/xcuserdata/richard_ohg.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ fakestagram.xcscheme_^#shared#^_ orderHint - 0 + 4 diff --git a/fakestagram.xcworkspace/contents.xcworkspacedata b/fakestagram.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..666ee12 --- /dev/null +++ b/fakestagram.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/fakestagram.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/fakestagram.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/fakestagram.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/fakestagram/AppDelegate.swift b/fakestagram/AppDelegate.swift index a1d6769..02c0626 100644 --- a/fakestagram/AppDelegate.swift +++ b/fakestagram/AppDelegate.swift @@ -13,6 +13,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. + StorageType.permanent.ensureExists() + StorageType.cache.ensureExists() + loadOrCreateAccount() return true } @@ -30,4 +33,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } + func loadOrCreateAccount() { + if Credentials.apiToken.get() != nil { return } + let account = Account(id: nil, name: "Richard", deviceNumber: UIDevice.identifier, deviceModel: UIDevice.modelName) + let client = RestClient(client: Client.fakestagram, basePath: "/api/v1/accounts") + client.create(account) { account in + guard let account = account, let idx = account.id else { return } + _ = Credentials.apiToken.set(value: idx) + } + } } diff --git a/fakestagram/Assets.xcassets/comments.imageset/Contents.json b/fakestagram/Assets.xcassets/comments.imageset/Contents.json new file mode 100644 index 0000000..78acdd5 --- /dev/null +++ b/fakestagram/Assets.xcassets/comments.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "comments.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/fakestagram/Assets.xcassets/comments.imageset/comments.png b/fakestagram/Assets.xcassets/comments.imageset/comments.png new file mode 100644 index 0000000..a6561ed Binary files /dev/null and b/fakestagram/Assets.xcassets/comments.imageset/comments.png differ diff --git a/fakestagram/Assets.xcassets/heart_border.imageset/Contents.json b/fakestagram/Assets.xcassets/heart_border.imageset/Contents.json new file mode 100644 index 0000000..17df2fa --- /dev/null +++ b/fakestagram/Assets.xcassets/heart_border.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "heart_border.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/fakestagram/Assets.xcassets/heart_border.imageset/heart_border.png b/fakestagram/Assets.xcassets/heart_border.imageset/heart_border.png new file mode 100644 index 0000000..d71a130 Binary files /dev/null and b/fakestagram/Assets.xcassets/heart_border.imageset/heart_border.png differ diff --git a/fakestagram/Assets.xcassets/heart_full.imageset/Contents.json b/fakestagram/Assets.xcassets/heart_full.imageset/Contents.json new file mode 100644 index 0000000..029ccea --- /dev/null +++ b/fakestagram/Assets.xcassets/heart_full.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "heart_full.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/fakestagram/Assets.xcassets/heart_full.imageset/heart_full.png b/fakestagram/Assets.xcassets/heart_full.imageset/heart_full.png new file mode 100644 index 0000000..b733bc3 Binary files /dev/null and b/fakestagram/Assets.xcassets/heart_full.imageset/heart_full.png differ diff --git a/fakestagram/Assets.xcassets/loading.imageset/Contents.json b/fakestagram/Assets.xcassets/loading.imageset/Contents.json new file mode 100644 index 0000000..e3a1385 --- /dev/null +++ b/fakestagram/Assets.xcassets/loading.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "loading.jpeg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/fakestagram/Assets.xcassets/loading.imageset/loading.jpeg b/fakestagram/Assets.xcassets/loading.imageset/loading.jpeg new file mode 100644 index 0000000..e8e6b2b Binary files /dev/null and b/fakestagram/Assets.xcassets/loading.imageset/loading.jpeg differ diff --git a/fakestagram/Assets.xcassets/spacecat.imageset/Contents.json b/fakestagram/Assets.xcassets/spacecat.imageset/Contents.json new file mode 100644 index 0000000..d1bb6ed --- /dev/null +++ b/fakestagram/Assets.xcassets/spacecat.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "spacecat.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/fakestagram/Assets.xcassets/spacecat.imageset/spacecat.jpg b/fakestagram/Assets.xcassets/spacecat.imageset/spacecat.jpg new file mode 100644 index 0000000..32ea7fd Binary files /dev/null and b/fakestagram/Assets.xcassets/spacecat.imageset/spacecat.jpg differ diff --git a/fakestagram/Base.lproj/Main.storyboard b/fakestagram/Base.lproj/Main.storyboard index 27e1b7e..8a483ad 100644 --- a/fakestagram/Base.lproj/Main.storyboard +++ b/fakestagram/Base.lproj/Main.storyboard @@ -1,98 +1,147 @@ - - + + - + + - - + + - - - + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - - + + - - - + + + - - + + + - + - + + - - - + + + + + + + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + diff --git a/fakestagram/CheckSum.h b/fakestagram/CheckSum.h new file mode 100644 index 0000000..168df88 --- /dev/null +++ b/fakestagram/CheckSum.h @@ -0,0 +1,18 @@ +// +// CheckSum.h +// fakestagram +// +// Created by LuisE on 11/9/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +#ifndef CheckSum_h +#define CheckSum_h +#import +#import + +@interface CheckSum : NSObject ++(NSString *) sha256String: (NSString *)input; +@end + +#endif /* Checksum_h */ diff --git a/fakestagram/CheckSum.m b/fakestagram/CheckSum.m new file mode 100644 index 0000000..181a11f --- /dev/null +++ b/fakestagram/CheckSum.m @@ -0,0 +1,31 @@ +// +// CheckSum.m +// fakestagram +// +// Created by LuisE on 11/9/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// +#import "CheckSum.h" + +@implementation CheckSum +- (instancetype)init { + if (self = [super init]) { + } + return self; +} + ++(NSString *) sha256String: (NSString *)input{ + const char* str = [input UTF8String]; + unsigned char result[CC_SHA256_DIGEST_LENGTH]; + CC_SHA256(str, strlen(str), result); + + NSMutableString *ret = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH*2]; + for(int i = 0; i() + + func read(key: String) -> UIImage? { + return memCache.object(forKey: key as NSString) + } + + func write(key: String, value: UIImage?) { + guard let value = value else { return } + memCache.setObject(value, forKey: key as NSString) + } +} diff --git a/fakestagram/DataSource/CodableSerializer.swift b/fakestagram/DataSource/CodableSerializer.swift new file mode 100644 index 0000000..a6aedf1 --- /dev/null +++ b/fakestagram/DataSource/CodableSerializer.swift @@ -0,0 +1,35 @@ +// +// CodableSerializer.swift +// fakestagram +// +// Created by LuisE on 10/11/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +class CodableSerializer { + let data: Data? + let decoder: JSONDecoder = { + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + return decoder + }() + + init(data: Data?) { + self.data = data + } + + func async(result: @escaping (T?) -> Void) { + guard let data = data else { + DispatchQueue.main.async { result(nil) } + return + } + do { + let json = try decoder.decode(T.self, from: data) + DispatchQueue.main.async { result(json) } + } catch let err { + print("Invalid JSON format: \(err.localizedDescription)") + } + } +} diff --git a/fakestagram/DataSource/DataContainer.swift b/fakestagram/DataSource/DataContainer.swift new file mode 100644 index 0000000..e3a6953 --- /dev/null +++ b/fakestagram/DataSource/DataContainer.swift @@ -0,0 +1,50 @@ +// +// DataContainer.swift +// fakestagram +// +// Created by LuisE on 11/8/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +// Usage +// DataContainer.cache.write("file.json",data: parsedData) +// DataContainer.cache.read("file.png") +// DataContainer.permanent.write("file.json",data: parsedData) +// DataContainer.permanent.read("file.png") + +enum DataContainer { + case cache + case permanent + + var baseUrl: URL { + switch self { + case .cache: + return StorageType.cache.url + case .permanent: + return StorageType.permanent.url + } + } + + func read(_ filename: String) -> Data? { + return try? Data(contentsOf: urlFor(filename: filename)) + } + + func write(_ filename: String, data: Data) -> Bool { + do { + try data.write(to: urlFor(filename: filename)) + return true + } catch let err { + debugPrint("Error: \(err.localizedDescription)") + return false + } + } + + func urlFor(filename: String) -> URL { + var url = baseUrl + url.appendPathComponent(filename) + return url + } + +} diff --git a/fakestagram/DataSource/ImageStore.swift b/fakestagram/DataSource/ImageStore.swift new file mode 100644 index 0000000..b9994f5 --- /dev/null +++ b/fakestagram/DataSource/ImageStore.swift @@ -0,0 +1,52 @@ +// +// ImageStore.swift +// fakestagram +// +// Created by LuisE on 11/8/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation +import UIKit + +// Usage +// ImagaStore.permanent.write("filename.jpg", image: img) +// ImagaStore.cache.read("filename.jpg") + +enum ImageStore { + case cache + case permanent + + var container: DataContainer { + switch self { + case .cache: + return DataContainer.cache + case .permanent: + return DataContainer.permanent + } + } + + func read(_ filename: String) -> UIImage? { + if let img = CacheImage.shared.read(key: filename) { + print(" - Reading from memory") + return img + } + print(" - Reading from disk") + guard let data = container.read(filename) else { return nil } + let image = UIImage(data: data) + + print(" * Writting into memory") + CacheImage.shared.write(key: filename, value: image) + return image + } + + func write(_ filename: String, image: UIImage) -> Bool { + guard let data = image.jpegData(compressionQuality: 0.9) else { return false } + + print(" - Writting into memory") + CacheImage.shared.write(key: filename, value: image) + + print(" - Writting into disk") + return container.write(filename, data: data) + } +} diff --git a/fakestagram/DataSource/RestClient.swift b/fakestagram/DataSource/RestClient.swift new file mode 100644 index 0000000..0ed7b41 --- /dev/null +++ b/fakestagram/DataSource/RestClient.swift @@ -0,0 +1,62 @@ +// +// RestClient.swift +// fakestagram +// +// Created by LuisE on 10/5/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +class RestClient { + private let client: Client + let basePath: String + let encoder: JSONEncoder = { + let encoder = JSONEncoder() + encoder.keyEncodingStrategy = .convertToSnakeCase + return encoder + }() + + init(client: Client, basePath: String) { + self.client = client + self.basePath = basePath + } + + // eg. POST /posts/ + func create(id: Int? = nil, _ data: T, success: @escaping (T?) -> Void) { + var path = basePath + if let uid = id { + path += "/\(uid)/like" + } + let payload = try? encoder.encode(data) + client.post(path: path, body: payload) { data in + CodableSerializer(data: data).async(result: success) + } + } + + // eg. GET /posts/ + // eg. GET /posts/:id + func show(id: String? = nil, success: @escaping (T?) -> Void) { + var path = basePath + if let uid = id { + path += "/\(uid)" + } + client.get(path: path) { data in + CodableSerializer(data: data).async(result: success) + } + } + // eg. PUT /posts/:id + func update(id: String, data: T, success: @escaping (T?) -> Void) { + let payload = try? encoder.encode(data) + client.put(path: "\(basePath)/\(id)", body: payload) { data in + CodableSerializer(data: data).async(result: success) + } + } + + // eg. DELETE /posts/:id + func delete(id: String, success: @escaping (T?) -> Void) { + client.delete(path: "\(basePath)/\(id)") { data in + CodableSerializer(data: data).async(result: success) + } + } +} diff --git a/fakestagram/DataSource/StorageType.swift b/fakestagram/DataSource/StorageType.swift new file mode 100644 index 0000000..e337d51 --- /dev/null +++ b/fakestagram/DataSource/StorageType.swift @@ -0,0 +1,47 @@ +// +// StorageType.swift +// fakestagram +// +// Created by LuisE on 11/8/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +enum StorageType { + case cache + case permanent + + var searchPathDirectory: FileManager.SearchPathDirectory { + switch self { + case .cache: + return .cachesDirectory + case .permanent: + return .documentDirectory + } + } + + var url: URL { + var url = FileManager.default.urls(for: searchPathDirectory, in: .userDomainMask).first! + let applicationPath = "mx.unam.ioslab.fakestagram.storage" + url.appendPathComponent(applicationPath) + return url + } + + var path: String { + return url.path + } + + func clear() { + try? FileManager.default.removeItem(at: url) + } + + func ensureExists() { + var isDir: ObjCBool = false + if FileManager.default.fileExists(atPath: path, isDirectory: &isDir) { + if isDir.boolValue { return } + clear() + } + try? FileManager.default.createDirectory(at: url, withIntermediateDirectories: false, attributes: nil) + } +} diff --git a/fakestagram/Info.plist b/fakestagram/Info.plist index 2a3483c..d1b73e7 100644 --- a/fakestagram/Info.plist +++ b/fakestagram/Info.plist @@ -20,6 +20,10 @@ 1 LSRequiresIPhoneOS + NSCameraUsageDescription + To capture your favorite moments and share with the world + NSLocationWhenInUseUsageDescription + Geololcalize your moments UIApplicationSceneManifest UIApplicationSupportsMultipleScenes @@ -50,8 +54,6 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad diff --git a/fakestagram/Models/Account.swift b/fakestagram/Models/Account.swift new file mode 100644 index 0000000..9f4c69c --- /dev/null +++ b/fakestagram/Models/Account.swift @@ -0,0 +1,16 @@ +// +// Account.swift +// fakestagram +// +// Created by LuisE on 10/5/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +struct Account: Codable { + let id: String? + let name: String + let deviceNumber: String? + let deviceModel: String? +} diff --git a/fakestagram/Models/Author.swift b/fakestagram/Models/Author.swift new file mode 100644 index 0000000..607dad2 --- /dev/null +++ b/fakestagram/Models/Author.swift @@ -0,0 +1,13 @@ +// +// Author.swift +// fakestagram +// +// Created by LuisE on 10/12/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +struct Author: Codable { + let name: String +} diff --git a/fakestagram/Models/Comment.swift b/fakestagram/Models/Comment.swift new file mode 100644 index 0000000..12db31e --- /dev/null +++ b/fakestagram/Models/Comment.swift @@ -0,0 +1,14 @@ +// +// Comment.swift +// fakestagram +// +// Created by LuisE on 10/12/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +struct Comment: Codable { + let content: String + let author: Author? +} diff --git a/fakestagram/Models/Like.swift b/fakestagram/Models/Like.swift new file mode 100644 index 0000000..5b2ba6f --- /dev/null +++ b/fakestagram/Models/Like.swift @@ -0,0 +1,13 @@ +// +// Like.swift +// fakestagram +// +// Created by LuisE on 10/12/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +struct Like: Codable { + let author: Author +} diff --git a/fakestagram/Models/Post.swift b/fakestagram/Models/Post.swift new file mode 100644 index 0000000..0b4995e --- /dev/null +++ b/fakestagram/Models/Post.swift @@ -0,0 +1,47 @@ +// +// Post.swift +// fakestagram +// +// Created by LuisE on 10/5/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation +import UIKit + +struct Post: Codable { + let id: Int? + let title: String + let imageUrl: String? + var likesCount: Int + var commentsCount: Int + let createdAt: String + var liked: Bool + let location: String + let author: Author? + + func likesCountText() -> String { + return "\(likesCount) likes" + } + + func commentsCountText() -> String { + return "\(commentsCount) comments" + } + + func load(_ image: @escaping (UIImage) -> Void) { + guard let urlString = imageUrl, let url = URL(string: urlString) else { return } + let filename = CheckSum.sha256String(urlString)! + if let img = ImageStore.cache.read(filename) { + print("Reading cache") + image(img) + return + } + DispatchQueue.global(qos: .background).async { + if let data = try? Data(contentsOf: url), let img = UIImage(data: data) { + print("Loading from the internet") + _ = ImageStore.cache.write(filename, image: img) + DispatchQueue.main.async { image(img) } + } + } + } +} diff --git a/fakestagram/Network/Client.swift b/fakestagram/Network/Client.swift new file mode 100644 index 0000000..187f7ca --- /dev/null +++ b/fakestagram/Network/Client.swift @@ -0,0 +1,76 @@ +// +// Client.swift +// fakestagram +// +// Created by LuisE on 10/4/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +class Client { + static let fakestagram = Client(session: URLSession.shared, baseUrl: "https://fakestagram-api.herokuapp.com") + let session: URLSession + let baseUrl: String + + init(session: URLSession, baseUrl: String) { + self.session = session + self.baseUrl = baseUrl + } + + typealias successfulResponse = (Data?) -> Void + + func get(path: String, success: @escaping successfulResponse) { + request(method: "get", path: path, body: nil, success: success) + } + + func post(path: String, body: Data?, success: @escaping successfulResponse) { + request(method: "post", path: path, body: body, success: success) + } + + func put(path: String, body: Data?, success: @escaping successfulResponse) { + request(method: "put", path: path, body: body, success: success) + } + + func delete(path: String, success: @escaping successfulResponse) { + request(method: "delete", path: path, body: nil, success: success) + } + + private func request(method: String, path: String, body: Data?, success: @escaping successfulResponse) { + guard let req = buildRequest(method: method, path: path, body: body) else { + debugPrint("Invalid request") + return + } + + session.dataTask(with: req) { (data, response, error) in + if let error = error { + debugPrint(error) + return + } + + let response = HttpResponse(response: response) + if response.isSuccessful() { + success(data) + } else { + #if DEBUG + debugPrint(response.status) + if let data = data { + let error = String(data: data, encoding: .utf8) + debugPrint(error) + } + #endif + } + }.resume() + } + + private func buildRequest(method: String, path: String, body: Data?) -> URLRequest? { + var builder = RequestBuilder(baseUrl: self.baseUrl) + builder.method = method + builder.path = path + builder.body = body + if let token = Credentials.apiToken.get() { + builder.headers = ["Authorization": "Bearer \(token)"] + } + return builder.request() + } +} diff --git a/fakestagram/Network/HttpResponse.swift b/fakestagram/Network/HttpResponse.swift new file mode 100644 index 0000000..cd7b4aa --- /dev/null +++ b/fakestagram/Network/HttpResponse.swift @@ -0,0 +1,25 @@ +// +// HttpResponse.swift +// fakestagram +// +// Created by LuisE on 10/4/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +class HttpResponse { + let httpUrlResponse: HTTPURLResponse + + init(response: URLResponse?) { + self.httpUrlResponse = response as! HTTPURLResponse + } + + lazy var status: StatusCode = { + return StatusCode(rawValue: self.httpUrlResponse.statusCode) + }() + + func isSuccessful() -> Bool { + return status == StatusCode.success + } +} diff --git a/fakestagram/Network/RequestBuilder.swift b/fakestagram/Network/RequestBuilder.swift new file mode 100644 index 0000000..0fb17dd --- /dev/null +++ b/fakestagram/Network/RequestBuilder.swift @@ -0,0 +1,62 @@ +// +// RequestBuilder.swift +// fakestagram +// +// Created by LuisE on 10/4/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +struct RequestBuilder { + enum ContentMode { + case jsonApp + + func accept() -> String { + switch self { + case .jsonApp: + return "application/json" + } + } + + func contentType() -> String { + switch self { + case .jsonApp: + return "application/json" + } + } + } + private let urlComponents: URLComponents + public var scheme: String = "https" + public var method: String = "get" + public var path: String = "/" + public var body: Data? + public var headers: [String: String]? + public var contentMode: ContentMode = .jsonApp + + init(baseUrl: String) { + self.urlComponents = URLComponents(string: baseUrl)! + } + + func url() -> URL? { + var comps = self.urlComponents + comps.scheme = scheme + comps.path = path + return comps.url + } + + func request() -> URLRequest? { + guard let url = url() else { return nil } + var req = URLRequest(url: url) + req.httpMethod = method + req.httpBody = body + req.addValue(contentMode.accept(), forHTTPHeaderField: "Accept") + req.addValue(contentMode.contentType(), forHTTPHeaderField: "Content-Type") + if let headers = self.headers { + for (key, value) in headers { + req.addValue(value, forHTTPHeaderField: key) + } + } + return req + } +} diff --git a/fakestagram/Network/StatusCode.swift b/fakestagram/Network/StatusCode.swift new file mode 100644 index 0000000..cdc5e29 --- /dev/null +++ b/fakestagram/Network/StatusCode.swift @@ -0,0 +1,36 @@ +// +// StatusCode.swift +// fakestagram +// +// Created by LuisE on 10/4/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +enum StatusCode: Int { + case unkown = 0 + case info + case success + case redirection + case clientError + case serverError + + public init(rawValue: Int) { + switch rawValue { + case 100, 101, 102: + self = .info + case 200, 201, 202, 203, 204, 205, 206, 207, 208, 226: + self = .success + case 300, 301, 302, 303, 304, 305, 306, 307, 308: + self = .redirection + case 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 421, 422, 423, 424, 426, 428, 429, 431, 451: + self = .clientError + case 500, 501, 502, 503, 504, 505, 506, 507, 510, 511: + self = .serverError + default: + self = .unkown + } + } +} diff --git a/fakestagram/PostsTableViewController.swift b/fakestagram/PostsTableViewController.swift deleted file mode 100644 index 2bb0b63..0000000 --- a/fakestagram/PostsTableViewController.swift +++ /dev/null @@ -1,153 +0,0 @@ -// -// PostsTableViewController.swift -// fakestagram -// -// Created by LuisE on 9/24/19. -// Copyright © 2019 3zcurdia. All rights reserved. -// - -import UIKit - -struct Post: Codable { - let id: Int? - let title: String - let imageUrl: String? - var likesCount: Int - var commentsCount: Int - let createdAt: String - var liked: Bool - let location: String - - func likesCountText() -> String { - return "\(likesCount) likes" - } - - func commentsCountText() -> String { - return "\(commentsCount) comments" - } - - func load(_ image: @escaping (UIImage) -> Void) { - guard let urlString = imageUrl, let url = URL(string: urlString) else { return } - DispatchQueue.global(qos: .background).async { - if let data = try? Data(contentsOf: url), let img = UIImage(data: data) { - DispatchQueue.main.async { image(img) } - } - } - } -} - -class PostsTableViewController: UITableViewController { - static let cellId = "PostCell" - var posts = [Post]() - - override func viewDidLoad() { - super.viewDidLoad() - loadPosts { data in - DispatchQueue.main.async { - self.posts = data - self.tableView.reloadData() - } - } - - // Uncomment the following line to preserve selection between presentations - // self.clearsSelectionOnViewWillAppear = false - - // Uncomment the following line to display an Edit button in the navigation bar for this view controller. - // self.navigationItem.rightBarButtonItem = self.editButtonItem - } - - // MARK: - Table view data source - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return posts.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: PostsTableViewController.cellId, for: indexPath) - posts[indexPath.row].load { img in - cell.imageView?.contentMode = .scaleAspectFit - cell.imageView?.image = img - } - cell.textLabel?.text = posts[indexPath.row].title - cell.detailTextLabel?.text = posts[indexPath.row].location - - return cell - } - - /* - // Override to support conditional editing of the table view. - override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - // Return false if you do not want the specified item to be editable. - return true - } - */ - - /* - // Override to support editing the table view. - override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { - if editingStyle == .delete { - // Delete the row from the data source - tableView.deleteRows(at: [indexPath], with: .fade) - } else if editingStyle == .insert { - // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view - } - } - */ - - /* - // Override to support rearranging the table view. - override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) { - - } - */ - - /* - // Override to support conditional rearranging of the table view. - override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { - // Return false if you do not want the item to be re-orderable. - return true - } - */ - - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - if segue.identifier == "showPostSegue" { - let dest = segue.destination as! PostViewController - let idx = self.tableView.indexPathForSelectedRow?.row ?? 0 - dest.post = posts[idx] - } - } - - func loadPosts(successful: @escaping ([Post]) -> Void) { - let url = URL(string: "https://fakestagram-api.herokuapp.com/api/v1/posts")! - var request = URLRequest(url: url) - request.setValue("application/json", forHTTPHeaderField: "Accept") - request.setValue("application/json", forHTTPHeaderField: "Content-Type") - request.httpMethod = "get" - request.addValue("Bearer f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e", forHTTPHeaderField: "Authorization") - - let task = URLSession.shared.dataTask(with: request) { (data, _, error) in - if error != nil || data == nil { - return - } - let decoder = JSONDecoder() - decoder.keyDecodingStrategy = .convertFromSnakeCase - do { - guard let data = data else { print("Empty response"); return } - let json = try decoder.decode([Post].self, from: data) - successful(json) - } catch let err { - print("Unable to parse successfull response: \(err.localizedDescription)") - } - } - task.resume() - } -} diff --git a/fakestagram/Services/CreateLikeService.swift b/fakestagram/Services/CreateLikeService.swift new file mode 100644 index 0000000..a8bed9d --- /dev/null +++ b/fakestagram/Services/CreateLikeService.swift @@ -0,0 +1,25 @@ +// +// CreateLikeService.swift +// fakestagram +// +// Created by Ricardo Hernández González on 23/11/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +struct CreateLike: Codable{ + var postId: Int? +} + +class CreateLikeService { + private let client = RestClient(client: Client.fakestagram, basePath: "/api/v1/posts") + + func call(postId: Int?, success: @escaping (Int?) -> Void) { + let newLike = CreateLike(postId: postId) + client.create(id: newLike.postId, newLike) { like in + NotificationCenter.default.post(name: NotificationKeys.didFinishPostCreation.value, object: nil) + success(like?.postId) + } + } +} diff --git a/fakestagram/Services/CreatePostService.swift b/fakestagram/Services/CreatePostService.swift new file mode 100644 index 0000000..6a50b85 --- /dev/null +++ b/fakestagram/Services/CreatePostService.swift @@ -0,0 +1,46 @@ +// +// CreatePostService.swift +// fakestagram +// +// Created by LuisE on 11/8/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation +import UIKit +import CoreLocation + +struct CreatePost: Codable { + let id: Int? + let title: String + let imageData: String? + let latitude: Double? + let longitude: Double? +} + +//protocol Geolocable { +// func update(coordinate: CLLocationCoordinate2D?) +//} + +class CreatePostService { + private let client = RestClient(client: Client.fakestagram, basePath: "/api/v1/posts/") + private var currentLocation: CLLocationCoordinate2D? + + func call(image: UIImage, title: String, success: @escaping (Int?) -> Void) { + let newPost = CreatePost( + id: nil, + title: title, + imageData: image.base64(), + latitude: currentLocation?.latitude, + longitude: currentLocation?.longitude + ) + client.create(newPost) { post in + NotificationCenter.default.post(name: NotificationKeys.didFinishPostCreation.value, object: nil) + success(post?.id) + } + } + + func update(coordinate: CLLocationCoordinate2D?) { + currentLocation = coordinate + } +} diff --git a/fakestagram/Services/IndexService.swift b/fakestagram/Services/IndexService.swift new file mode 100644 index 0000000..5c6cb55 --- /dev/null +++ b/fakestagram/Services/IndexService.swift @@ -0,0 +1,17 @@ +// +// IndexService.swift +// fakestagram +// +// Created by LuisE on 11/9/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +class IndexService { + let client = RestClient<[Post]>(client: Client.fakestagram, basePath: "/api/v1/posts") + + func call(success: @escaping ([Post]?) -> Void) { + client.show(success: success) + } +} diff --git a/fakestagram/Utils/Credentials.swift b/fakestagram/Utils/Credentials.swift new file mode 100644 index 0000000..3ce1105 --- /dev/null +++ b/fakestagram/Utils/Credentials.swift @@ -0,0 +1,37 @@ +// +// Credentials.swift +// fakestagram +// +// Created by LuisE on 10/4/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation +import SAMKeychain + +enum Credentials { + case apiToken + + func get() -> String? { + switch self { + case .apiToken: + return SAMKeychain.password(forService: "mx.unam.fakestagram", account: "apiToken") + } + } + + func set(value: String) -> Bool { + switch self { + case .apiToken: + SAMKeychain.setPassword(value, forService: "mx.unam.fakestagram", account: "apiToken") + } + return true + } + + func destroy() -> Bool { + switch self { + case .apiToken: + SAMKeychain.deletePassword(forService: "mx.unam.fakestagram", account: "apiToken") + } + return true + } +} diff --git a/fakestagram/Utils/NotificationKeys.swift b/fakestagram/Utils/NotificationKeys.swift new file mode 100644 index 0000000..d0bf641 --- /dev/null +++ b/fakestagram/Utils/NotificationKeys.swift @@ -0,0 +1,20 @@ +// +// NotificationNames.swift +// fakestagram +// +// Created by LuisE on 11/16/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import Foundation + +enum NotificationKeys { + case didFinishPostCreation + + var value: Notification.Name { + switch self { + case .didFinishPostCreation: + return Notification.Name(rawValue: "didFinishPostCreationNotification") + } + } +} diff --git a/fakestagram/Utils/UIDevice+models.swift b/fakestagram/Utils/UIDevice+models.swift new file mode 100644 index 0000000..4102a1e --- /dev/null +++ b/fakestagram/Utils/UIDevice+models.swift @@ -0,0 +1,95 @@ +// +// UIDevice+models.swift +// fakestagram +// +// Created by LuisE on 10/18/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit + +public extension UIDevice { + static let identifier: String = { + if let vendorId = UIDevice.current.identifierForVendor { + return "\(vendorId.hashValue):\(vendorId.uuidString)" + } else { + return ":\(UUID().uuidString)" + } + }() + + static let modelName: String = { + var systemInfo = utsname() + uname(&systemInfo) + let machineMirror = Mirror(reflecting: systemInfo.machine) + let identifier = machineMirror.children.reduce("") { identifier, element in + guard let value = element.value as? Int8, value != 0 else { return identifier } + return identifier + String(UnicodeScalar(UInt8(value))) + } + + func mapToDevice(identifier: String) -> String { // swiftlint:disable:this cyclomatic_complexity + #if os(iOS) + switch identifier { + case "iPod5,1": return "iPod touch (5th generation)" + case "iPod7,1": return "iPod touch (6th generation)" + case "iPod9,1": return "iPod touch (7th generation)" + case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4" + case "iPhone4,1": return "iPhone 4s" + case "iPhone5,1", "iPhone5,2": return "iPhone 5" + case "iPhone5,3", "iPhone5,4": return "iPhone 5c" + case "iPhone6,1", "iPhone6,2": return "iPhone 5s" + case "iPhone7,2": return "iPhone 6" + case "iPhone7,1": return "iPhone 6 Plus" + case "iPhone8,1": return "iPhone 6s" + case "iPhone8,2": return "iPhone 6s Plus" + case "iPhone9,1", "iPhone9,3": return "iPhone 7" + case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus" + case "iPhone8,4": return "iPhone SE" + case "iPhone10,1", "iPhone10,4": return "iPhone 8" + case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus" + case "iPhone10,3", "iPhone10,6": return "iPhone X" + case "iPhone11,2": return "iPhone XS" + case "iPhone11,4", "iPhone11,6": return "iPhone XS Max" + case "iPhone11,8": return "iPhone XR" + case "iPhone12,1": return "iPhone 11" + case "iPhone12,3": return "iPhone 11 Pro" + case "iPhone12,5": return "iPhone 11 Pro Max" + case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2" + case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad (3rd generation)" + case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad (4th generation)" + case "iPad6,11", "iPad6,12": return "iPad (5th generation)" + case "iPad7,5", "iPad7,6": return "iPad (6th generation)" + case "iPad7,11", "iPad7,12": return "iPad (7th generation)" + case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air" + case "iPad5,3", "iPad5,4": return "iPad Air 2" + case "iPad11,4", "iPad11,5": return "iPad Air (3rd generation)" + case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad mini" + case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad mini 2" + case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad mini 3" + case "iPad5,1", "iPad5,2": return "iPad mini 4" + case "iPad11,1", "iPad11,2": return "iPad mini (5th generation)" + case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)" + case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch)" + case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch) (2nd generation)" + case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)" + case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4":return "iPad Pro (11-inch)" + case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8":return "iPad Pro (12.9-inch) (3rd generation)" + case "AppleTV5,3": return "Apple TV" + case "AppleTV6,2": return "Apple TV 4K" + case "AudioAccessory1,1": return "HomePod" + case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))" + default: return identifier + } + #elseif os(tvOS) + switch identifier { + case "AppleTV5,3": return "Apple TV 4" + case "AppleTV6,2": return "Apple TV 4K" + case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))" + default: return identifier + } + #endif + } + + return mapToDevice(identifier: identifier) + }() + +} diff --git a/fakestagram/Utils/UIImage+Base64.swift b/fakestagram/Utils/UIImage+Base64.swift new file mode 100644 index 0000000..5bb19a0 --- /dev/null +++ b/fakestagram/Utils/UIImage+Base64.swift @@ -0,0 +1,23 @@ +// +// UIImage+Base64.swift +// fakestagram +// +// Created by LuisE on 10/19/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit + +extension Data { + func imageBase64(ext: String = "tiff") -> String { + let encoded = self.base64EncodedString(options: .lineLength64Characters) + return "data:image/\(ext);base64,\(encoded)" + } +} + +extension UIImage { + func base64() -> String { + let data = self.jpegData(compressionQuality: 0.85)! + return data.imageBase64(ext: "jpg") + } +} diff --git a/fakestagram/ViewControllers/CameraViewController.swift b/fakestagram/ViewControllers/CameraViewController.swift new file mode 100644 index 0000000..7be6f74 --- /dev/null +++ b/fakestagram/ViewControllers/CameraViewController.swift @@ -0,0 +1,136 @@ +// +// CameraViewController.swift +// fakestagram +// +// Created by LuisE on 10/19/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit +import CoreLocation +import AVFoundation + +class CameraViewController: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + enableBasicLocationServices() + enableCameraAccess() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + locationManager.startUpdatingLocation() + } + + override func viewWillDisappear(_ animated: Bool) { + locationManager.stopUpdatingLocation() + super.viewWillDisappear(animated) + } + + let service = CreatePostService() + @IBAction func onTapCreate(_ sender: Any) { + print("📸") + let settings: AVCapturePhotoSettings + print(self.photoOutput.availablePhotoCodecTypes) + if self.photoOutput.availablePhotoCodecTypes.contains(.hevc) { + settings = AVCapturePhotoSettings(format: + [AVVideoCodecKey: AVVideoCodecType.hevc]) + } else { + settings = AVCapturePhotoSettings() + } + settings.flashMode = .auto + photoOutput.capturePhoto(with: settings, delegate: self) + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + + // MARK: - CoreLocation methods + let locationManager = CLLocationManager() + func enableBasicLocationServices() { + locationManager.delegate = self + switch CLLocationManager.authorizationStatus() { + case .notDetermined: + locationManager.requestWhenInUseAuthorization() + case .restricted, .denied: + print("Disable location features") + case .authorizedWhenInUse, .authorizedAlways: + print("Enable location features") + @unknown default: + fatalError() + } + } + + // MARK: - AVFoundation methods + + @IBOutlet weak var previewView: PreviewView! + func enableCameraAccess() { + switch AVCaptureDevice.authorizationStatus(for: .video) { + case .authorized: + // The user has previously granted access to the camera. + self.setupCaptureSession() + case .notDetermined: + // The user has not yet been asked for camera access. + AVCaptureDevice.requestAccess(for: .video) { granted in + if granted { + self.setupCaptureSession() + } + } + case .denied: + // The user has previously denied access. + return + case .restricted: + // The user can't grant access due to restrictions. + return + @unknown default: + fatalError() + } + } + + let session = AVCaptureSession() + let photoOutput = AVCapturePhotoOutput() + + func setupCaptureSession() { + session.beginConfiguration() + let device = AVCaptureDevice.default(.builtInWideAngleCamera, + for: .video, position: .back)! + guard let videoDeviceInput = try? AVCaptureDeviceInput(device: device), + session.canAddInput(videoDeviceInput) else { return } + session.addInput(videoDeviceInput) + + guard session.canAddOutput(photoOutput) else { return } + session.sessionPreset = .photo + session.addOutput(photoOutput) + + session.commitConfiguration() + previewView.session = session + + session.startRunning() + } + +} + +extension CameraViewController: AVCapturePhotoCaptureDelegate { + func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { + debugPrint(photo.metadata) + + guard let data = photo.fileDataRepresentation(), let img = UIImage(data: data) else { return } + let previewVC = PreviewImageViewController() + previewVC.image = img + present(previewVC, animated: true) + } +} + +extension CameraViewController: CLLocationManagerDelegate { + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + guard let location = locations.last else { return } + service.update(coordinate: location.coordinate) + } +} diff --git a/fakestagram/PostViewController.swift b/fakestagram/ViewControllers/PostViewController.swift similarity index 95% rename from fakestagram/PostViewController.swift rename to fakestagram/ViewControllers/PostViewController.swift index dc0887e..f18ad1d 100644 --- a/fakestagram/PostViewController.swift +++ b/fakestagram/ViewControllers/PostViewController.swift @@ -8,17 +8,6 @@ import UIKit -struct Author: Codable { - let name: String -} -struct Comment: Codable { - let content: String - let author: Author? -} -struct Like: Codable { - let author: Author -} - class PostViewController: UIViewController { var post: Post? { didSet { diff --git a/fakestagram/ViewControllers/PostsViewController.swift b/fakestagram/ViewControllers/PostsViewController.swift new file mode 100644 index 0000000..a49ab76 --- /dev/null +++ b/fakestagram/ViewControllers/PostsViewController.swift @@ -0,0 +1,74 @@ +// +// PostsViewController.swift +// fakestagram +// +// Created by LuisE on 10/18/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit + +class PostsViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + var posts: [Post]? { + didSet { + self.postsCollection.reloadData() + } + } + + let service = IndexService() + let refreshControl = UIRefreshControl() + + @IBOutlet weak var postsCollection: UICollectionView! + override func viewDidLoad() { + super.viewDidLoad() + postsCollection.delegate = self + postsCollection.dataSource = self + let nib = UINib(nibName: String(describing: PostCollectionViewCell.self), bundle: nil) + postsCollection.register(nib, forCellWithReuseIdentifier: PostCollectionViewCell.identifier) + postsCollection.addSubview(refreshControl) + + refreshControl.addTarget(self, action: #selector(self.reloadData), for: UIControl.Event.valueChanged) + + service.call { [unowned self] data in + self.posts = data + } + NotificationCenter.default.addObserver(self, selector: #selector(reloadData), name: NotificationKeys.didFinishPostCreation.value, object: nil) + + // Do any additional setup after loading the view. + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + + @objc + func reloadData() { + service.call { [unowned self] data in + self.posts = data + self.refreshControl.endRefreshing() + } + } + + // MARK: - Collection View Delegates + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return self.posts?.count ?? 0 + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PostCollectionViewCell.identifier, for: indexPath) as! PostCollectionViewCell + guard let posts = self.posts else { return cell } + cell.post = posts[indexPath.row] + return cell + } + + // MARK: - Flow Layout Delegates + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: self.view.frame.width, height: 650) + } +} diff --git a/fakestagram/ViewControllers/PreviewCameraViewController.swift b/fakestagram/ViewControllers/PreviewCameraViewController.swift new file mode 100644 index 0000000..f22c829 --- /dev/null +++ b/fakestagram/ViewControllers/PreviewCameraViewController.swift @@ -0,0 +1,43 @@ +// +// PreviewCameraViewController.swift +// fakestagram +// +// Created by Ricardo Hernández González on 25/11/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit + +class PreviewCameraViewController: UIViewController { + + var cameraVC: CameraViewController! +// var dato: String! + var imagen: UIImage! + @IBOutlet weak var previewImage: UIImageView! + @IBOutlet weak var textForTitle: UITextField! + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. +// print("dato: \(dato)") + previewImage.image = imagen + + } + + @IBAction func cancel(_ sender: UIButton) { + } + + @IBAction func uploadImage(_ sender: UIButton) { + } + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/fakestagram/Views/AuthorView.swift b/fakestagram/Views/AuthorView.swift new file mode 100644 index 0000000..288967c --- /dev/null +++ b/fakestagram/Views/AuthorView.swift @@ -0,0 +1,66 @@ +// +// AuthorView.swift +// fakestagram +// +// Created by LuisE on 10/12/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit + +@IBDesignable +class AuthorView: UIView { + var author: Author? { + didSet { updateContent() } + } + + private let avatar: UIImageView = { + let iv = UIImageView() + iv.image = UIImage(systemName: "person.circle.fill") + iv.contentMode = .scaleAspectFill + iv.translatesAutoresizingMaskIntoConstraints = false + return iv + }() + private let nameLbl: UILabel = { + let lbl = UILabel() + lbl.text = "Lorem ipsum" + lbl.font = UIFont.systemFont(ofSize: 18, weight: .bold) + lbl.translatesAutoresizingMaskIntoConstraints = false + return lbl + }() + + convenience init() { + self.init(frame: .zero) + } + + override init(frame: CGRect) { + super.init(frame: frame) + setupConstraints() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupConstraints() + } + + private func setupConstraints() { + addSubview(avatar) + NSLayoutConstraint.activate([ + avatar.topAnchor.constraint(equalTo: self.topAnchor, constant: 5), + avatar.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5), + avatar.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -5), + avatar.widthAnchor.constraint(equalToConstant: 90) + ]) + addSubview(nameLbl) + NSLayoutConstraint.activate([ + nameLbl.leadingAnchor.constraint(equalTo: avatar.trailingAnchor, constant: 5), + nameLbl.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -5), + nameLbl.centerYAnchor.constraint(equalTo: self.centerYAnchor) + ]) + } + + func updateContent() { + guard let uauthor = author else { return } + nameLbl.text = uauthor.name + } +} diff --git a/fakestagram/Views/PostCollectionViewCell.swift b/fakestagram/Views/PostCollectionViewCell.swift new file mode 100644 index 0000000..a2a692a --- /dev/null +++ b/fakestagram/Views/PostCollectionViewCell.swift @@ -0,0 +1,55 @@ +// +// PostCollectionViewCell.swift +// fakestagram +// +// Created by LuisE on 10/18/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit + +class PostCollectionViewCell: UICollectionViewCell { + static let identifier: String = "PostCell" + public var post: Post? { + didSet { + updateView() + } + } + @IBOutlet weak var authorView: AuthorView! + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var likeCounter: UILabel! + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var likeBttn: UIButton! + @IBOutlet weak var commentBttn: UIButton! + + func reset() { + self.imageView.image = UIImage(named: "loading") + self.likeCounter.text = "" + self.titleLabel.text = "" + } + + func updateView() { + reset() + guard let post = self.post else { return } + self.authorView.author = post.author + self.titleLabel.text = post.title + self.likeCounter.text = post.likesCountText() + post.load { [unowned self] img in + self.imageView.image = img + } + } + + + @IBAction func likeAction(_ sender: UIButton) { + likeBttn.setImage(UIImage(named: "heart_full"), for: .normal) // problems with reusable cells + let service = CreateLikeService() + service.call(postId: post?.id) { (post) in + print("success") + } + + } + + @IBAction func commentAction(_ sender: UIButton) { + print("comment") + } +} diff --git a/fakestagram/Views/PostCollectionViewCell.xib b/fakestagram/Views/PostCollectionViewCell.xib new file mode 100644 index 0000000..8c19eb8 --- /dev/null +++ b/fakestagram/Views/PostCollectionViewCell.xib @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fakestagram/Views/PreviewImageViewController.swift b/fakestagram/Views/PreviewImageViewController.swift new file mode 100644 index 0000000..0165e7f --- /dev/null +++ b/fakestagram/Views/PreviewImageViewController.swift @@ -0,0 +1,45 @@ +// +// PreviewImageViewController.swift +// fakestagram +// +// Created by Ricardo Hernández González on 09/12/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit + +class PreviewImageViewController: UIViewController { + + @IBOutlet weak var previewImage: UIImageView! + @IBOutlet weak var textForTitle: UITextField! + var image: UIImage! + let service = CreatePostService() + + override func viewDidLoad() { + super.viewDidLoad() + + previewImage.image = image + } + + @IBAction func cancel(_ sender: UIButton) { + dismiss(animated: true, completion: nil) + } + + @IBAction func save(_ sender: UIButton) { + let text = textForTitle.text! + service.call(image: image, title: text) { postId in + print("Successful!") + print(postId ?? -1) + } + } + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/fakestagram/Views/PreviewImageViewController.xib b/fakestagram/Views/PreviewImageViewController.xib new file mode 100644 index 0000000..1fe6142 --- /dev/null +++ b/fakestagram/Views/PreviewImageViewController.xib @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fakestagram/Views/PreviewView.swift b/fakestagram/Views/PreviewView.swift new file mode 100644 index 0000000..8c38648 --- /dev/null +++ b/fakestagram/Views/PreviewView.swift @@ -0,0 +1,30 @@ +// +// PreviewView.swift +// HelloCamera +// +// Created by LuisE on 11/15/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit +import AVFoundation + +class PreviewView: UIView { + override class var layerClass: AnyClass { + return AVCaptureVideoPreviewLayer.self + } + + var session: AVCaptureSession? { + get { + return videoPreviewLayer.session + } + set { + videoPreviewLayer.session = newValue + } + } + + /// Convenience wrapper to get layer as its statically known type. + var videoPreviewLayer: AVCaptureVideoPreviewLayer { + return layer as! AVCaptureVideoPreviewLayer + } +} diff --git a/fakestagram/Views/ShowPostViewController.swift b/fakestagram/Views/ShowPostViewController.swift new file mode 100644 index 0000000..c0afe40 --- /dev/null +++ b/fakestagram/Views/ShowPostViewController.swift @@ -0,0 +1,48 @@ +// +// PostViewController.swift +// fakestagram +// +// Created by LuisE on 10/12/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import UIKit + +class ShowPostViewController: UIViewController { + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var likeCounter: UILabel! + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var likeBttn: UIButton! + @IBOutlet weak var commentBttn: UIButton! + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + @IBAction + func onTapLike(_ sender: Any) { + print("like") + } + + @IBAction + func onTapCreateComment(_ sender: Any) { + print("to comment") + } + + @IBAction + func onTapShowComments(_ sender: Any) { + print("to show comment") + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/fakestagram/Views/ShowPostViewController.xib b/fakestagram/Views/ShowPostViewController.xib new file mode 100644 index 0000000..9d91849 --- /dev/null +++ b/fakestagram/Views/ShowPostViewController.xib @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fakestagram/fakestagram-Bridging-Header.h b/fakestagram/fakestagram-Bridging-Header.h new file mode 100644 index 0000000..f31fb29 --- /dev/null +++ b/fakestagram/fakestagram-Bridging-Header.h @@ -0,0 +1,5 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "CheckSum.m" diff --git a/fakestagramTests/CheckSumTest.swift b/fakestagramTests/CheckSumTest.swift new file mode 100644 index 0000000..5236806 --- /dev/null +++ b/fakestagramTests/CheckSumTest.swift @@ -0,0 +1,26 @@ +// +// CheckSumTest.swift +// fakestagramTests +// +// Created by LuisE on 11/9/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import XCTest +//import CryptoKit +@testable import fakestagram + +class CheckSumTest: XCTestCase { + + func testPerformanceExample() { + let text = "lorem ipsum dolor quet sit amet consectetur" +// let data = text.data(using: .utf8)! + let expected = "df033ae7d7ff21916308e1e0f52c8f559f76bed69f5b4f8ed6237514bed8e2c4" + self.measure { + let result = CheckSum.sha256String(text) +// let result = String(SHA256.hash(data: data).description.dropFirst(15)) + XCTAssertEqual(expected, result) + } + } + +} diff --git a/fakestagramTests/RequestBuilderTests.swift b/fakestagramTests/RequestBuilderTests.swift new file mode 100644 index 0000000..01606ed --- /dev/null +++ b/fakestagramTests/RequestBuilderTests.swift @@ -0,0 +1,65 @@ +// +// RequestBuilderTests.swift +// RequestBuilderTests +// +// Created by LuisE on 9/24/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import XCTest +@testable import fakestagram + +class RequestBuilderTests: XCTestCase { + func testBuildValidURL() { + var builder = RequestBuilder(baseUrl: "https://example.com/") + builder.path = "/api/v1/accounts" + XCTAssertEqual(builder.scheme, "https") + XCTAssertEqual(builder.method, "get") + XCTAssertEqual(builder.url(), URL(string: "https://example.com/api/v1/accounts")!) + } + + func testBuildInvalidURL() { + var builder = RequestBuilder(baseUrl: "example.com") + builder.path = "//@3`-" + XCTAssertNil(builder.url()) + } + + func testBuildForceSchemeURL() { + let builder = RequestBuilder(baseUrl: "http://example.com/") + XCTAssertEqual(builder.url(), URL(string: "https://example.com/")!) + } + + func testBuildOverrideSchemeURL() { + var builder = RequestBuilder(baseUrl: "http://example.com/") + builder.scheme = "ftp" + XCTAssertEqual(builder.url(), URL(string: "ftp://example.com/")!) + } + + func testBuildInvalidRequest() { + var builder = RequestBuilder(baseUrl: "example.com") + builder.path = "//@3`-" + XCTAssertNil(builder.request()) + } + + func testBuildValidRequest() { + var builder = RequestBuilder(baseUrl: "https://example.com/") + builder.path = "/api/v1/accounts" + builder.method = "post" + builder.body = "{\"a\": 1}".data(using: .utf8) + builder.headers = ["test": "example"] + + let result = builder.request() + XCTAssertNotNil(result) + XCTAssertEqual(result!.httpMethod!, "POST") + XCTAssertEqual(result!.httpBody!, "{\"a\": 1}".data(using: .utf8)) + XCTAssertEqual(result!.allHTTPHeaderFields!, ["Accept": "application/json", "Content-Type": "application/json", "test": "example"]) + } + + func testBuildValidRequestWithDefaults() { + let result = RequestBuilder(baseUrl: "https://example.com/").request() + XCTAssertNotNil(result) + XCTAssertEqual(result!.httpMethod!, "GET") + XCTAssertNil(result!.httpBody) + XCTAssertEqual(result!.allHTTPHeaderFields!, ["Accept": "application/json", "Content-Type": "application/json"]) + } +} diff --git a/fakestagramTests/RestClientTest.swift b/fakestagramTests/RestClientTest.swift new file mode 100644 index 0000000..9ed3fc0 --- /dev/null +++ b/fakestagramTests/RestClientTest.swift @@ -0,0 +1,47 @@ +// +// RestClientTest.swift +// fakestagramTests +// +// Created by LuisE on 10/11/19. +// Copyright © 2019 3zcurdia. All rights reserved. +// + +import XCTest +import DVR +@testable import fakestagram + +class RestClientTest: XCTestCase { + func testShowPosts() { + let session = Session(cassetteName: "posts.successful") + let client = Client(session: session, baseUrl: "https://fakestagram-api.herokuapp.com") + let restClient = RestClient<[Post]>(client: client, basePath: "/api/v1/posts") + let exp = expectation(description: "Successfull index posts") + + restClient.show { posts in + exp.fulfill() + XCTAssertNotNil(posts) + XCTAssertEqual(posts!.count, 25) + XCTAssertEqual(posts!.first!.id, 228) + XCTAssertEqual(posts!.first!.title, "Example") + } + + waitForExpectations(timeout: 2, handler: nil) + } + + func testShowPost() { + let session = Session(cassetteName: "show_post.successful") + let client = Client(session: session, baseUrl: "https://fakestagram-api.herokuapp.com") + + let restClient = RestClient(client: client, basePath: "/api/v1/posts") + let exp = expectation(description: "Successfull index posts") + + restClient.show(id: "228") { post in + exp.fulfill() + XCTAssertNotNil(post) + XCTAssertEqual(post!.id, 228) + XCTAssertEqual(post!.title, "Example") + } + + waitForExpectations(timeout: 2, handler: nil) + } +} diff --git a/fakestagramTests/casettes/posts.successful.json b/fakestagramTests/casettes/posts.successful.json new file mode 100644 index 0000000..24d2ccf --- /dev/null +++ b/fakestagramTests/casettes/posts.successful.json @@ -0,0 +1,444 @@ +{ + "interactions" : [ + { + "request" : { + "method" : "GET", + "headers" : { + "Content-Type" : "application\/json", + "Authorization" : "Bearer f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e", + "Accept" : "application\/json" + }, + "url" : "https:\/\/fakestagram-api.herokuapp.com\/api\/v1\/posts" + }, + "recorded_at" : 1570837975.1744719, + "response" : { + "url" : "https:\/\/fakestagram-api.herokuapp.com\/api\/v1\/posts", + "headers" : { + "Etag" : "W\/\"0d7dc5010941ab1928365db038e254f9\"", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "X-Request-Id" : "f9b64a0a-2902-46c5-9355-feffcda2b924", + "Vary" : "Origin", + "X-Download-Options" : "noopen", + "Via" : "1.1 vegur", + "X-Permitted-Cross-Domain-Policies" : "none", + "X-Content-Type-Options" : "nosniff", + "Content-Length" : "0", + "X-Xss-Protection" : "1; mode=block", + "Connection" : "keep-alive", + "Cache-Control" : "max-age=0, private, must-revalidate", + "Content-Type" : "application\/json; charset=utf-8", + "X-Frame-Options" : "SAMEORIGIN", + "X-Runtime" : "0.087793", + "Referrer-Policy" : "strict-origin-when-cross-origin", + "Date" : "Fri, 11 Oct 2019 23:52:54 GMT", + "Transfer-Encoding" : "Identity", + "Server" : "Cowboy" + }, + "body" : [ + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e", + "name" : "John Carney", + "avatar_url" : null + }, + "id" : 228, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZTA9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--b668068c1f6252a77beacbd9313d8f4e078a400f\/4ed83e29-b955-4dc6-b5ee-eafd994e9de8", + "title" : "Example", + "created_at" : "2019-10-04T21:15:42.650Z", + "liked" : true, + "updated_at" : "2019-10-04T21:15:42.738Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e", + "name" : "John Carney", + "avatar_url" : null + }, + "id" : 227, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZWs9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--af591b63753c7a621bbaece3f99c79c9375551b4\/9b13eeaf-3a33-45d8-9f96-09506672ddf4", + "title" : "Example", + "created_at" : "2019-10-04T05:11:50.647Z", + "liked" : true, + "updated_at" : "2019-10-04T05:11:50.701Z", + "comments_count" : 0 + }, + { + "location" : "South San Francisco BART, Bart, South San Francisco, San Mateo County, California, 94014, USA", + "likes_count" : 0, + "author" : { + "id" : "26c0b0a1-6b04-4625-9d08-f8b348b968d6", + "name" : "Gerard Hane", + "avatar_url" : null + }, + "id" : 226, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZVk9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--a89eead659aa964493322d79f9f5cca4db18ff9d\/3340cca1-dd82-4c63-ba8f-3986bddbc500", + "title" : "1566158823894", + "created_at" : "2019-08-18T20:07:04.661Z", + "liked" : false, + "updated_at" : "2019-08-18T20:07:04.686Z", + "comments_count" : 0 + }, + { + "location" : "South San Francisco BART, Bart, South San Francisco, San Mateo County, California, 94014, USA", + "likes_count" : 0, + "author" : { + "id" : "26c0b0a1-6b04-4625-9d08-f8b348b968d6", + "name" : "Gerard Hane", + "avatar_url" : null + }, + "id" : 225, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZVU9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--0e22a6bc1f9e9477762e32356036134efd54eb55\/70bb725c-e86e-4430-b925-11c25718392a", + "title" : "1566158820509", + "created_at" : "2019-08-18T20:07:01.750Z", + "liked" : false, + "updated_at" : "2019-08-18T20:07:01.854Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 2, + "author" : { + "id" : "ababf2cd-0eb9-45b6-99e5-90de794f7860", + "name" : "Katelyn Sanford", + "avatar_url" : null + }, + "id" : 224, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZVE9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--b927d8cd407bfb7f4e32dff66842cbce798e10a3\/78a88dea-8b8e-4d33-a633-5e492bc14842", + "title" : ":p", + "created_at" : "2019-08-11T20:17:49.826Z", + "liked" : false, + "updated_at" : "2019-08-11T20:17:49.895Z", + "comments_count" : 2 + }, + { + "location" : "", + "likes_count" : 1, + "author" : { + "id" : "9b590ebf-4875-4a83-8249-c6223e0d1a2a", + "name" : "Sammy Beier", + "avatar_url" : null + }, + "id" : 223, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZU09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--5726e694e2d04ec83ee589ff11293f8d4a49daf5\/3c7f898e-ae8d-410c-800d-20c590b8118e", + "title" : "1565393475188", + "created_at" : "2019-08-09T23:31:20.358Z", + "liked" : false, + "updated_at" : "2019-08-09T23:31:20.380Z", + "comments_count" : 1 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "f9d53895-93f9-43c2-973e-ce47aadf6239", + "name" : "Arlinda Balistreri", + "avatar_url" : null + }, + "id" : 222, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZUk9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3d89565f024de56af1b3d510d954b64e11593812\/0314b818-2096-4387-bcee-ed62594b013e", + "title" : "1565392767381", + "created_at" : "2019-08-09T23:19:30.715Z", + "liked" : false, + "updated_at" : "2019-08-09T23:19:30.737Z", + "comments_count" : 1 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "f9d53895-93f9-43c2-973e-ce47aadf6239", + "name" : "Arlinda Balistreri", + "avatar_url" : null + }, + "id" : 221, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZUU9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--26a6cfcb28d63275d7d2e38cc19cc318106bc7a1\/74ee9a0c-3fd3-413f-9a05-ed56514f9b4c", + "title" : "1565392624022", + "created_at" : "2019-08-09T23:17:06.162Z", + "liked" : false, + "updated_at" : "2019-08-09T23:17:06.191Z", + "comments_count" : 4 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "f9d53895-93f9-43c2-973e-ce47aadf6239", + "name" : "Arlinda Balistreri", + "avatar_url" : null + }, + "id" : 220, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZUE9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--84f7d1d7e2c9624478e486b85ef289101adff64b\/89fe9faf-dafb-4c44-9810-55f9dc1643f7", + "title" : "1565389845416", + "created_at" : "2019-08-09T22:30:45.562Z", + "liked" : false, + "updated_at" : "2019-08-09T22:30:45.589Z", + "comments_count" : 11 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "f9d53895-93f9-43c2-973e-ce47aadf6239", + "name" : "Arlinda Balistreri", + "avatar_url" : null + }, + "id" : 219, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZDg9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--aa3dbf1922f86c5ab9f874710541abd83a10aa21\/8d34e2e6-d33d-4ac1-954b-b0c3e1403301", + "title" : "1565389827272", + "created_at" : "2019-08-09T22:30:27.612Z", + "liked" : false, + "updated_at" : "2019-08-09T22:30:27.633Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "f9d53895-93f9-43c2-973e-ce47aadf6239", + "name" : "Arlinda Balistreri", + "avatar_url" : null + }, + "id" : 218, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZDQ9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--9534d1e17eab3138685b2ae633f1fce2b3072fa3\/24f26bae-f215-499a-a985-ad1cca2168e3", + "title" : "1565387654424", + "created_at" : "2019-08-09T21:54:14.782Z", + "liked" : false, + "updated_at" : "2019-08-09T21:54:14.823Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 1, + "author" : { + "id" : "cb9a00b1-c23d-4dcd-84a3-0066cc930adc", + "name" : "Melvina DuBuque", + "avatar_url" : null + }, + "id" : 217, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZDA9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--ce6d7e4e61a3bad722d0b1ecc9d9c85a5d443782\/b077e3b9-7abd-4f01-a3d4-baaeaa03d035", + "title" : "1565284409539", + "created_at" : "2019-08-08T17:13:30.621Z", + "liked" : false, + "updated_at" : "2019-08-08T17:13:30.647Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "cb9a00b1-c23d-4dcd-84a3-0066cc930adc", + "name" : "Melvina DuBuque", + "avatar_url" : null + }, + "id" : 216, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZHc9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--5fd762895b481581889f8370850660961ac27ae2\/79075b3f-a2f6-4a28-8478-2b2024361b8f", + "title" : "1565284311613", + "created_at" : "2019-08-08T17:11:51.968Z", + "liked" : false, + "updated_at" : "2019-08-08T17:11:52.041Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "1a11b5ea-b450-478c-b968-6e4bf1724a27", + "name" : "Garth Hartmann", + "avatar_url" : null + }, + "id" : 215, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZHM9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3aaf6ee04bf6e2e276af0a7542057df4bc859a9d\/b2f6db08-2257-4bd4-9371-e784c7dd3ef5", + "title" : "1565240319353", + "created_at" : "2019-08-08T04:58:39.800Z", + "liked" : false, + "updated_at" : "2019-08-08T04:58:39.871Z", + "comments_count" : 0 + }, + { + "location" : "Powell Street Station, Market Street, Union Square, San Francisco, San Francisco City and County, California, 94103-3124, USA", + "likes_count" : 0, + "author" : { + "id" : "44a51289-6d9e-4e27-8638-6d3102511ad8", + "name" : "Melanie Gaylord", + "avatar_url" : null + }, + "id" : 214, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZG89IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--475805cb649993f55820a95307fc1f7a80db3f4e\/71f1b9e0-f262-4261-ad1d-ece8046151ef", + "title" : "1565064895736", + "created_at" : "2019-08-06T04:14:56.879Z", + "liked" : false, + "updated_at" : "2019-08-06T04:14:56.920Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "90834f94-fd51-420a-b350-30851abf61d5", + "name" : "Belle Douglas", + "avatar_url" : null + }, + "id" : 213, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZGs9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--f5b051063503aadef9f0cd9a0723c12d2d627dde\/bc279b9d-2dce-49c6-9120-4e4b575f7a78", + "title" : "1565028839754", + "created_at" : "2019-08-05T18:14:00.016Z", + "liked" : false, + "updated_at" : "2019-08-05T18:14:00.078Z", + "comments_count" : 0 + }, + { + "location" : "Powell Street Station, Market Street, Union Square, San Francisco, San Francisco City and County, California, 94103-3124, USA", + "likes_count" : 0, + "author" : { + "id" : "44a51289-6d9e-4e27-8638-6d3102511ad8", + "name" : "Melanie Gaylord", + "avatar_url" : null + }, + "id" : 212, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZGc9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--ead89bde0e160956f51b9d5d7637c4ca1b8d5643\/3c16b6e2-838b-453e-87a8-c8e623efee6f", + "title" : "1564953882318", + "created_at" : "2019-08-04T21:24:43.366Z", + "liked" : false, + "updated_at" : "2019-08-04T21:24:43.424Z", + "comments_count" : 0 + }, + { + "location" : "Powell Street Station, Market Street, Union Square, San Francisco, San Francisco City and County, California, 94103-3124, USA", + "likes_count" : 1, + "author" : { + "id" : "44a51289-6d9e-4e27-8638-6d3102511ad8", + "name" : "Melanie Gaylord", + "avatar_url" : null + }, + "id" : 211, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZGM9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--aa53a5c71d2af02eb63f222e8f62666ac020626d\/70601715-1ce5-4886-8647-614a88acdc3e", + "title" : "1564938932927", + "created_at" : "2019-08-04T17:15:34.008Z", + "liked" : false, + "updated_at" : "2019-08-04T17:15:34.072Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 1, + "author" : { + "id" : "15e6a545-c5c7-4775-b3b3-f4c08622b7f8", + "name" : "Venessa Prosacco", + "avatar_url" : null + }, + "id" : 209, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZFE9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--677615c8da9ee16d4a2f2d04d71620345dad3dcb\/a37c2b48-53b0-4200-8ca4-0ab3c601c2be", + "title" : "No lo haga compa", + "created_at" : "2019-07-26T22:14:55.445Z", + "liked" : false, + "updated_at" : "2019-07-26T22:14:55.465Z", + "comments_count" : 2 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "15e6a545-c5c7-4775-b3b3-f4c08622b7f8", + "name" : "Venessa Prosacco", + "avatar_url" : null + }, + "id" : 208, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZE09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--701845e2a532406662abd63bd9903cfb3d6fa427\/f56ff4ea-21aa-416f-9644-bbcc36c0a489", + "title" : "No lo haga compa", + "created_at" : "2019-07-26T22:14:48.407Z", + "liked" : false, + "updated_at" : "2019-07-26T22:14:48.472Z", + "comments_count" : 2 + }, + { + "location" : "Calle Durango, Condesa, Mexico City, Cuauhtémoc, Mexico City, 06140, Mexico", + "likes_count" : 0, + "author" : { + "id" : "3c06d9f5-9cc0-483e-a089-8bcc4c11c14e", + "name" : "Shenita Champlin", + "avatar_url" : null + }, + "id" : 207, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZEU9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--b375a88531fce2fba8301e8f4d9cda92016317f6\/2a6c1b7a-16d8-4155-9825-e92a834f083a", + "title" : "1563810644322", + "created_at" : "2019-07-22T15:50:48.103Z", + "liked" : false, + "updated_at" : "2019-07-22T15:50:48.219Z", + "comments_count" : 1 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "10b7accf-1817-4fe5-9674-8f7703220e96", + "name" : "Shonda Hammes", + "avatar_url" : null + }, + "id" : 206, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZEE9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--6b9c9e7a5919fc296349d7e0ba3eb327fab7e28d\/8be5a13a-b703-4e9d-bfa8-640969a1d03b", + "title" : "Las svm son chidas", + "created_at" : "2019-07-11T17:43:09.553Z", + "liked" : false, + "updated_at" : "2019-07-11T17:43:09.600Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "10b7accf-1817-4fe5-9674-8f7703220e96", + "name" : "Shonda Hammes", + "avatar_url" : null + }, + "id" : 205, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBYzg9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--9bd1e3affaa38a100b254bcc0ebfbd34697367ee\/5abbd134-50c2-4529-8474-64ad58de7383", + "title" : "Mr. Bean es mi pastor!", + "created_at" : "2019-07-11T17:40:58.360Z", + "liked" : false, + "updated_at" : "2019-07-11T17:40:58.429Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "10b7accf-1817-4fe5-9674-8f7703220e96", + "name" : "Shonda Hammes", + "avatar_url" : null + }, + "id" : 204, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZEk9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--f0193550348281afd2b2998b93997529e8ca4d16\/9b188868-6f6a-424d-b577-5bd8e99fff4c", + "title" : "Todos los del diplomado en las fiestas jajaja!", + "created_at" : "2019-07-10T23:46:37.725Z", + "liked" : false, + "updated_at" : "2019-07-23T01:22:34.916Z", + "comments_count" : 0 + }, + { + "location" : "", + "likes_count" : 1, + "author" : { + "id" : "519661d9-5f38-45dc-ba4e-ec3522aa128a", + "name" : "Lesley Funk", + "avatar_url" : null + }, + "id" : 203, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBY3M9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--954b1ccc1f0dcb9d061ac38009b43f0bd727b118\/83e80764-2bd6-40e7-b6a8-01c54af1dd84", + "title" : "1562190435299", + "created_at" : "2019-07-03T21:47:15.564Z", + "liked" : false, + "updated_at" : "2019-07-03T21:47:15.623Z", + "comments_count" : 1 + } + ], + "status" : 200 + } + } + ], + "name" : "posts.successful" +} diff --git a/fakestagramTests/casettes/show_post.successful.json b/fakestagramTests/casettes/show_post.successful.json new file mode 100644 index 0000000..03e91e1 --- /dev/null +++ b/fakestagramTests/casettes/show_post.successful.json @@ -0,0 +1,57 @@ +{ + "interactions" : [ + { + "response" : { + "status" : 200, + "body" : { + "location" : "", + "likes_count" : 0, + "author" : { + "id" : "f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e", + "name" : "John Carney", + "avatar_url" : null + }, + "id" : 228, + "image_url" : "https:\/\/fakestagram-api.herokuapp.com\/rails\/active_storage\/blobs\/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZTA9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--b668068c1f6252a77beacbd9313d8f4e078a400f\/4ed83e29-b955-4dc6-b5ee-eafd994e9de8", + "title" : "Example", + "created_at" : "2019-10-04T21:15:42.650Z", + "liked" : false, + "updated_at" : "2019-10-04T21:15:42.738Z", + "comments_count" : 0 + }, + "headers" : { + "X-Permitted-Cross-Domain-Policies" : "none", + "Content-Type" : "application\/json; charset=utf-8", + "X-Request-Id" : "c6266b7f-6e74-4fc8-808c-6046b689f67f", + "Via" : "1.1 vegur", + "Cache-Control" : "max-age=0, private, must-revalidate", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Date" : "Sat, 12 Oct 2019 00:46:20 GMT", + "Transfer-Encoding" : "Identity", + "X-Xss-Protection" : "1; mode=block", + "Referrer-Policy" : "strict-origin-when-cross-origin", + "X-Download-Options" : "noopen", + "Server" : "Cowboy", + "X-Runtime" : "0.063186", + "Connection" : "keep-alive", + "Etag" : "W\/\"819b2d0fa0647c5c452d27fb77a8d11e\"", + "X-Frame-Options" : "SAMEORIGIN", + "Vary" : "Origin", + "X-Content-Type-Options" : "nosniff" + }, + "url" : "https:\/\/fakestagram-api.herokuapp.com\/api\/v1\/posts\/228" + }, + "request" : { + "headers" : { + "Accept" : "application\/json", + "Content-Type" : "application\/json", + "Authorization" : "Bearer f41af9b1-5a7e-4f0b-8c88-e44f686b1d2e" + }, + "method" : "GET", + "url" : "https:\/\/fakestagram-api.herokuapp.com\/api\/v1\/posts\/228" + }, + "recorded_at" : 1570841180.898001 + } + ], + "name" : "show_post.successful" +} diff --git a/fakestagramTests/fakestagramTests.swift b/fakestagramTests/fakestagramTests.swift deleted file mode 100644 index f022cfd..0000000 --- a/fakestagramTests/fakestagramTests.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// fakestagramTests.swift -// fakestagramTests -// -// Created by LuisE on 9/24/19. -// Copyright © 2019 3zcurdia. All rights reserved. -// - -import XCTest -@testable import fakestagram - -class fakestagramTests: XCTestCase { - - override func setUp() { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } - - func testPerformanceExample() { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -}