From ca4d9ae0e0f32a640e1c31f6d222b47654c40812 Mon Sep 17 00:00:00 2001 From: Spencer Curtis Date: Tue, 1 Sep 2020 17:26:55 -0600 Subject: [PATCH 01/20] Remove Firebase functionality from project --- Cocopods-Homebrew-and-Ruby-Install-Guide.md | 143 -------------- LambdaTimeline.xcodeproj/project.pbxproj | 148 +-------------- LambdaTimeline/Helpers/Cache.swift | 25 --- .../User+DictionaryRepresentation.swift | 21 --- .../Helpers/FirebaseConvertible.swift | 13 -- LambdaTimeline/Helpers/Networking.swift | 51 ----- .../Operations/ConcurrentOperation.swift | 64 ------- .../Operations/FetchMediaOperation.swift | 59 ------ .../Model Controllers/PostController.swift | 117 ++---------- LambdaTimeline/Models/Author.swift | 36 ---- LambdaTimeline/Models/Comment.swift | 30 +-- LambdaTimeline/Models/Post.swift | 75 ++------ LambdaTimeline/Resources/AppDelegate.swift | 28 +-- .../{Base.lproj => }/Main.storyboard | 117 +++++++----- .../ImagePostDetailTableViewController.swift | 28 ++- .../ImagePostViewController.swift | 73 +++----- .../PostsCollectionViewController.swift | 101 ++-------- .../SignInViewController.swift | 76 +++----- .../Views/ImagePostCollectionViewCell.swift | 37 ++-- Podfile | 15 -- Podfile.lock | 174 ------------------ 21 files changed, 205 insertions(+), 1226 deletions(-) delete mode 100644 Cocopods-Homebrew-and-Ruby-Install-Guide.md delete mode 100644 LambdaTimeline/Helpers/Cache.swift delete mode 100644 LambdaTimeline/Helpers/Extensions/User+DictionaryRepresentation.swift delete mode 100644 LambdaTimeline/Helpers/FirebaseConvertible.swift delete mode 100644 LambdaTimeline/Helpers/Networking.swift delete mode 100644 LambdaTimeline/Helpers/Operations/ConcurrentOperation.swift delete mode 100644 LambdaTimeline/Helpers/Operations/FetchMediaOperation.swift delete mode 100644 LambdaTimeline/Models/Author.swift rename LambdaTimeline/Storyboards/{Base.lproj => }/Main.storyboard (84%) delete mode 100644 Podfile delete mode 100644 Podfile.lock diff --git a/Cocopods-Homebrew-and-Ruby-Install-Guide.md b/Cocopods-Homebrew-and-Ruby-Install-Guide.md deleted file mode 100644 index 2654e85a..00000000 --- a/Cocopods-Homebrew-and-Ruby-Install-Guide.md +++ /dev/null @@ -1,143 +0,0 @@ -# Cocopods Homebrew and Ruby Install Guide - -You'll use Hombrew (`brew`) to install Cocoapods in order to build the Firebase project. - -Homebrew is built on Ruby, and you'll want to configure Ruby (programming language) so that it's update to date. - -With the system installed version in macOS, you don't have the ability to update the libraries that come with Ruby (`gem update`). - -Gem is the tool to update Ruby packages, which is a prerequisite for Homebrew (`brew`). - -## Enter `rbenv` - -To help with managing different versions of Ruby, there is a tool called `rbenv`. - -You can use it to install a different version of Ruby, which you can then update, and then install hombrew, and then install Cocoapods. - -# When Ruby gem update fails (and how to install Cocoapods) -​ -You can't update the system version of Ruby, and you shouldn't do that anyway, since Apple manages it. Forcing it to change can cause issues with other tools that Apple ships with each verison of macOS. - -Running the command in Terminal may fail. - -`gem update` - -If you see this error, then you'll want to setup `rbenv` to manage your versions of Ruby (programming langauge). - -`Updating installed gems -Updating CFPropertyList -ERROR: While executing gem ... (Gem::FilePermissionError) - You don't have write permissions for the /Library/Ruby/Gems/2.6.0 directory.` - - -## Install `rbenv` - -Follow the [rbenv install instructors](https://github.com/rbenv/rbenv) to setup your `.zshrc` file for `rbenv` - -### Terminal setup (zsh/bash for rbenv) - -To follow the instructions you'll either need to edit your zsh setup file, or bash. In Catalina (10.15) Apple made `zsh` the new default shell in Terminal (instead of `bash`). - -`open ~/.zshrc` - -Will allow you to open and edit your .zshrc file (in your home directory) that is used by the shell `zsh` in Catalina (If you're still using bash, edit the `~/.bashrc` file) - -## Use `rbenv` to see what versions are installed - -Run the command: - -`rbenv versions` - -``` -* system (set by /Users/paulsolt/.rbenv/version) - 2.6.2 - 2.6.3 -``` - -And you can see the current "global" version of Ruby is the "system"" default (what Apple provides, and it's read-only) - -## Install a new Ruby version that will read-write - -Run the command: - -`rbenv install 2.6.3` - -## Switch Ruby Versions - -After you install a new version of Ruby, you can switch to it as the default. - -`rbenv global 2.6.3` - -Will change Ruby across the system, unless you've specified a local version (inside a directory). - -NOTE: Sometimes you need to switch back to system with `rbenv global system` if Apple related commands are failing, but generally you'll want to stay on your version) - -## Update Ruby Gems (Package Manager for Ruby) - -Gems are either applications or libraries that you can use within Ruby projects or apps. - -Run the command to keep your gems for the current version of Ruby up to date. - -`gem update` - -## Install Homebrew - -To install [Homebrew](https://brew.sh) Run - -``` -/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" -``` - -## Install Cocoapods (if you don't have it installed) - -```brew install cocoapods``` - -## (Optional) Update Cocoapods - -Update your current cocoapods version to keep it up to date after it's installed: - -``` -brew upgrade cocoapods -``` - -## Test pod - -Type the command test pod is installed, you should see normal output. - -``` -Usage: - - $ pod COMMAND - - CocoaPods, the Cocoa library package manager. - ... -``` - - -## (Extra) Occasionally you get errors running pod / gem / etc. - -Errors are one of the challenges you'll need to overcome as a developer. Maintaining your Mac is part of the job. - -I Google these errors or I follow the instructions provided in the error (read the message). Usually they have a hint. - -On my system I had overwritten an install of Ruby 2.6.3 that I believe is causing this issue. It's warning me every time I try to use the command `pod` (not good) - -``` -pod - -Ignoring json-2.3.0 because its extensions are not built. Try: gem pristine json --version 2.3.0 -Ignoring json-2.3.0 because its extensions are not built. Try: gem pristine json --version 2.3.0 -... - -``` - -Run a command to install gems with the current version you installed (2.6.3 in this case). - -Keep in mind that ruby gems are install per install of Ruby, so you might need to do this again if there's a new version of Ruby to install. - -``` -rbenv global 2.6.3 -gem pristine --all -``` - -After running `gem pristine` (and waiting 5-10 minutes) the errors went away. diff --git a/LambdaTimeline.xcodeproj/project.pbxproj b/LambdaTimeline.xcodeproj/project.pbxproj index 95ea1e3d..b2af5414 100644 --- a/LambdaTimeline.xcodeproj/project.pbxproj +++ b/LambdaTimeline.xcodeproj/project.pbxproj @@ -3,63 +3,45 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ 4646377C216FDE4B00E7FF73 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4646377B216FDE4B00E7FF73 /* AppDelegate.swift */; }; - 46463781216FDE4B00E7FF73 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4646377F216FDE4B00E7FF73 /* Main.storyboard */; }; 46463783216FDE4C00E7FF73 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 46463782216FDE4C00E7FF73 /* Assets.xcassets */; }; 46463786216FDE4C00E7FF73 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46463784216FDE4C00E7FF73 /* LaunchScreen.storyboard */; }; 46463790216FFD1B00E7FF73 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4646378F216FFD1B00E7FF73 /* Post.swift */; }; 46463792216FFDD900E7FF73 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46463791216FFDD900E7FF73 /* Comment.swift */; }; - 464637992170048900E7FF73 /* FirebaseConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 464637982170048900E7FF73 /* FirebaseConvertible.swift */; }; 4646379C2170091A00E7FF73 /* PostController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4646379B2170091A00E7FF73 /* PostController.swift */; }; 46A0366A21700F5100E7FF73 /* PostsCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A0366921700F5100E7FF73 /* PostsCollectionViewController.swift */; }; 46A0366D2170158900E7FF73 /* SignInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A0366C2170158900E7FF73 /* SignInViewController.swift */; }; - 46CFE6F32170757F00E7FF73 /* User+DictionaryRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CFE6F22170757F00E7FF73 /* User+DictionaryRepresentation.swift */; }; 46CFE6F521707D0000E7FF73 /* ImagePostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CFE6F421707D0000E7FF73 /* ImagePostViewController.swift */; }; 46CFE6F721707FA600E7FF73 /* UIViewController+InformationalAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CFE6F621707FA600E7FF73 /* UIViewController+InformationalAlert.swift */; }; 46CFE6F92170862C00E7FF73 /* ShiftableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CFE6F82170862C00E7FF73 /* ShiftableViewController.swift */; }; - 46CFE6FB21714E6100E7FF73 /* Author.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CFE6FA21714E6100E7FF73 /* Author.swift */; }; - 46CFE6FD217154F500E7FF73 /* Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CFE6FC217154F500E7FF73 /* Networking.swift */; }; - 46CFE6FF2171556D00E7FF73 /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CFE6FE2171556D00E7FF73 /* ConcurrentOperation.swift */; }; - 46CFE7012171559500E7FF73 /* FetchMediaOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CFE7002171559500E7FF73 /* FetchMediaOperation.swift */; }; 46CFE7032171572600E7FF73 /* ImagePostCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46CFE7022171572600E7FF73 /* ImagePostCollectionViewCell.swift */; }; - 46D571F32172D43B00E7FF73 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D571F22172D43B00E7FF73 /* Cache.swift */; }; + 46D1A48924FF0BC4008D1CA7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46D1A48824FF0BC4008D1CA7 /* Main.storyboard */; }; 46D571F52173CF3E00E7FF73 /* UIImage+Ratio.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D571F42173CF3E00E7FF73 /* UIImage+Ratio.swift */; }; 46D571F82173FC2700E7FF73 /* ImagePostDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D571F72173FC2700E7FF73 /* ImagePostDetailTableViewController.swift */; }; - E453457955DF907FCBD117F1 /* Pods_LambdaTimeline.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA39CACB677861CF84322FB5 /* Pods_LambdaTimeline.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 33A2B89DE9E21538434BD640 /* Pods-LambdaTimeline.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LambdaTimeline.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LambdaTimeline/Pods-LambdaTimeline.debug.xcconfig"; sourceTree = ""; }; 46463778216FDE4B00E7FF73 /* LambdaTimeline.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LambdaTimeline.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4646377B216FDE4B00E7FF73 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 46463780216FDE4B00E7FF73 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46463782216FDE4C00E7FF73 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 46463785216FDE4C00E7FF73 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 46463787216FDE4C00E7FF73 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4646378F216FFD1B00E7FF73 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = ""; }; 46463791216FFDD900E7FF73 /* Comment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; - 464637982170048900E7FF73 /* FirebaseConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseConvertible.swift; sourceTree = ""; }; 4646379B2170091A00E7FF73 /* PostController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostController.swift; sourceTree = ""; }; 46A0366921700F5100E7FF73 /* PostsCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsCollectionViewController.swift; sourceTree = ""; }; 46A0366C2170158900E7FF73 /* SignInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInViewController.swift; sourceTree = ""; }; - 46CFE6F22170757F00E7FF73 /* User+DictionaryRepresentation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "User+DictionaryRepresentation.swift"; sourceTree = ""; }; 46CFE6F421707D0000E7FF73 /* ImagePostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePostViewController.swift; sourceTree = ""; }; 46CFE6F621707FA600E7FF73 /* UIViewController+InformationalAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+InformationalAlert.swift"; sourceTree = ""; }; 46CFE6F82170862C00E7FF73 /* ShiftableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShiftableViewController.swift; sourceTree = ""; }; - 46CFE6FA21714E6100E7FF73 /* Author.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Author.swift; sourceTree = ""; }; - 46CFE6FC217154F500E7FF73 /* Networking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Networking.swift; sourceTree = ""; }; - 46CFE6FE2171556D00E7FF73 /* ConcurrentOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentOperation.swift; sourceTree = ""; }; - 46CFE7002171559500E7FF73 /* FetchMediaOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchMediaOperation.swift; sourceTree = ""; }; 46CFE7022171572600E7FF73 /* ImagePostCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePostCollectionViewCell.swift; sourceTree = ""; }; - 46D571F22172D43B00E7FF73 /* Cache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cache.swift; sourceTree = ""; }; + 46D1A48824FF0BC4008D1CA7 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 46D571F42173CF3E00E7FF73 /* UIImage+Ratio.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Ratio.swift"; sourceTree = ""; }; 46D571F72173FC2700E7FF73 /* ImagePostDetailTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePostDetailTableViewController.swift; sourceTree = ""; }; - 5D2CCD6C68779B0A70AC37FA /* Pods-LambdaTimeline.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LambdaTimeline.release.xcconfig"; path = "Pods/Target Support Files/Pods-LambdaTimeline/Pods-LambdaTimeline.release.xcconfig"; sourceTree = ""; }; - AA39CACB677861CF84322FB5 /* Pods_LambdaTimeline.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LambdaTimeline.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -67,29 +49,17 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E453457955DF907FCBD117F1 /* Pods_LambdaTimeline.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 2B7D7DE8669C7C706445FCCC /* Pods */ = { - isa = PBXGroup; - children = ( - 33A2B89DE9E21538434BD640 /* Pods-LambdaTimeline.debug.xcconfig */, - 5D2CCD6C68779B0A70AC37FA /* Pods-LambdaTimeline.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; 4646376F216FDE4B00E7FF73 = { isa = PBXGroup; children = ( 4646377A216FDE4B00E7FF73 /* LambdaTimeline */, 46463779216FDE4B00E7FF73 /* Products */, - 2B7D7DE8669C7C706445FCCC /* Pods */, - 7C2A25429FC0F968FC1D35E7 /* Frameworks */, ); sourceTree = ""; }; @@ -119,7 +89,6 @@ isa = PBXGroup; children = ( 4646378F216FFD1B00E7FF73 /* Post.swift */, - 46CFE6FA21714E6100E7FF73 /* Author.swift */, 46463791216FFDD900E7FF73 /* Comment.swift */, ); path = Models; @@ -138,7 +107,7 @@ 46463797216FFF7400E7FF73 /* Storyboards */ = { isa = PBXGroup; children = ( - 4646377F216FDE4B00E7FF73 /* Main.storyboard */, + 46D1A48824FF0BC4008D1CA7 /* Main.storyboard */, 46463784216FDE4C00E7FF73 /* LaunchScreen.storyboard */, ); path = Storyboards; @@ -171,23 +140,10 @@ path = Views; sourceTree = ""; }; - 46CFE7052171573200E7FF73 /* Operations */ = { - isa = PBXGroup; - children = ( - 46CFE7002171559500E7FF73 /* FetchMediaOperation.swift */, - 46CFE6FE2171556D00E7FF73 /* ConcurrentOperation.swift */, - ); - path = Operations; - sourceTree = ""; - }; 46CFE7062171573F00E7FF73 /* Helpers */ = { isa = PBXGroup; children = ( - 46CFE7052171573200E7FF73 /* Operations */, 46D571F62173D6D200E7FF73 /* Extensions */, - 46D571F22172D43B00E7FF73 /* Cache.swift */, - 464637982170048900E7FF73 /* FirebaseConvertible.swift */, - 46CFE6FC217154F500E7FF73 /* Networking.swift */, 46CFE6F82170862C00E7FF73 /* ShiftableViewController.swift */, ); path = Helpers; @@ -196,21 +152,12 @@ 46D571F62173D6D200E7FF73 /* Extensions */ = { isa = PBXGroup; children = ( - 46CFE6F22170757F00E7FF73 /* User+DictionaryRepresentation.swift */, 46D571F42173CF3E00E7FF73 /* UIImage+Ratio.swift */, 46CFE6F621707FA600E7FF73 /* UIViewController+InformationalAlert.swift */, ); path = Extensions; sourceTree = ""; }; - 7C2A25429FC0F968FC1D35E7 /* Frameworks */ = { - isa = PBXGroup; - children = ( - AA39CACB677861CF84322FB5 /* Pods_LambdaTimeline.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -218,12 +165,9 @@ isa = PBXNativeTarget; buildConfigurationList = 4646378A216FDE4C00E7FF73 /* Build configuration list for PBXNativeTarget "LambdaTimeline" */; buildPhases = ( - 4E9D00EBF902E9530D554E98 /* [CP] Check Pods Manifest.lock */, 46463774216FDE4B00E7FF73 /* Sources */, 46463775216FDE4B00E7FF73 /* Frameworks */, 46463776216FDE4B00E7FF73 /* Resources */, - 931381193B5D2856F9B0CA8C /* [CP] Embed Pods Frameworks */, - 8108F7AF1127B3F2AAFC77E1 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -273,93 +217,27 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 46D1A48924FF0BC4008D1CA7 /* Main.storyboard in Resources */, 46463786216FDE4C00E7FF73 /* LaunchScreen.storyboard in Resources */, 46463783216FDE4C00E7FF73 /* Assets.xcassets in Resources */, - 46463781216FDE4B00E7FF73 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 4E9D00EBF902E9530D554E98 /* [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-LambdaTimeline-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; - }; - 8108F7AF1127B3F2AAFC77E1 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-LambdaTimeline/Pods-LambdaTimeline-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-LambdaTimeline/Pods-LambdaTimeline-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-LambdaTimeline/Pods-LambdaTimeline-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 931381193B5D2856F9B0CA8C /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-LambdaTimeline/Pods-LambdaTimeline-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-LambdaTimeline/Pods-LambdaTimeline-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-LambdaTimeline/Pods-LambdaTimeline-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 46463774216FDE4B00E7FF73 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 46A0366D2170158900E7FF73 /* SignInViewController.swift in Sources */, - 46CFE6FB21714E6100E7FF73 /* Author.swift in Sources */, 46CFE6F92170862C00E7FF73 /* ShiftableViewController.swift in Sources */, 4646377C216FDE4B00E7FF73 /* AppDelegate.swift in Sources */, - 46CFE6FD217154F500E7FF73 /* Networking.swift in Sources */, 46CFE6F521707D0000E7FF73 /* ImagePostViewController.swift in Sources */, - 46CFE6FF2171556D00E7FF73 /* ConcurrentOperation.swift in Sources */, 46463790216FFD1B00E7FF73 /* Post.swift in Sources */, - 46CFE6F32170757F00E7FF73 /* User+DictionaryRepresentation.swift in Sources */, - 46D571F32172D43B00E7FF73 /* Cache.swift in Sources */, - 46CFE7012171559500E7FF73 /* FetchMediaOperation.swift in Sources */, 46D571F82173FC2700E7FF73 /* ImagePostDetailTableViewController.swift in Sources */, 46CFE7032171572600E7FF73 /* ImagePostCollectionViewCell.swift in Sources */, 4646379C2170091A00E7FF73 /* PostController.swift in Sources */, - 464637992170048900E7FF73 /* FirebaseConvertible.swift in Sources */, 46A0366A21700F5100E7FF73 /* PostsCollectionViewController.swift in Sources */, 46D571F52173CF3E00E7FF73 /* UIImage+Ratio.swift in Sources */, 46463792216FFDD900E7FF73 /* Comment.swift in Sources */, @@ -370,14 +248,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - 4646377F216FDE4B00E7FF73 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 46463780216FDE4B00E7FF73 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; 46463784216FDE4C00E7FF73 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -507,17 +377,17 @@ }; 4646378B216FDE4C00E7FF73 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 33A2B89DE9E21538434BD640 /* Pods-LambdaTimeline.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/LambdaTimeline/Resources/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = ""; + PRODUCT_BUNDLE_IDENTIFIER = com.LambdaSchool.LambdaTimeline; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -526,17 +396,17 @@ }; 4646378C216FDE4C00E7FF73 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5D2CCD6C68779B0A70AC37FA /* Pods-LambdaTimeline.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/LambdaTimeline/Resources/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = ""; + PRODUCT_BUNDLE_IDENTIFIER = com.LambdaSchool.LambdaTimeline; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/LambdaTimeline/Helpers/Cache.swift b/LambdaTimeline/Helpers/Cache.swift deleted file mode 100644 index 42996051..00000000 --- a/LambdaTimeline/Helpers/Cache.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// Cache.swift -// LambdaTimeline -// -// Created by Spencer Curtis on 10/13/18. -// Copyright © 2018 Lambda School. All rights reserved. -// - -import Foundation - -class Cache { - - func cache(value: Value, for key: Key) { - queue.async { - self.cache[key] = value - } - } - - func value(for key: Key) -> Value? { - return queue.sync { cache[key] } - } - - private var cache = [Key : Value]() - private let queue = DispatchQueue(label: "com.LambdaSchool.LambdaTimeline.CacheQueue") -} diff --git a/LambdaTimeline/Helpers/Extensions/User+DictionaryRepresentation.swift b/LambdaTimeline/Helpers/Extensions/User+DictionaryRepresentation.swift deleted file mode 100644 index 7740ab89..00000000 --- a/LambdaTimeline/Helpers/Extensions/User+DictionaryRepresentation.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// User+DictionaryRepresentation.swift -// LambdaTimeline -// -// Created by Spencer Curtis on 10/12/18. -// Copyright © 2018 Lambda School. All rights reserved. -// - -import Foundation -import FirebaseAuth - -extension User { - - private static let uidKey = "uid" - private static let displayNameKey = "displayName" - - var dictionaryRepresentation: [String: String] { - return [User.uidKey: uid, - User.displayNameKey: displayName ?? "No display name"] - } -} diff --git a/LambdaTimeline/Helpers/FirebaseConvertible.swift b/LambdaTimeline/Helpers/FirebaseConvertible.swift deleted file mode 100644 index a3608644..00000000 --- a/LambdaTimeline/Helpers/FirebaseConvertible.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// FirebaseConvertible.swift -// LambdaTimeline -// -// Created by Spencer Curtis on 10/11/18. -// Copyright © 2018 Lambda School. All rights reserved. -// - -import Foundation - -protocol FirebaseConvertible { - var dictionaryRepresentation: [String: Any] { get } -} diff --git a/LambdaTimeline/Helpers/Networking.swift b/LambdaTimeline/Helpers/Networking.swift deleted file mode 100644 index 90e171bf..00000000 --- a/LambdaTimeline/Helpers/Networking.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// Networking.swift -// LambdaTimeline -// -// Created by Spencer Curtis on 10/12/18. -// Copyright © 2018 Lambda School. All rights reserved. -// - -import Foundation - -enum HTTPMethod: String { - case get = "GET" - case post = "POST" - case put = "PUT" - case patch = "PATCH" - case delete = "DELETE" -} - -enum Networking { - - static func performRequestFor(url: URL, httpMethod: HTTPMethod, parameters: [String: String]? = nil, headers: [String: String]? = nil, body: Data? = nil, completion: @escaping (Data?, URLResponse?, Error?) -> Void) { - - var formattedURL: URL? = url - - if let parameters = parameters { formattedURL = format(url: url, with: parameters) } - - guard let requestURL = formattedURL else { fatalError("requestURL is nil") } - - var request = URLRequest(url: requestURL) - - request.httpMethod = httpMethod.rawValue - request.httpBody = body - - if let headers = headers { - headers.forEach { (key, value) in - request.setValue(value, forHTTPHeaderField: key) - } - } - - URLSession.shared.dataTask(with: request, completionHandler: completion).resume() - } - - static private func format(url: URL, with queryParameters: [String: String]) -> URL? { - - var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) - - urlComponents?.queryItems = queryParameters.compactMap({ URLQueryItem(name: $0.key, value: $0.value) }) - - return urlComponents?.url ?? nil - } -} diff --git a/LambdaTimeline/Helpers/Operations/ConcurrentOperation.swift b/LambdaTimeline/Helpers/Operations/ConcurrentOperation.swift deleted file mode 100644 index 53121118..00000000 --- a/LambdaTimeline/Helpers/Operations/ConcurrentOperation.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// ConcurrentOperation.swift -// LambdaTimeline -// -// Created by Andrew Madsen -// Copyright © 2018 Lambda School. All rights reserved. -// - -import Foundation - -class ConcurrentOperation: Operation { - - // MARK: Types - - enum State: String { - case isReady, isExecuting, isFinished - } - - // MARK: Properties - - private var _state = State.isReady - - private let stateQueue = DispatchQueue(label: "com.LambdaSchool.Astronomy.ConcurrentOperationStateQueue") - var state: State { - get { - var result: State? - let queue = self.stateQueue - queue.sync { - result = _state - } - return result! - } - - set { - let oldValue = state - willChangeValue(forKey: newValue.rawValue) - willChangeValue(forKey: oldValue.rawValue) - - stateQueue.sync { self._state = newValue } - - didChangeValue(forKey: oldValue.rawValue) - didChangeValue(forKey: newValue.rawValue) - } - } - - // MARK: NSOperation - - override dynamic var isReady: Bool { - return super.isReady && state == .isReady - } - - override dynamic var isExecuting: Bool { - return state == .isExecuting - } - - override dynamic var isFinished: Bool { - return state == .isFinished - } - - override var isAsynchronous: Bool { - return true - } - -} diff --git a/LambdaTimeline/Helpers/Operations/FetchMediaOperation.swift b/LambdaTimeline/Helpers/Operations/FetchMediaOperation.swift deleted file mode 100644 index 7632555b..00000000 --- a/LambdaTimeline/Helpers/Operations/FetchMediaOperation.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// FetchMediaOperation.swift -// LambdaTimeline -// -// Created by Spencer Curtis on 10/12/18. -// Copyright © 2018 Lambda School. All rights reserved. -// - -import Foundation - -class FetchMediaOperation: ConcurrentOperation { - - init(post: Post, postController: PostController, session: URLSession = URLSession.shared) { - self.post = post - self.postController = postController - self.session = session - super.init() - } - - override func start() { - state = .isExecuting - - let url = post.mediaURL - - let task = session.dataTask(with: url) { (data, response, error) in - defer { self.state = .isFinished } - if self.isCancelled { return } - if let error = error { - NSLog("Error fetching data for \(self.post): \(error)") - return - } - - guard let data = data else { - NSLog("No data returned from fetch media operation data task.") - return - } - - self.mediaData = data - } - task.resume() - dataTask = task - } - - override func cancel() { - dataTask?.cancel() - super.cancel() - } - - // MARK: Properties - - let post: Post - let postController: PostController - var mediaData: Data? - - private let session: URLSession - - private var dataTask: URLSessionDataTask? - -} diff --git a/LambdaTimeline/Model Controllers/PostController.swift b/LambdaTimeline/Model Controllers/PostController.swift index 29ce3869..3df87148 100644 --- a/LambdaTimeline/Model Controllers/PostController.swift +++ b/LambdaTimeline/Model Controllers/PostController.swift @@ -6,122 +6,31 @@ // Copyright © 2018 Lambda School. All rights reserved. // -import Foundation -import FirebaseAuth -import FirebaseDatabase -import FirebaseStorage +import UIKit class PostController { - func createPost(with title: String, ofType mediaType: MediaType, mediaData: Data, ratio: CGFloat? = nil, completion: @escaping (Bool) -> Void = { _ in }) { - - guard let currentUser = Auth.auth().currentUser, - let author = Author(user: currentUser) else { return } - - store(mediaData: mediaData, mediaType: mediaType) { (mediaURL) in - - guard let mediaURL = mediaURL else { completion(false); return } - - let imagePost = Post(title: title, mediaURL: mediaURL, ratio: ratio, author: author) - - self.postsRef.childByAutoId().setValue(imagePost.dictionaryRepresentation) { (error, ref) in - if let error = error { - NSLog("Error posting image post: \(error)") - completion(false) - } - - completion(true) - } - } + var posts: [Post] = [] + + var currentUser: String? { + UserDefaults.standard.string(forKey: "username") } - func addComment(with text: String, to post: inout Post) { + func createImagePost(with title: String, image: UIImage, ratio: CGFloat?) { - guard let currentUser = Auth.auth().currentUser, - let author = Author(user: currentUser) else { return } + guard let currentUser = currentUser else { return } - let comment = Comment(text: text, author: author) - post.comments.append(comment) - - savePostToFirebase(post) - } - - func observePosts(completion: @escaping (Error?) -> Void) { + let post = Post(title: title, mediaType: .image(image), ratio: ratio, author: currentUser) - postsRef.observe(.value, with: { (snapshot) in - - guard let postDictionaries = snapshot.value as? [String: [String: Any]] else { return } - - var posts: [Post] = [] - - for (key, value) in postDictionaries { - - guard let post = Post(dictionary: value, id: key) else { continue } - - posts.append(post) - } - - self.posts = posts.sorted(by: { $0.timestamp > $1.timestamp }) - - completion(nil) - - }) { (error) in - NSLog("Error fetching posts: \(error)") - } + posts.append(post) } - func savePostToFirebase(_ post: Post, completion: (Error?) -> Void = { _ in }) { - - guard let postID = post.id else { return } + func addComment(with text: String, to post: inout Post) { - let ref = postsRef.child(postID) + guard let currentUser = currentUser else { return } - ref.setValue(post.dictionaryRepresentation) - } + let comment = Comment(text: text, author: currentUser) + post.comments.append(comment) - private func store(mediaData: Data, mediaType: MediaType, completion: @escaping (URL?) -> Void) { - - let mediaID = UUID().uuidString - - let mediaRef = storageRef.child(mediaType.rawValue).child(mediaID) - - let uploadTask = mediaRef.putData(mediaData, metadata: nil) { (metadata, error) in - if let error = error { - NSLog("Error storing media data: \(error)") - completion(nil) - return - } - - if metadata == nil { - NSLog("No metadata returned from upload task.") - completion(nil) - return - } - - mediaRef.downloadURL(completion: { (url, error) in - - if let error = error { - NSLog("Error getting download url of media: \(error)") - } - - guard let url = url else { - NSLog("Download url is nil. Unable to create a Media object") - - completion(nil) - return - } - completion(url) - }) - } - - uploadTask.resume() } - - var posts: [Post] = [] - let currentUser = Auth.auth().currentUser - let postsRef = Database.database().reference().child("posts") - - let storageRef = Storage.storage().reference() - - } diff --git a/LambdaTimeline/Models/Author.swift b/LambdaTimeline/Models/Author.swift deleted file mode 100644 index 4d847ad1..00000000 --- a/LambdaTimeline/Models/Author.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// Author.swift -// LambdaTimeline -// -// Created by Spencer Curtis on 10/12/18. -// Copyright © 2018 Lambda School. All rights reserved. -// - -import Foundation -import FirebaseAuth - -struct Author: FirebaseConvertible, Equatable { - - init?(user: User) { - self.init(dictionary: user.dictionaryRepresentation) - } - - init?(dictionary: [String: Any]) { - guard let uid = dictionary[Author.uidKey] as? String, - let displayName = dictionary[Author.displayNameKey] as? String else { return nil } - - self.uid = uid - self.displayName = displayName - } - - let uid: String - let displayName: String? - - private static let uidKey = "uid" - private static let displayNameKey = "displayName" - - var dictionaryRepresentation: [String: Any] { - return [Author.uidKey: uid, - Author.displayNameKey: displayName ?? "No display name"] - } -} diff --git a/LambdaTimeline/Models/Comment.swift b/LambdaTimeline/Models/Comment.swift index a71ffe4d..a7dad6f5 100644 --- a/LambdaTimeline/Models/Comment.swift +++ b/LambdaTimeline/Models/Comment.swift @@ -7,41 +7,27 @@ // import Foundation -import FirebaseAuth -class Comment: FirebaseConvertible, Equatable { +class Comment: Hashable { static private let textKey = "text" - static private let author = "author" + static private let authorKey = "author" static private let timestampKey = "timestamp" - let text: String - let author: Author + let text: String? + let author: String let timestamp: Date - init(text: String, author: Author, timestamp: Date = Date()) { + init(text: String? = nil, author: String, timestamp: Date = Date()) { self.text = text self.author = author self.timestamp = timestamp } - init?(dictionary: [String : Any]) { - guard let text = dictionary[Comment.textKey] as? String, - let authorDictionary = dictionary[Comment.author] as? [String: Any], - let author = Author(dictionary: authorDictionary), - let timestampTimeInterval = dictionary[Comment.timestampKey] as? TimeInterval else { return nil } - - self.text = text - self.author = author - self.timestamp = Date(timeIntervalSince1970: timestampTimeInterval) - } - - var dictionaryRepresentation: [String: Any] { - return [Comment.textKey: text, - Comment.author: author.dictionaryRepresentation, - Comment.timestampKey: timestamp.timeIntervalSince1970] + func hash(into hasher: inout Hasher) { + hasher.combine(timestamp.hashValue ^ author.hashValue) } - + static func ==(lhs: Comment, rhs: Comment) -> Bool { return lhs.author == rhs.author && lhs.timestamp == rhs.timestamp diff --git a/LambdaTimeline/Models/Post.swift b/LambdaTimeline/Models/Post.swift index ec961e9f..15e1d65c 100644 --- a/LambdaTimeline/Models/Post.swift +++ b/LambdaTimeline/Models/Post.swift @@ -6,74 +6,35 @@ // Copyright © 2018 Lambda School. All rights reserved. // -import Foundation -import FirebaseAuth +import UIKit -enum MediaType: String { - case image +enum MediaType { + case image(UIImage) } -class Post { +class Post: Equatable { - init(title: String, mediaURL: URL, ratio: CGFloat? = nil, author: Author, timestamp: Date = Date()) { - self.mediaURL = mediaURL - self.ratio = ratio - self.mediaType = .image - self.author = author - self.comments = [Comment(text: title, author: author)] - self.timestamp = timestamp - } - - init?(dictionary: [String : Any], id: String) { - guard let mediaURLString = dictionary[Post.mediaKey] as? String, - let mediaURL = URL(string: mediaURLString), - let mediaTypeString = dictionary[Post.mediaTypeKey] as? String, - let mediaType = MediaType(rawValue: mediaTypeString), - let authorDictionary = dictionary[Post.authorKey] as? [String: Any], - let author = Author(dictionary: authorDictionary), - let timestampTimeInterval = dictionary[Post.timestampKey] as? TimeInterval, - let captionDictionaries = dictionary[Post.commentsKey] as? [[String: Any]] else { return nil } - - self.mediaURL = mediaURL - self.mediaType = mediaType - self.ratio = dictionary[Post.ratioKey] as? CGFloat - self.author = author - self.timestamp = Date(timeIntervalSince1970: timestampTimeInterval) - self.comments = captionDictionaries.compactMap({ Comment(dictionary: $0) }) - self.id = id - } - - var dictionaryRepresentation: [String : Any] { - var dict: [String: Any] = [Post.mediaKey: mediaURL.absoluteString, - Post.mediaTypeKey: mediaType.rawValue, - Post.commentsKey: comments.map({ $0.dictionaryRepresentation }), - Post.authorKey: author.dictionaryRepresentation, - Post.timestampKey: timestamp.timeIntervalSince1970] - - guard let ratio = self.ratio else { return dict } - - dict[Post.ratioKey] = ratio - - return dict - } - - var mediaURL: URL let mediaType: MediaType - let author: Author + let author: String let timestamp: Date var comments: [Comment] - var id: String? var ratio: CGFloat? + var id: String? var title: String? { return comments.first?.text } - static private let mediaKey = "media" - static private let ratioKey = "ratio" - static private let mediaTypeKey = "mediaType" - static private let authorKey = "author" - static private let commentsKey = "comments" - static private let timestampKey = "timestamp" - static private let idKey = "id" + init(title: String, mediaType: MediaType, ratio: CGFloat?, author: String, timestamp: Date = Date()) { + self.mediaType = mediaType + self.ratio = ratio + self.author = author + self.comments = [Comment(text: title, author: author)] + self.timestamp = timestamp + self.id = UUID().uuidString + } + + static func ==(lhs: Post, rhs: Post) -> Bool { + return lhs.id == rhs.id + } } diff --git a/LambdaTimeline/Resources/AppDelegate.swift b/LambdaTimeline/Resources/AppDelegate.swift index d889d46c..a44cc8ca 100644 --- a/LambdaTimeline/Resources/AppDelegate.swift +++ b/LambdaTimeline/Resources/AppDelegate.swift @@ -7,40 +7,14 @@ // import UIKit -import Firebase -import GoogleSignIn @UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate { +class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - FirebaseApp.configure() - - let signIn = GIDSignIn.sharedInstance() - signIn?.clientID = FirebaseApp.app()?.options.clientID - - if Auth.auth().currentUser != nil { - let storyboard = UIStoryboard(name: "Main", bundle: nil) - let postsNavigationController = storyboard.instantiateViewController(withIdentifier: "PostsNavigationController") - window?.rootViewController = postsNavigationController - window?.makeKeyAndVisible() - } - return true } - - func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, - withError error: Error!) { - if let error = error { - if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue { - print("Error: The user has not signed in before or they have since signed out.") - } else { - print("\(error.localizedDescription)") - } - return - } - } } diff --git a/LambdaTimeline/Storyboards/Base.lproj/Main.storyboard b/LambdaTimeline/Storyboards/Main.storyboard similarity index 84% rename from LambdaTimeline/Storyboards/Base.lproj/Main.storyboard rename to LambdaTimeline/Storyboards/Main.storyboard index fcec352d..9e2d25d6 100644 --- a/LambdaTimeline/Storyboards/Base.lproj/Main.storyboard +++ b/LambdaTimeline/Storyboards/Main.storyboard @@ -1,9 +1,9 @@ - - + + - + @@ -12,10 +12,10 @@ - - + + - + @@ -24,7 +24,7 @@ - + @@ -88,11 +88,6 @@ - - - - - @@ -106,30 +101,30 @@ - + - + - + - + - + - + - @@ -151,7 +145,7 @@ - + @@ -168,12 +162,12 @@ - + - + - + @@ -195,15 +189,16 @@ - + - + - + + - + @@ -213,59 +208,80 @@ - + - + - - + + + + + + + + + + - + - + - + - + - + @@ -274,16 +290,16 @@ - + - @@ -305,22 +320,22 @@ - - + + - + - + + + + diff --git a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift index 31b43fa3..c108edd7 100644 --- a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift +++ b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift @@ -10,6 +10,16 @@ import UIKit class ImagePostDetailTableViewController: UITableViewController { + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var authorLabel: UILabel! + @IBOutlet weak var imageViewAspectRatioConstraint: NSLayoutConstraint! + @IBOutlet weak var commentButton: UIBarButtonItem! + + var post: Post! + var postController: PostController! + var imageData: Data? + override func viewDidLoad() { super.viewDidLoad() updateViews() @@ -17,15 +27,14 @@ class ImagePostDetailTableViewController: UITableViewController { func updateViews() { - guard let imageData = imageData, - let image = UIImage(data: imageData) else { return } + guard case MediaType.image(let image) = post.mediaType else { return } title = post?.title imageView.image = image titleLabel.text = post.title - authorLabel.text = post.author.displayName + authorLabel.text = post.author } // MARK: - Table view data source @@ -70,19 +79,8 @@ class ImagePostDetailTableViewController: UITableViewController { let comment = post?.comments[indexPath.row + 1] cell.textLabel?.text = comment?.text - cell.detailTextLabel?.text = comment?.author.displayName + cell.detailTextLabel?.text = comment?.author return cell } - - var post: Post! - var postController: PostController! - var imageData: Data? - - - - @IBOutlet weak var imageView: UIImageView! - @IBOutlet weak var titleLabel: UILabel! - @IBOutlet weak var authorLabel: UILabel! - @IBOutlet weak var imageViewAspectRatioConstraint: NSLayoutConstraint! } diff --git a/LambdaTimeline/View Controllers/ImagePostViewController.swift b/LambdaTimeline/View Controllers/ImagePostViewController.swift index 93c4b93e..9cffbbbb 100644 --- a/LambdaTimeline/View Controllers/ImagePostViewController.swift +++ b/LambdaTimeline/View Controllers/ImagePostViewController.swift @@ -11,29 +11,20 @@ import Photos class ImagePostViewController: ShiftableViewController { + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var titleTextField: UITextField! + @IBOutlet weak var chooseImageButton: UIButton! + @IBOutlet weak var imageHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var postButton: UIBarButtonItem! + + var postController: PostController! + var post: Post? + var imageData: Data? + override func viewDidLoad() { super.viewDidLoad() setImageViewHeight(with: 1.0) - - updateViews() - } - - func updateViews() { - - guard let imageData = imageData, - let image = UIImage(data: imageData) else { - title = "New Post" - return - } - - title = post?.title - - setImageViewHeight(with: image.ratio) - - imageView.image = image - - chooseImageButton.setTitle("", for: []) } private func presentImagePickerController() { @@ -44,11 +35,9 @@ class ImagePostViewController: ShiftableViewController { } let imagePicker = UIImagePickerController() - imagePicker.delegate = self - imagePicker.sourceType = .photoLibrary - + present(imagePicker, animated: true, completion: nil) } @@ -56,24 +45,15 @@ class ImagePostViewController: ShiftableViewController { view.endEditing(true) - guard let imageData = imageView.image?.jpegData(compressionQuality: 0.1), + guard let image = imageView.image, let title = titleTextField.text, title != "" else { - presentInformationalAlertController(title: "Uh-oh", message: "Make sure that you add a photo and a caption before posting.") - return - } - - postController.createPost(with: title, ofType: .image, mediaData: imageData, ratio: imageView.image?.ratio) { (success) in - guard success else { - DispatchQueue.main.async { - self.presentInformationalAlertController(title: "Error", message: "Unable to create post. Try again.") - } + presentInformationalAlertController(title: "Uh-oh", message: "Make sure that you add a photo and a caption before posting.") return - } - - DispatchQueue.main.async { - self.navigationController?.popViewController(animated: true) - } } + + postController.createImagePost(with: title, image: image, ratio: image.ratio) + + navigationController?.popViewController(animated: true) } @IBAction func chooseImage(_ sender: Any) { @@ -100,29 +80,22 @@ class ImagePostViewController: ShiftableViewController { self.presentInformationalAlertController(title: "Error", message: "In order to access the photo library, you must allow this application access to it.") case .restricted: self.presentInformationalAlertController(title: "Error", message: "Unable to access the photo library. Your device's restrictions do not allow access.") - - @unknown default: - print("FatalError") + default: + break } presentImagePickerController() } + @IBAction func addFilter(_ sender: Any) { + + } + func setImageViewHeight(with aspectRatio: CGFloat) { imageHeightConstraint.constant = imageView.frame.size.width * aspectRatio view.layoutSubviews() } - - var postController: PostController! - var post: Post? - var imageData: Data? - - @IBOutlet weak var imageView: UIImageView! - @IBOutlet weak var titleTextField: UITextField! - @IBOutlet weak var chooseImageButton: UIButton! - @IBOutlet weak var imageHeightConstraint: NSLayoutConstraint! - @IBOutlet weak var postButton: UIBarButtonItem! } extension ImagePostViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate { diff --git a/LambdaTimeline/View Controllers/PostsCollectionViewController.swift b/LambdaTimeline/View Controllers/PostsCollectionViewController.swift index 7a8191b4..b9ed6b54 100644 --- a/LambdaTimeline/View Controllers/PostsCollectionViewController.swift +++ b/LambdaTimeline/View Controllers/PostsCollectionViewController.swift @@ -7,29 +7,15 @@ // import UIKit -import FirebaseAuth -import FirebaseUI class PostsCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout { - override func viewDidLoad() { - super.viewDidLoad() - - postController.observePosts { (_) in - DispatchQueue.main.async { - self.collectionView.reloadData() - } - } - } + var postController: PostController! - @IBAction func signout(_ sender: Any) { - let firebaseAuth = Auth.auth() - do { - try firebaseAuth.signOut() - } catch let signOutError as NSError { - print ("Error signing out: %@", signOutError) - } - dismiss(animated: true, completion: nil) + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + collectionView.reloadData() } @IBAction func addPost(_ sender: Any) { @@ -51,10 +37,11 @@ class PostsCollectionViewController: UICollectionViewController, UICollectionVie // MARK: UICollectionViewDataSource override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return postController.posts.count + return postController?.posts.count ?? 0 } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let post = postController.posts[indexPath.row] switch post.mediaType { @@ -64,8 +51,6 @@ class PostsCollectionViewController: UICollectionViewController, UICollectionVie cell.post = post - loadImage(for: cell, forItemAt: indexPath) - return cell } } @@ -76,14 +61,9 @@ class PostsCollectionViewController: UICollectionViewController, UICollectionVie let post = postController.posts[indexPath.row] - switch post.mediaType { - - case .image: - - guard let ratio = post.ratio else { return size } - - size.height = size.width * ratio - } + guard let ratio = post.ratio else { return size } + + size.height = size.width * ratio return size } @@ -98,59 +78,7 @@ class PostsCollectionViewController: UICollectionViewController, UICollectionVie } } - override func collectionView(_ collectionView: UICollectionView, didEndDisplayingSupplementaryView view: UICollectionReusableView, forElementOfKind elementKind: String, at indexPath: IndexPath) { - - guard let postID = postController.posts[indexPath.row].id else { return } - operations[postID]?.cancel() - } - func loadImage(for imagePostCell: ImagePostCollectionViewCell, forItemAt indexPath: IndexPath) { - let post = postController.posts[indexPath.row] - - guard let postID = post.id else { return } - - if let mediaData = cache.value(for: postID), - let image = UIImage(data: mediaData) { - imagePostCell.setImage(image) - self.collectionView.reloadItems(at: [indexPath]) - return - } - - let fetchOp = FetchMediaOperation(post: post, postController: postController) - - let cacheOp = BlockOperation { - if let data = fetchOp.mediaData { - self.cache.cache(value: data, for: postID) - DispatchQueue.main.async { - self.collectionView.reloadItems(at: [indexPath]) - } - } - } - - let completionOp = BlockOperation { - defer { self.operations.removeValue(forKey: postID) } - - if let currentIndexPath = self.collectionView?.indexPath(for: imagePostCell), - currentIndexPath != indexPath { - print("Got image for now-reused cell") - return - } - - if let data = fetchOp.mediaData { - imagePostCell.setImage(UIImage(data: data)) - self.collectionView.reloadItems(at: [indexPath]) - } - } - - cacheOp.addDependency(fetchOp) - completionOp.addDependency(fetchOp) - - mediaFetchQueue.addOperation(fetchOp) - mediaFetchQueue.addOperation(cacheOp) - OperationQueue.main.addOperation(completionOp) - - operations[postID] = fetchOp - } // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation @@ -163,17 +91,10 @@ class PostsCollectionViewController: UICollectionViewController, UICollectionVie let destinationVC = segue.destination as? ImagePostDetailTableViewController - guard let indexPath = collectionView.indexPathsForSelectedItems?.first, - let postID = postController.posts[indexPath.row].id else { return } + guard let indexPath = collectionView.indexPathsForSelectedItems?.first else { return } destinationVC?.postController = postController destinationVC?.post = postController.posts[indexPath.row] - destinationVC?.imageData = cache.value(for: postID) } } - - private let postController = PostController() - private var operations = [String : Operation]() - private let mediaFetchQueue = OperationQueue() - private let cache = Cache() } diff --git a/LambdaTimeline/View Controllers/SignInViewController.swift b/LambdaTimeline/View Controllers/SignInViewController.swift index 5b44b832..c81bb748 100644 --- a/LambdaTimeline/View Controllers/SignInViewController.swift +++ b/LambdaTimeline/View Controllers/SignInViewController.swift @@ -7,70 +7,38 @@ // import UIKit -import Firebase -import GoogleSignIn class SignInViewController: UIViewController { - + + @IBOutlet weak var nameTextField: UITextField! + + let postController = PostController() + override func viewDidLoad() { super.viewDidLoad() - GIDSignIn.sharedInstance()?.presentingViewController = self - GIDSignIn.sharedInstance()?.delegate = self - - setUpSignInButton() } - @IBAction func googleSignIn(_ sender: Any) { - GIDSignIn.sharedInstance()?.signIn() + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + segueIfUsernameExists() } -} - -extension SignInViewController: GIDSignInDelegate { - func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) { - - if let error = error { - print("Error signing in with Google: \(error)") - return - } - - guard let authentication = user.authentication else { return } - - let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken) - - Auth.auth().signIn(with: credential) { (authResult, error) in - if let error = error { - print("Error signing in with Google: \(error)") - return - } - - DispatchQueue.main.async { - let storyboard = UIStoryboard(name: "Main", bundle: nil) - let postsNavigationController = storyboard.instantiateViewController(withIdentifier: "PostsNavigationController") - postsNavigationController.modalPresentationStyle = .fullScreen - self.present(postsNavigationController, animated: true, completion: nil) - } - } + + @IBAction func getStarted(_ sender: Any) { + UserDefaults.standard.set(nameTextField.text, forKey: "username") + segueIfUsernameExists() } - func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) { - print("User disconnected") + func segueIfUsernameExists() { + if UserDefaults.standard.string(forKey: "username") != nil { + performSegue(withIdentifier: "ModalPostsVC", sender: nil) + } } - func setUpSignInButton() { - - let button = GIDSignInButton() - - button.translatesAutoresizingMaskIntoConstraints = false - - view.addSubview(button) - - - let buttonCenterXConstraint = button.centerXAnchor.constraint(equalTo: view.centerXAnchor) - let buttonCenterYConstraint = button.centerYAnchor.constraint(equalTo: view.centerYAnchor) - let buttonWidthConstraint = button.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5) - - view.addConstraints([buttonCenterXConstraint, - buttonCenterYConstraint, - buttonWidthConstraint]) + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "ModalPostsVC" { + guard let postsVC = (segue.destination as? UINavigationController)?.topViewController as? PostsCollectionViewController else { return } + + postsVC.postController = postController + } } } diff --git a/LambdaTimeline/Views/ImagePostCollectionViewCell.swift b/LambdaTimeline/Views/ImagePostCollectionViewCell.swift index 3841cf65..f83f73ed 100644 --- a/LambdaTimeline/Views/ImagePostCollectionViewCell.swift +++ b/LambdaTimeline/Views/ImagePostCollectionViewCell.swift @@ -10,10 +10,22 @@ import UIKit class ImagePostCollectionViewCell: UICollectionViewCell { + @IBOutlet weak var imageView: UIImageView! + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var authorLabel: UILabel! + @IBOutlet weak var labelBackgroundView: UIView! + + var post: Post? { + didSet { + updateViews() + } + } + override func layoutSubviews() { super.layoutSubviews() setupLabelBackgroundView() } + override func prepareForReuse() { super.prepareForReuse() @@ -23,32 +35,21 @@ class ImagePostCollectionViewCell: UICollectionViewCell { } func updateViews() { - guard let post = post else { return } - + guard let post = post, + case MediaType.image(let image) = post.mediaType else { return } + titleLabel.text = post.title - authorLabel.text = post.author.displayName + authorLabel.text = post.author + imageView.image = image } - + func setupLabelBackgroundView() { labelBackgroundView.layer.cornerRadius = 8 -// labelBackgroundView.layer.borderColor = UIColor.white.cgColor -// labelBackgroundView.layer.borderWidth = 0.5 labelBackgroundView.clipsToBounds = true } func setImage(_ image: UIImage?) { imageView.image = image } - - var post: Post? { - didSet { - updateViews() - } - } - -@IBOutlet weak var imageView: UIImageView! -@IBOutlet weak var titleLabel: UILabel! -@IBOutlet weak var authorLabel: UILabel! -@IBOutlet weak var labelBackgroundView: UIView! - } + diff --git a/Podfile b/Podfile deleted file mode 100644 index 7d5e126d..00000000 --- a/Podfile +++ /dev/null @@ -1,15 +0,0 @@ -# Uncomment the next line to define a global platform for your project -platform :ios, '13.0' - -target 'LambdaTimeline' do - # Comment the next line if you're not using Swift and don't want to use dynamic frameworks - use_frameworks! - - # Pods for LambdaTimeline - pod 'Firebase/Core' - pod 'Firebase/Database' - pod 'Firebase/Storage' - pod 'Firebase/Auth' - pod 'FirebaseUI/Google' - pod 'GoogleSignIn' -end diff --git a/Podfile.lock b/Podfile.lock deleted file mode 100644 index 9d835784..00000000 --- a/Podfile.lock +++ /dev/null @@ -1,174 +0,0 @@ -PODS: - - AppAuth (1.3.0): - - AppAuth/Core (= 1.3.0) - - AppAuth/ExternalUserAgent (= 1.3.0) - - AppAuth/Core (1.3.0) - - AppAuth/ExternalUserAgent (1.3.0) - - Firebase/Auth (6.19.0): - - Firebase/CoreOnly - - FirebaseAuth (~> 6.4.3) - - Firebase/Core (6.19.0): - - Firebase/CoreOnly - - FirebaseAnalytics (= 6.3.1) - - Firebase/CoreOnly (6.19.0): - - FirebaseCore (= 6.6.4) - - Firebase/Database (6.19.0): - - Firebase/CoreOnly - - FirebaseDatabase (~> 6.1.4) - - Firebase/Storage (6.19.0): - - Firebase/CoreOnly - - FirebaseStorage (~> 3.6.0) - - FirebaseAnalytics (6.3.1): - - FirebaseCore (~> 6.6) - - FirebaseInstallations (~> 1.1) - - GoogleAppMeasurement (= 6.3.1) - - GoogleUtilities/AppDelegateSwizzler (~> 6.0) - - GoogleUtilities/MethodSwizzler (~> 6.0) - - GoogleUtilities/Network (~> 6.0) - - "GoogleUtilities/NSData+zlib (~> 6.0)" - - nanopb (= 0.3.9011) - - FirebaseAuth (6.4.3): - - FirebaseAuthInterop (~> 1.0) - - FirebaseCore (~> 6.6) - - GoogleUtilities/AppDelegateSwizzler (~> 6.5) - - GoogleUtilities/Environment (~> 6.5) - - GTMSessionFetcher/Core (~> 1.1) - - FirebaseAuthInterop (1.1.0) - - FirebaseCore (6.6.4): - - FirebaseCoreDiagnostics (~> 1.2) - - FirebaseCoreDiagnosticsInterop (~> 1.2) - - GoogleUtilities/Environment (~> 6.5) - - GoogleUtilities/Logger (~> 6.5) - - FirebaseCoreDiagnostics (1.2.2): - - FirebaseCoreDiagnosticsInterop (~> 1.2) - - GoogleDataTransportCCTSupport (~> 2.0) - - GoogleUtilities/Environment (~> 6.5) - - GoogleUtilities/Logger (~> 6.5) - - nanopb (~> 0.3.901) - - FirebaseCoreDiagnosticsInterop (1.2.0) - - FirebaseDatabase (6.1.4): - - FirebaseAuthInterop (~> 1.0) - - FirebaseCore (~> 6.0) - - leveldb-library (~> 1.22) - - FirebaseInstallations (1.1.0): - - FirebaseCore (~> 6.6) - - GoogleUtilities/UserDefaults (~> 6.5) - - PromisesObjC (~> 1.2) - - FirebaseStorage (3.6.0): - - FirebaseAuthInterop (~> 1.1) - - FirebaseCore (~> 6.6) - - GTMSessionFetcher/Core (~> 1.1) - - FirebaseUI/Auth (8.4.2): - - Firebase/Auth (~> 6.0) - - GoogleUtilities/UserDefaults - - FirebaseUI/Google (8.4.2): - - FirebaseUI/Auth - - GoogleSignIn (~> 5.0) - - GoogleAppMeasurement (6.3.1): - - GoogleUtilities/AppDelegateSwizzler (~> 6.0) - - GoogleUtilities/MethodSwizzler (~> 6.0) - - GoogleUtilities/Network (~> 6.0) - - "GoogleUtilities/NSData+zlib (~> 6.0)" - - nanopb (= 0.3.9011) - - GoogleDataTransport (5.0.0) - - GoogleDataTransportCCTSupport (2.0.0): - - GoogleDataTransport (~> 5.0) - - nanopb (~> 0.3.901) - - GoogleSignIn (5.0.2): - - AppAuth (~> 1.2) - - GTMAppAuth (~> 1.0) - - GTMSessionFetcher/Core (~> 1.1) - - GoogleUtilities/AppDelegateSwizzler (6.5.1): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Environment (6.5.1) - - GoogleUtilities/Logger (6.5.1): - - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (6.5.1): - - GoogleUtilities/Logger - - GoogleUtilities/Network (6.5.1): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (6.5.1)" - - GoogleUtilities/Reachability (6.5.1): - - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (6.5.1): - - GoogleUtilities/Logger - - GTMAppAuth (1.0.0): - - AppAuth/Core (~> 1.0) - - GTMSessionFetcher (~> 1.1) - - GTMSessionFetcher (1.3.1): - - GTMSessionFetcher/Full (= 1.3.1) - - GTMSessionFetcher/Core (1.3.1) - - GTMSessionFetcher/Full (1.3.1): - - GTMSessionFetcher/Core (= 1.3.1) - - leveldb-library (1.22) - - nanopb (0.3.9011): - - nanopb/decode (= 0.3.9011) - - nanopb/encode (= 0.3.9011) - - nanopb/decode (0.3.9011) - - nanopb/encode (0.3.9011) - - PromisesObjC (1.2.8) - -DEPENDENCIES: - - Firebase/Auth - - Firebase/Core - - Firebase/Database - - Firebase/Storage - - FirebaseUI/Google - - GoogleSignIn - -SPEC REPOS: - trunk: - - AppAuth - - Firebase - - FirebaseAnalytics - - FirebaseAuth - - FirebaseAuthInterop - - FirebaseCore - - FirebaseCoreDiagnostics - - FirebaseCoreDiagnosticsInterop - - FirebaseDatabase - - FirebaseInstallations - - FirebaseStorage - - FirebaseUI - - GoogleAppMeasurement - - GoogleDataTransport - - GoogleDataTransportCCTSupport - - GoogleSignIn - - GoogleUtilities - - GTMAppAuth - - GTMSessionFetcher - - leveldb-library - - nanopb - - PromisesObjC - -SPEC CHECKSUMS: - AppAuth: 73574f3013a1e65b9601a3ddc8b3158cce68c09d - Firebase: d55ddb0e0bb3207166cddc028647833d8a1b5b6f - FirebaseAnalytics: 572e467f3d977825266e8ccd52674aa3e6f47eac - FirebaseAuth: 5ce2b03a3d7fe56b7a6e4c5ec7ff1522890b1d6f - FirebaseAuthInterop: a0f37ae05833af156e72028f648d313f7e7592e9 - FirebaseCore: ed0a24c758a57c2b88c5efa8e6a8195e868af589 - FirebaseCoreDiagnostics: e9b4cd8ba60dee0f2d13347332e4b7898cca5b61 - FirebaseCoreDiagnosticsInterop: 296e2c5f5314500a850ad0b83e9e7c10b011a850 - FirebaseDatabase: 0144e0706a4761f1b0e8679572eba8095ddb59be - FirebaseInstallations: 575cd32f2aec0feeb0e44f5d0110a09e5e60b47b - FirebaseStorage: b43ee271294227e1a3225544b073f3b49b427f46 - FirebaseUI: e57e9b9c4340631151fbe67a14206d23d0974f37 - GoogleAppMeasurement: c29d405ff76e18551b5d158eaba6753fda8c7542 - GoogleDataTransport: a857c6a002d201b524dd4bc2ed7e7355ed07e785 - GoogleDataTransportCCTSupport: 32f75fbe904c82772fcbb6b6bd4525bfb6f2a862 - GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213 - GoogleUtilities: 06eb53bb579efe7099152735900dd04bf09e7275 - GTMAppAuth: 4deac854479704f348309e7b66189e604cf5e01e - GTMSessionFetcher: cea130bbfe5a7edc8d06d3f0d17288c32ffe9925 - leveldb-library: 55d93ee664b4007aac644a782d11da33fba316f7 - nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd - PromisesObjC: c119f3cd559f50b7ae681fa59dc1acd19173b7e6 - -PODFILE CHECKSUM: 28424f1a99ace6e65529f57867177322416678fa - -COCOAPODS: 1.9.1 From 80ee64da7fc5a2fe61ec2cccf49e68dc86a39fa3 Mon Sep 17 00:00:00 2001 From: Spencer Curtis Date: Tue, 1 Sep 2020 17:29:24 -0600 Subject: [PATCH 02/20] Update README to reflect removal of Firebase --- README.md | 52 +++++----------------------------------------------- 1 file changed, 5 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index adfee3d4..d294b91f 100644 --- a/README.md +++ b/README.md @@ -23,57 +23,15 @@ Create a new Xcode project called `ImageFilterEditor` to use as a playground for 2. Create an `ImagePostViewController` that will get a starting image and filter it. 1. Add whatever UI elements you want to control the filters with the selected image. 2. For filters that require other parameters use a slider, UITextField, segmented control, or UIPanGestureRecognizer. -3. Ensure that the controls to add your filters, adjust them, etc. are only available to the user at the apropriate time. +3. Ensure that the controls to add your filters, adjust them, etc. are only available to the user at the appropriate time. 1. For example, you shouldn't let the user add a filter if they haven't selected an image yet. And it doesn't make sense to show the adjustment UI if they selected a filter that has no adjustment. 4. You can use a Collection or Table View to select filters with additional detail screens to fine tune amounts of filters (i.e.: Instagram or Apple Photo) -### Part 2 - Firebase Setup +### Part 2: Feature Integration -Though you have a base project, you will need to modify it. - -**Cocoapods** - -To begin, run `pod install` after navigating to the repo in terminal. (If you have issues with [Cocoapods, Homebrew, Ruby, follow this guide](Cocopods-Homebrew-and-Ruby-Install-Guide.md)) Work out of the generated `.xcworkspace` - - pod install - -NOTE: If you run `pod update` there may be breaking changes from newer versions of Firebase. The current Podfile.lock versions work with Swift 5.1 and Xcode 11. - -**Firebase Setup** - -[Watch the iOS Firebase Authentication Video](https://youtu.be/vGeuZtHmcMM) to follow these steps -[![Watch the iOS Firebase Authentication Video](https://tk-assets.lambdaschool.com/a8f55011-48ef-4eb9-af2b-17a7b92fae64_FirebaseVideo.png)](https://youtu.be/vGeuZtHmcMM) - -1. Create a new Firebase project (or use an existing one). -2. Change the project's bundle identifier to your own bundle identifier (e.g. `com.JohnSmith.LambdaTimeline`) -3. In the "Project Overview" in your Firebase project, you will need to add your app as we are using the Firebase SDK in our Xcode project. You will need to add the "GoogleService-Info.plist" file that will be given to you when you add the app. -4. Please refer to this page: https://firebase.google.com/docs/auth/ios/firebaseui and follow the steps under the “Set up sign-in methods”. - 1. You will only need to do the two steps under the [Google section](https://firebase.google.com/docs/auth/ios/firebaseui#google). - 2. The starter project will have a URL type already. You just need to paste the right URL scheme in. - 3. You can find the URL Type in your project file in the `Project Settings > Info > URL Types (expand) > URL Schemes` -5. In the Firebase project's database, change the rules to: -``` JSON -{ - "rules": { - ".read": "auth != null", - ".write": "auth != null" - } -} -``` -This will allow only users of the app who are authenticated to access the database. (Authentication is already taken care of in the starter project) - -6. In the left pane of your Firebase project under "Develop", click the Storage item. Click the "Get Started" button and it will pull up a modal window about security rules. Simply click "Got it". It will set Storage's rules to allow access to any authenticated user, which works great for our uses. - -Firebase Storage is essentially a Google Drive for data in your Firebase. It makes sense to use Storage in this application as we will be storing images, audio, and video data. If you're curious as to how Database and Storage interact, feel free to read Firebase's Storage documentation and look at the code in the base project. Particularly in the `Post`, `Media` and `PostController` objects. (Don't feel like you have to, however) - -At this point, run the app on your simulator or physical device in order to make sure that you've set up your Firebase Project correctly. If set up correctly, you should be able to create posts, comment on them, and have them get sent to Firebase. You should also be able to re-run the app and have the posts and comments get fetched correctly. If this does not work, the likely scenario is that you've not set up your Firebase project correctly. If you can't figure out what's wrong, please reach out to your TL. - -*Note: If you have a free Apple Developer account you may need to reuse your Bundle ID from a previous project to run on a real device (Apple limits you to three unique identifiers).* - -### Part 3: Feature Integration - -1. Integrate your `ImagePostViewController` into the Lambda Timeline Firebase project. -2. You should be able to create a new post, select a photo, edit the photo, and post it to your Firebase server. +1. Integrate your `ImagePostViewController` into the Lambda Timeline project. +2. You should be able to create a new post, select a photo, edit the photo, and create an image post. +3. Be sure that you are able to add comments to posts. ## Go Further From 08a66c0ca1f498f1aaee51a2fd7d31862e87f605 Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Wed, 2 Sep 2020 19:20:05 -0700 Subject: [PATCH 03/20] Created ImageFilterEditor Project. Added Filters and set up UI. Did not for repo leading to this being a larger commit. --- .../project.pbxproj | 341 ++++++++++++++++++ .../ImageFilterEditor/AppDelegate.swift | 37 ++ .../AppIcon.appiconset/Contents.json | 98 +++++ .../Assets.xcassets/Contents.json | 6 + .../spirited.imageset/Contents.json | 21 ++ .../spirited.imageset/spirited.jpg | Bin 0 -> 190123 bytes .../Base.lproj/LaunchScreen.storyboard | 25 ++ .../Base.lproj/Main.storyboard | 134 +++++++ .../ImageFilterEditor/Filters.swift | 22 ++ .../ImageFilterEditor/Info.plist | 64 ++++ .../ImageFilterEditor/SceneDelegate.swift | 53 +++ 11 files changed, 801 insertions(+) create mode 100644 ImageFilterEditor/ImageFilterEditor.xcodeproj/project.pbxproj create mode 100644 ImageFilterEditor/ImageFilterEditor/AppDelegate.swift create mode 100644 ImageFilterEditor/ImageFilterEditor/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 ImageFilterEditor/ImageFilterEditor/Assets.xcassets/Contents.json create mode 100644 ImageFilterEditor/ImageFilterEditor/Assets.xcassets/spirited.imageset/Contents.json create mode 100644 ImageFilterEditor/ImageFilterEditor/Assets.xcassets/spirited.imageset/spirited.jpg create mode 100644 ImageFilterEditor/ImageFilterEditor/Base.lproj/LaunchScreen.storyboard create mode 100644 ImageFilterEditor/ImageFilterEditor/Base.lproj/Main.storyboard create mode 100644 ImageFilterEditor/ImageFilterEditor/Filters.swift create mode 100644 ImageFilterEditor/ImageFilterEditor/Info.plist create mode 100644 ImageFilterEditor/ImageFilterEditor/SceneDelegate.swift diff --git a/ImageFilterEditor/ImageFilterEditor.xcodeproj/project.pbxproj b/ImageFilterEditor/ImageFilterEditor.xcodeproj/project.pbxproj new file mode 100644 index 00000000..79441c24 --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor.xcodeproj/project.pbxproj @@ -0,0 +1,341 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 0B8FFC90250083F600C2AFE9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8FFC8F250083F600C2AFE9 /* AppDelegate.swift */; }; + 0B8FFC92250083F600C2AFE9 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8FFC91250083F600C2AFE9 /* SceneDelegate.swift */; }; + 0B8FFC97250083F600C2AFE9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0B8FFC95250083F600C2AFE9 /* Main.storyboard */; }; + 0B8FFC99250083F800C2AFE9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0B8FFC98250083F800C2AFE9 /* Assets.xcassets */; }; + 0B8FFC9C250083F800C2AFE9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0B8FFC9A250083F800C2AFE9 /* LaunchScreen.storyboard */; }; + 0B8FFCA4250084D100C2AFE9 /* Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8FFCA3250084D100C2AFE9 /* Filters.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0B8FFC8C250083F600C2AFE9 /* ImageFilterEditor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ImageFilterEditor.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0B8FFC8F250083F600C2AFE9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 0B8FFC91250083F600C2AFE9 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 0B8FFC96250083F600C2AFE9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 0B8FFC98250083F800C2AFE9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 0B8FFC9B250083F800C2AFE9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 0B8FFC9D250083F800C2AFE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0B8FFCA3250084D100C2AFE9 /* Filters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filters.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0B8FFC89250083F600C2AFE9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0B8FFC83250083F600C2AFE9 = { + isa = PBXGroup; + children = ( + 0B8FFC8E250083F600C2AFE9 /* ImageFilterEditor */, + 0B8FFC8D250083F600C2AFE9 /* Products */, + ); + sourceTree = ""; + }; + 0B8FFC8D250083F600C2AFE9 /* Products */ = { + isa = PBXGroup; + children = ( + 0B8FFC8C250083F600C2AFE9 /* ImageFilterEditor.app */, + ); + name = Products; + sourceTree = ""; + }; + 0B8FFC8E250083F600C2AFE9 /* ImageFilterEditor */ = { + isa = PBXGroup; + children = ( + 0B8FFC8F250083F600C2AFE9 /* AppDelegate.swift */, + 0B8FFC91250083F600C2AFE9 /* SceneDelegate.swift */, + 0B8FFC95250083F600C2AFE9 /* Main.storyboard */, + 0B8FFC98250083F800C2AFE9 /* Assets.xcassets */, + 0B8FFC9A250083F800C2AFE9 /* LaunchScreen.storyboard */, + 0B8FFC9D250083F800C2AFE9 /* Info.plist */, + 0B8FFCA3250084D100C2AFE9 /* Filters.swift */, + ); + path = ImageFilterEditor; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0B8FFC8B250083F600C2AFE9 /* ImageFilterEditor */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0B8FFCA0250083F800C2AFE9 /* Build configuration list for PBXNativeTarget "ImageFilterEditor" */; + buildPhases = ( + 0B8FFC88250083F600C2AFE9 /* Sources */, + 0B8FFC89250083F600C2AFE9 /* Frameworks */, + 0B8FFC8A250083F600C2AFE9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ImageFilterEditor; + productName = ImageFilterEditor; + productReference = 0B8FFC8C250083F600C2AFE9 /* ImageFilterEditor.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0B8FFC84250083F600C2AFE9 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1160; + LastUpgradeCheck = 1160; + ORGANIZATIONNAME = "Clayton Watkins"; + TargetAttributes = { + 0B8FFC8B250083F600C2AFE9 = { + CreatedOnToolsVersion = 11.6; + }; + }; + }; + buildConfigurationList = 0B8FFC87250083F600C2AFE9 /* Build configuration list for PBXProject "ImageFilterEditor" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0B8FFC83250083F600C2AFE9; + productRefGroup = 0B8FFC8D250083F600C2AFE9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0B8FFC8B250083F600C2AFE9 /* ImageFilterEditor */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0B8FFC8A250083F600C2AFE9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B8FFC9C250083F800C2AFE9 /* LaunchScreen.storyboard in Resources */, + 0B8FFC99250083F800C2AFE9 /* Assets.xcassets in Resources */, + 0B8FFC97250083F600C2AFE9 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0B8FFC88250083F600C2AFE9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B8FFCA4250084D100C2AFE9 /* Filters.swift in Sources */, + 0B8FFC90250083F600C2AFE9 /* AppDelegate.swift in Sources */, + 0B8FFC92250083F600C2AFE9 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 0B8FFC95250083F600C2AFE9 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0B8FFC96250083F600C2AFE9 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 0B8FFC9A250083F800C2AFE9 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0B8FFC9B250083F800C2AFE9 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 0B8FFC9E250083F800C2AFE9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 0B8FFC9F250083F800C2AFE9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0B8FFCA1250083F800C2AFE9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = ImageFilterEditor/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.claytonwatkins.ImageFilterEditor; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0B8FFCA2250083F800C2AFE9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = ImageFilterEditor/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.claytonwatkins.ImageFilterEditor; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0B8FFC87250083F600C2AFE9 /* Build configuration list for PBXProject "ImageFilterEditor" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0B8FFC9E250083F800C2AFE9 /* Debug */, + 0B8FFC9F250083F800C2AFE9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0B8FFCA0250083F800C2AFE9 /* Build configuration list for PBXNativeTarget "ImageFilterEditor" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0B8FFCA1250083F800C2AFE9 /* Debug */, + 0B8FFCA2250083F800C2AFE9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0B8FFC84250083F600C2AFE9 /* Project object */; +} diff --git a/ImageFilterEditor/ImageFilterEditor/AppDelegate.swift b/ImageFilterEditor/ImageFilterEditor/AppDelegate.swift new file mode 100644 index 00000000..cd2fa633 --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/AppDelegate.swift @@ -0,0 +1,37 @@ +// +// AppDelegate.swift +// ImageFilterEditor +// +// Created by Clayton Watkins on 9/2/20. +// Copyright © 2020 Clayton Watkins. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/AppIcon.appiconset/Contents.json b/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..9221b9bb --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/Contents.json b/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/spirited.imageset/Contents.json b/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/spirited.imageset/Contents.json new file mode 100644 index 00000000..3bdb8cbf --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/spirited.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "spirited.jpg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/spirited.imageset/spirited.jpg b/ImageFilterEditor/ImageFilterEditor/Assets.xcassets/spirited.imageset/spirited.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f774df89b82ac1cf9fc22eb84337d306edbdd427 GIT binary patch literal 190123 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�|e1P2A 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 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageFilterEditor/ImageFilterEditor/Base.lproj/Main.storyboard b/ImageFilterEditor/ImageFilterEditor/Base.lproj/Main.storyboard new file mode 100644 index 00000000..819dfaa5 --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/Base.lproj/Main.storyboard @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageFilterEditor/ImageFilterEditor/Filters.swift b/ImageFilterEditor/ImageFilterEditor/Filters.swift new file mode 100644 index 00000000..74c09d81 --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/Filters.swift @@ -0,0 +1,22 @@ +// +// Filters.swift +// ImageFilterEditor +// +// Created by Clayton Watkins on 9/2/20. +// Copyright © 2020 Clayton Watkins. All rights reserved. +// + +import Foundation +import CoreImage +import CoreImage.CIFilterBuiltins + + +class Filters { + + // MARK: - Properties + let blurFilter = CIFilter.gaussianBlur() + let falseColorFilter = CIFilter.falseColor() + let vignetteFilter = CIFilter.vignette() + let whitePointFilter = CIFilter.whitePointAdjust() + let monoChromaticFilter = CIFilter.photoEffectMono() +} diff --git a/ImageFilterEditor/ImageFilterEditor/Info.plist b/ImageFilterEditor/ImageFilterEditor/Info.plist new file mode 100644 index 00000000..2a3483c0 --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ImageFilterEditor/ImageFilterEditor/SceneDelegate.swift b/ImageFilterEditor/ImageFilterEditor/SceneDelegate.swift new file mode 100644 index 00000000..e21f578e --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/SceneDelegate.swift @@ -0,0 +1,53 @@ +// +// SceneDelegate.swift +// ImageFilterEditor +// +// Created by Clayton Watkins on 9/2/20. +// Copyright © 2020 Clayton Watkins. All rights reserved. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + From c6b478f84a3354dfbbcbb8d5a218353ea212bfe1 Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Wed, 2 Sep 2020 19:37:45 -0700 Subject: [PATCH 04/20] Added UIImage+Scaling --- .../project.pbxproj | 8 ++++ .../Base.lproj/Main.storyboard | 12 ++++-- .../ImageFilterEditor/Filters.swift | 4 ++ .../ImagePostViewController.swift | 19 ++++++++++ .../ImageFilterEditor/UIImage+Scaling.swift | 38 +++++++++++++++++++ 5 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 ImageFilterEditor/ImageFilterEditor/ImagePostViewController.swift create mode 100644 ImageFilterEditor/ImageFilterEditor/UIImage+Scaling.swift diff --git a/ImageFilterEditor/ImageFilterEditor.xcodeproj/project.pbxproj b/ImageFilterEditor/ImageFilterEditor.xcodeproj/project.pbxproj index 79441c24..ac115c5a 100644 --- a/ImageFilterEditor/ImageFilterEditor.xcodeproj/project.pbxproj +++ b/ImageFilterEditor/ImageFilterEditor.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 0B8FFC99250083F800C2AFE9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0B8FFC98250083F800C2AFE9 /* Assets.xcassets */; }; 0B8FFC9C250083F800C2AFE9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0B8FFC9A250083F800C2AFE9 /* LaunchScreen.storyboard */; }; 0B8FFCA4250084D100C2AFE9 /* Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8FFCA3250084D100C2AFE9 /* Filters.swift */; }; + 0BFB3BC325008A7F0027F38F /* ImagePostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BFB3BC225008A7F0027F38F /* ImagePostViewController.swift */; }; + 0BFB3BC525008E4E0027F38F /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BFB3BC425008E4E0027F38F /* UIImage+Scaling.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -24,6 +26,8 @@ 0B8FFC9B250083F800C2AFE9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 0B8FFC9D250083F800C2AFE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0B8FFCA3250084D100C2AFE9 /* Filters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filters.swift; sourceTree = ""; }; + 0BFB3BC225008A7F0027F38F /* ImagePostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePostViewController.swift; sourceTree = ""; }; + 0BFB3BC425008E4E0027F38F /* UIImage+Scaling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Scaling.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -63,6 +67,8 @@ 0B8FFC9A250083F800C2AFE9 /* LaunchScreen.storyboard */, 0B8FFC9D250083F800C2AFE9 /* Info.plist */, 0B8FFCA3250084D100C2AFE9 /* Filters.swift */, + 0BFB3BC225008A7F0027F38F /* ImagePostViewController.swift */, + 0BFB3BC425008E4E0027F38F /* UIImage+Scaling.swift */, ); path = ImageFilterEditor; sourceTree = ""; @@ -138,6 +144,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0BFB3BC325008A7F0027F38F /* ImagePostViewController.swift in Sources */, + 0BFB3BC525008E4E0027F38F /* UIImage+Scaling.swift in Sources */, 0B8FFCA4250084D100C2AFE9 /* Filters.swift in Sources */, 0B8FFC90250083F600C2AFE9 /* AppDelegate.swift in Sources */, 0B8FFC92250083F600C2AFE9 /* SceneDelegate.swift in Sources */, diff --git a/ImageFilterEditor/ImageFilterEditor/Base.lproj/Main.storyboard b/ImageFilterEditor/ImageFilterEditor/Base.lproj/Main.storyboard index 819dfaa5..51214384 100644 --- a/ImageFilterEditor/ImageFilterEditor/Base.lproj/Main.storyboard +++ b/ImageFilterEditor/ImageFilterEditor/Base.lproj/Main.storyboard @@ -7,10 +7,10 @@ - + - + @@ -98,22 +98,28 @@ + + - + + diff --git a/ImageFilterEditor/ImageFilterEditor/Filters.swift b/ImageFilterEditor/ImageFilterEditor/Filters.swift index 74c09d81..ada5f7c1 100644 --- a/ImageFilterEditor/ImageFilterEditor/Filters.swift +++ b/ImageFilterEditor/ImageFilterEditor/Filters.swift @@ -19,4 +19,8 @@ class Filters { let vignetteFilter = CIFilter.vignette() let whitePointFilter = CIFilter.whitePointAdjust() let monoChromaticFilter = CIFilter.photoEffectMono() + + + + } diff --git a/ImageFilterEditor/ImageFilterEditor/ImagePostViewController.swift b/ImageFilterEditor/ImageFilterEditor/ImagePostViewController.swift new file mode 100644 index 00000000..c18a25ae --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/ImagePostViewController.swift @@ -0,0 +1,19 @@ +// +// ImagePostViewController.swift +// ImageFilterEditor +// +// Created by Clayton Watkins on 9/2/20. +// Copyright © 2020 Clayton Watkins. All rights reserved. +// + +import UIKit + +class ImagePostViewController: UIViewController { + + + // MARK: - Lifecycle + override func viewDidLoad() { + super.viewDidLoad() + } + +} diff --git a/ImageFilterEditor/ImageFilterEditor/UIImage+Scaling.swift b/ImageFilterEditor/ImageFilterEditor/UIImage+Scaling.swift new file mode 100644 index 00000000..40e02ffe --- /dev/null +++ b/ImageFilterEditor/ImageFilterEditor/UIImage+Scaling.swift @@ -0,0 +1,38 @@ +// +// UIImage+Scaling.swift +// ImageFilterEditor +// +// Created by Clayton Watkins on 9/2/20. +// Copyright © 2020 Clayton Watkins. All rights reserved. +// + +import UIKit + +extension UIImage { + + /// Resize the image to a max dimension from size parameter + func imageByScaling(toSize size: CGSize) -> UIImage? { + guard size.width > 0 && size.height > 0 else { return nil } + + let originalAspectRatio = self.size.width/self.size.height + var correctedSize = size + + if correctedSize.width > correctedSize.width*originalAspectRatio { + correctedSize.width = correctedSize.width*originalAspectRatio + } else { + correctedSize.height = correctedSize.height/originalAspectRatio + } + + return UIGraphicsImageRenderer(size: correctedSize, format: imageRendererFormat).image { context in + draw(in: CGRect(origin: .zero, size: correctedSize)) + } + } + + /// Renders the image if the pixel data was rotated due to orientation of camera + var flattened: UIImage { + if imageOrientation == .up { return self } + return UIGraphicsImageRenderer(size: size, format: imageRendererFormat).image { context in + draw(at: .zero) + } + } +} From 195ff57dea77f498b7428ea9438fdb7f05774e6a Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Thu, 3 Sep 2020 12:39:42 -0700 Subject: [PATCH 05/20] Added UIImage+Scaling helper extension --- LambdaTimeline.xcodeproj/project.pbxproj | 4 ++ LambdaTimeline/Helpers/UIImage+Scaling.swift | 39 ++++++++++++ LambdaTimeline/Storyboards/Main.storyboard | 61 +++++++++---------- .../ImagePostViewController.swift | 13 ++-- 4 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 LambdaTimeline/Helpers/UIImage+Scaling.swift diff --git a/LambdaTimeline.xcodeproj/project.pbxproj b/LambdaTimeline.xcodeproj/project.pbxproj index b2af5414..dd9a3ef2 100644 --- a/LambdaTimeline.xcodeproj/project.pbxproj +++ b/LambdaTimeline.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0B43785B25017D92009599C4 /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B43785A25017D92009599C4 /* UIImage+Scaling.swift */; }; 4646377C216FDE4B00E7FF73 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4646377B216FDE4B00E7FF73 /* AppDelegate.swift */; }; 46463783216FDE4C00E7FF73 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 46463782216FDE4C00E7FF73 /* Assets.xcassets */; }; 46463786216FDE4C00E7FF73 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46463784216FDE4C00E7FF73 /* LaunchScreen.storyboard */; }; @@ -25,6 +26,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 0B43785A25017D92009599C4 /* UIImage+Scaling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Scaling.swift"; sourceTree = ""; }; 46463778216FDE4B00E7FF73 /* LambdaTimeline.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LambdaTimeline.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4646377B216FDE4B00E7FF73 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 46463782216FDE4C00E7FF73 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -145,6 +147,7 @@ children = ( 46D571F62173D6D200E7FF73 /* Extensions */, 46CFE6F82170862C00E7FF73 /* ShiftableViewController.swift */, + 0B43785A25017D92009599C4 /* UIImage+Scaling.swift */, ); path = Helpers; sourceTree = ""; @@ -234,6 +237,7 @@ 46CFE6F92170862C00E7FF73 /* ShiftableViewController.swift in Sources */, 4646377C216FDE4B00E7FF73 /* AppDelegate.swift in Sources */, 46CFE6F521707D0000E7FF73 /* ImagePostViewController.swift in Sources */, + 0B43785B25017D92009599C4 /* UIImage+Scaling.swift in Sources */, 46463790216FFD1B00E7FF73 /* Post.swift in Sources */, 46D571F82173FC2700E7FF73 /* ImagePostDetailTableViewController.swift in Sources */, 46CFE7032171572600E7FF73 /* ImagePostCollectionViewCell.swift in Sources */, diff --git a/LambdaTimeline/Helpers/UIImage+Scaling.swift b/LambdaTimeline/Helpers/UIImage+Scaling.swift new file mode 100644 index 00000000..27c55318 --- /dev/null +++ b/LambdaTimeline/Helpers/UIImage+Scaling.swift @@ -0,0 +1,39 @@ +// +// UIImage+Scaling.swift +// LambdaTimeline +// +// Created by Clayton Watkins on 9/3/20. +// Copyright © 2020 Lambda School. All rights reserved. +// + +import Foundation +import UIKit + +extension UIImage { + + /// Resize the image to a max dimension from size parameter + func imageByScaling(toSize size: CGSize) -> UIImage? { + guard size.width > 0 && size.height > 0 else { return nil } + + let originalAspectRatio = self.size.width/self.size.height + var correctedSize = size + + if correctedSize.width > correctedSize.width*originalAspectRatio { + correctedSize.width = correctedSize.width*originalAspectRatio + } else { + correctedSize.height = correctedSize.height/originalAspectRatio + } + + return UIGraphicsImageRenderer(size: correctedSize, format: imageRendererFormat).image { context in + draw(in: CGRect(origin: .zero, size: correctedSize)) + } + } + + /// Renders the image if the pixel data was rotated due to orientation of camera + var flattened: UIImage { + if imageOrientation == .up { return self } + return UIGraphicsImageRenderer(size: size, format: imageRendererFormat).image { context in + draw(at: .zero) + } + } +} diff --git a/LambdaTimeline/Storyboards/Main.storyboard b/LambdaTimeline/Storyboards/Main.storyboard index 9e2d25d6..10070f8f 100644 --- a/LambdaTimeline/Storyboards/Main.storyboard +++ b/LambdaTimeline/Storyboards/Main.storyboard @@ -1,8 +1,7 @@ - + - @@ -13,7 +12,7 @@ - + @@ -24,7 +23,7 @@ - + @@ -34,19 +33,19 @@ - + - + - + - + - + - + + + + @@ -44,8 +47,11 @@ - + + + + @@ -65,22 +71,27 @@ + + + - @@ -92,10 +103,12 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift index e3d74dcb..736dbd0b 100644 --- a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift +++ b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift @@ -45,7 +45,7 @@ class ImagePostDetailTableViewController: UITableViewController { let alert = UIAlertController(title: "New Comment", message: "Which kind of comment do you want to create?", preferredStyle: .actionSheet) // If comment is a Text Post - let textPostAction = UIAlertAction(title: "Text", style: .default) { (_) in + let textPostAction = UIAlertAction(title: "Text", style: .default) { _ in let alert = UIAlertController(title: "Add a comment", message: "Write your comment below:", preferredStyle: .alert) var commentTextField: UITextField? @@ -73,9 +73,17 @@ class ImagePostDetailTableViewController: UITableViewController { self.present(alert, animated: true, completion: nil) } + // If comment is a voice comment + let voicePostAction = UIAlertAction(title: "Voice", style: .default) { _ in + let storyboard = UIStoryboard(name: "Main", bundle: nil) + let vc = storyboard.instantiateViewController(withIdentifier: "AudioCommentController") as! AudioCommentViewController + self.navigationController?.pushViewController(vc, animated: true) + } + let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) alert.addAction(textPostAction) + alert.addAction(voicePostAction) alert.addAction(cancelAction) self.present(alert, animated: true, completion: nil) From c6020378c4f842ac126e4195b8371b3057df620b Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Fri, 4 Sep 2020 15:20:00 -0700 Subject: [PATCH 14/20] Added bar button to save recording, gave the post controller a singleton property --- .../AudioCommentController.swift | 9 +++++++++ .../Model Controllers/PostController.swift | 15 ++++++++++++--- LambdaTimeline/Models/Comment.swift | 4 +++- LambdaTimeline/Models/Post.swift | 10 +++++++--- .../ImagePostViewController.swift | 2 +- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/LambdaTimeline/Model Controllers/AudioCommentController.swift b/LambdaTimeline/Model Controllers/AudioCommentController.swift index 21154d3c..d5ff8925 100644 --- a/LambdaTimeline/Model Controllers/AudioCommentController.swift +++ b/LambdaTimeline/Model Controllers/AudioCommentController.swift @@ -35,6 +35,8 @@ class AudioCommentViewController: UIViewController { var recordingURL: URL? var audioRecorder: AVAudioRecorder? + let saveButton = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(saveRecording)) + private lazy var timeIntervalFormatter: DateComponentsFormatter = { // NOTE: DateComponentFormatter is good for minutes/hours/seconds // DateComponentsFormatter is not good for milliseconds, use DateFormatter instead) @@ -59,6 +61,8 @@ class AudioCommentViewController: UIViewController { weight: .regular) loadAudio() + + navigationItem.setRightBarButton(saveButton, animated: true) } func updateViews() { @@ -238,6 +242,11 @@ class AudioCommentViewController: UIViewController { cancelTimer() } + @objc func saveRecording() { + let recordedCommentURL = recordingURL + + } + // MARK: - Actions @IBAction func togglePlayback(_ sender: Any) { diff --git a/LambdaTimeline/Model Controllers/PostController.swift b/LambdaTimeline/Model Controllers/PostController.swift index 3df87148..63bf7839 100644 --- a/LambdaTimeline/Model Controllers/PostController.swift +++ b/LambdaTimeline/Model Controllers/PostController.swift @@ -10,17 +10,19 @@ import UIKit class PostController { + static let shared = PostController() + var posts: [Post] = [] var currentUser: String? { UserDefaults.standard.string(forKey: "username") } - func createImagePost(with title: String, image: UIImage, ratio: CGFloat?) { + func createImagePost(with title: String, image: UIImage, ratio: CGFloat?, audioURL: URL?) { guard let currentUser = currentUser else { return } - let post = Post(title: title, mediaType: .image(image), ratio: ratio, author: currentUser) + let post = Post(title: title, mediaType: .image(image), ratio: ratio, author: currentUser, audioURL: audioURL) posts.append(post) } @@ -29,8 +31,15 @@ class PostController { guard let currentUser = currentUser else { return } - let comment = Comment(text: text, author: currentUser) + let comment = Comment(text: text, author: currentUser, audioURL: nil) post.comments.append(comment) } + + func addAudioComment(with url: URL, to post: inout Post) { + guard let currentUser = currentUser else { return } + + let comment = Comment(author: currentUser, audioURL: url) + post.comments.append(comment) + } } diff --git a/LambdaTimeline/Models/Comment.swift b/LambdaTimeline/Models/Comment.swift index a7dad6f5..e8770549 100644 --- a/LambdaTimeline/Models/Comment.swift +++ b/LambdaTimeline/Models/Comment.swift @@ -17,11 +17,13 @@ class Comment: Hashable { let text: String? let author: String let timestamp: Date + let audioURL: URL? - init(text: String? = nil, author: String, timestamp: Date = Date()) { + init(text: String? = nil, author: String, timestamp: Date = Date(), audioURL: URL?) { self.text = text self.author = author self.timestamp = timestamp + self.audioURL = audioURL } func hash(into hasher: inout Hasher) { diff --git a/LambdaTimeline/Models/Post.swift b/LambdaTimeline/Models/Post.swift index 15e1d65c..f6b070e8 100644 --- a/LambdaTimeline/Models/Post.swift +++ b/LambdaTimeline/Models/Post.swift @@ -22,14 +22,18 @@ class Post: Equatable { var id: String? var title: String? { - return comments.first?.text + comments.first?.text } - init(title: String, mediaType: MediaType, ratio: CGFloat?, author: String, timestamp: Date = Date()) { + var audioURL: URL? { + comments.first?.audioURL + } + + init(title: String, mediaType: MediaType, ratio: CGFloat?, author: String, timestamp: Date = Date(), audioURL: URL?) { self.mediaType = mediaType self.ratio = ratio self.author = author - self.comments = [Comment(text: title, author: author)] + self.comments = [Comment(text: title, author: author, audioURL: audioURL)] self.timestamp = timestamp self.id = UUID().uuidString } diff --git a/LambdaTimeline/View Controllers/ImagePostViewController.swift b/LambdaTimeline/View Controllers/ImagePostViewController.swift index c466f03e..07ee2168 100644 --- a/LambdaTimeline/View Controllers/ImagePostViewController.swift +++ b/LambdaTimeline/View Controllers/ImagePostViewController.swift @@ -138,7 +138,7 @@ class ImagePostViewController: ShiftableViewController { return } - postController.createImagePost(with: title, image: image, ratio: image.ratio) + postController.createImagePost(with: title, image: image, ratio: image.ratio, audioURL: <#URL?#>) navigationController?.popViewController(animated: true) } From dfb18fe1c06a08c1ace8f5cca01d22b57ab80600 Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Fri, 4 Sep 2020 15:21:17 -0700 Subject: [PATCH 15/20] Changed all instances of post controller to it's singleton version --- .../View Controllers/ImagePostDetailTableViewController.swift | 2 +- LambdaTimeline/View Controllers/ImagePostViewController.swift | 2 +- .../View Controllers/PostsCollectionViewController.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift index 736dbd0b..3b060f5c 100644 --- a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift +++ b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift @@ -18,7 +18,7 @@ class ImagePostDetailTableViewController: UITableViewController { @IBOutlet weak var commentButton: UIBarButtonItem! var post: Post! - var postController: PostController! + let postController = PostController.shared var imageData: Data? override func viewDidLoad() { diff --git a/LambdaTimeline/View Controllers/ImagePostViewController.swift b/LambdaTimeline/View Controllers/ImagePostViewController.swift index 07ee2168..24352ef1 100644 --- a/LambdaTimeline/View Controllers/ImagePostViewController.swift +++ b/LambdaTimeline/View Controllers/ImagePostViewController.swift @@ -26,7 +26,7 @@ class ImagePostViewController: ShiftableViewController { @IBOutlet weak var monoChromaticSlider: UISlider! // MARK: - Properties - var postController: PostController! + let postController = PostController.shared var post: Post? var imageData: Data? diff --git a/LambdaTimeline/View Controllers/PostsCollectionViewController.swift b/LambdaTimeline/View Controllers/PostsCollectionViewController.swift index b9ed6b54..671c9f09 100644 --- a/LambdaTimeline/View Controllers/PostsCollectionViewController.swift +++ b/LambdaTimeline/View Controllers/PostsCollectionViewController.swift @@ -10,7 +10,7 @@ import UIKit class PostsCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout { - var postController: PostController! + let postController = PostController.shared override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) From 4648313a916ba530c0df4eb41499243af2315319 Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Fri, 4 Sep 2020 16:39:20 -0700 Subject: [PATCH 16/20] Removed Save button in nav bar, added save button to view. Added unwind segue to take user back to comment table view. Added delegate to refresh table view --- LambdaTimeline.xcodeproj/project.pbxproj | 12 ++++-- LambdaTimeline/Storyboards/Main.storyboard | 40 ++++++++++++++++++- .../AudioCommentViewController.swift} | 17 +++++--- .../ImagePostDetailTableViewController.swift | 16 +++++++- .../ImagePostViewController.swift | 2 +- .../PostsCollectionViewController.swift | 4 +- .../SignInViewController.swift | 1 - LambdaTimeline/Views/AudioCommentCell.swift | 9 +++++ 8 files changed, 83 insertions(+), 18 deletions(-) rename LambdaTimeline/{Model Controllers/AudioCommentController.swift => View Controllers/AudioCommentViewController.swift} (96%) create mode 100644 LambdaTimeline/Views/AudioCommentCell.swift diff --git a/LambdaTimeline.xcodeproj/project.pbxproj b/LambdaTimeline.xcodeproj/project.pbxproj index 078966fb..69e712f6 100644 --- a/LambdaTimeline.xcodeproj/project.pbxproj +++ b/LambdaTimeline.xcodeproj/project.pbxproj @@ -8,8 +8,9 @@ /* Begin PBXBuildFile section */ 0B43785B25017D92009599C4 /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B43785A25017D92009599C4 /* UIImage+Scaling.swift */; }; + 0B8396BD25030775009DF3ED /* AudioCommentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8396BC25030775009DF3ED /* AudioCommentCell.swift */; }; 0B88760C2502E5ED00B6AAED /* AudioVisualizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B88760B2502E5ED00B6AAED /* AudioVisualizer.swift */; }; - 0B88760E2502E65600B6AAED /* AudioCommentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B88760D2502E65600B6AAED /* AudioCommentController.swift */; }; + 0B88760E2502E65600B6AAED /* AudioCommentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B88760D2502E65600B6AAED /* AudioCommentViewController.swift */; }; 4646377C216FDE4B00E7FF73 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4646377B216FDE4B00E7FF73 /* AppDelegate.swift */; }; 46463783216FDE4C00E7FF73 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 46463782216FDE4C00E7FF73 /* Assets.xcassets */; }; 46463786216FDE4C00E7FF73 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46463784216FDE4C00E7FF73 /* LaunchScreen.storyboard */; }; @@ -29,8 +30,9 @@ /* Begin PBXFileReference section */ 0B43785A25017D92009599C4 /* UIImage+Scaling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Scaling.swift"; sourceTree = ""; }; + 0B8396BC25030775009DF3ED /* AudioCommentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioCommentCell.swift; sourceTree = ""; }; 0B88760B2502E5ED00B6AAED /* AudioVisualizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioVisualizer.swift; sourceTree = ""; }; - 0B88760D2502E65600B6AAED /* AudioCommentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioCommentController.swift; sourceTree = ""; }; + 0B88760D2502E65600B6AAED /* AudioCommentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioCommentViewController.swift; sourceTree = ""; }; 46463778216FDE4B00E7FF73 /* LambdaTimeline.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LambdaTimeline.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4646377B216FDE4B00E7FF73 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 46463782216FDE4C00E7FF73 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -124,7 +126,6 @@ isa = PBXGroup; children = ( 4646379B2170091A00E7FF73 /* PostController.swift */, - 0B88760D2502E65600B6AAED /* AudioCommentController.swift */, ); path = "Model Controllers"; sourceTree = ""; @@ -136,6 +137,7 @@ 46A0366921700F5100E7FF73 /* PostsCollectionViewController.swift */, 46CFE6F421707D0000E7FF73 /* ImagePostViewController.swift */, 46D571F72173FC2700E7FF73 /* ImagePostDetailTableViewController.swift */, + 0B88760D2502E65600B6AAED /* AudioCommentViewController.swift */, ); path = "View Controllers"; sourceTree = ""; @@ -144,6 +146,7 @@ isa = PBXGroup; children = ( 46CFE7022171572600E7FF73 /* ImagePostCollectionViewCell.swift */, + 0B8396BC25030775009DF3ED /* AudioCommentCell.swift */, ); path = Views; sourceTree = ""; @@ -240,11 +243,12 @@ buildActionMask = 2147483647; files = ( 0B88760C2502E5ED00B6AAED /* AudioVisualizer.swift in Sources */, - 0B88760E2502E65600B6AAED /* AudioCommentController.swift in Sources */, + 0B88760E2502E65600B6AAED /* AudioCommentViewController.swift in Sources */, 46A0366D2170158900E7FF73 /* SignInViewController.swift in Sources */, 46CFE6F92170862C00E7FF73 /* ShiftableViewController.swift in Sources */, 4646377C216FDE4B00E7FF73 /* AppDelegate.swift in Sources */, 46CFE6F521707D0000E7FF73 /* ImagePostViewController.swift in Sources */, + 0B8396BD25030775009DF3ED /* AudioCommentCell.swift in Sources */, 0B43785B25017D92009599C4 /* UIImage+Scaling.swift in Sources */, 46463790216FFD1B00E7FF73 /* Post.swift in Sources */, 46D571F82173FC2700E7FF73 /* ImagePostDetailTableViewController.swift in Sources */, diff --git a/LambdaTimeline/Storyboards/Main.storyboard b/LambdaTimeline/Storyboards/Main.storyboard index 2d9353ae..1619b2bf 100644 --- a/LambdaTimeline/Storyboards/Main.storyboard +++ b/LambdaTimeline/Storyboards/Main.storyboard @@ -448,6 +448,33 @@ + + + + + + + + + + + + + + + + + + + @@ -517,7 +544,7 @@ + @@ -566,6 +601,7 @@ + diff --git a/LambdaTimeline/Model Controllers/AudioCommentController.swift b/LambdaTimeline/View Controllers/AudioCommentViewController.swift similarity index 96% rename from LambdaTimeline/Model Controllers/AudioCommentController.swift rename to LambdaTimeline/View Controllers/AudioCommentViewController.swift index d5ff8925..7d94630c 100644 --- a/LambdaTimeline/Model Controllers/AudioCommentController.swift +++ b/LambdaTimeline/View Controllers/AudioCommentViewController.swift @@ -9,6 +9,10 @@ import UIKit import AVFoundation +protocol VoiceCommentAddedDelegate { + func reloadData() +} + class AudioCommentViewController: UIViewController { // MARK: - IBOutlets @@ -35,7 +39,9 @@ class AudioCommentViewController: UIViewController { var recordingURL: URL? var audioRecorder: AVAudioRecorder? - let saveButton = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(saveRecording)) + let postController = PostController.shared + var post: Post! + var delegate: VoiceCommentAddedDelegate? private lazy var timeIntervalFormatter: DateComponentsFormatter = { // NOTE: DateComponentFormatter is good for minutes/hours/seconds @@ -61,8 +67,6 @@ class AudioCommentViewController: UIViewController { weight: .regular) loadAudio() - - navigationItem.setRightBarButton(saveButton, animated: true) } func updateViews() { @@ -242,9 +246,10 @@ class AudioCommentViewController: UIViewController { cancelTimer() } - @objc func saveRecording() { - let recordedCommentURL = recordingURL - + @IBAction func saveRecording(_ sender: Any) { + let commentUrl = createNewRecordingURL() + self.postController.addAudioComment(with: commentUrl, to: &self.post) + self.delegate?.reloadData() } // MARK: - Actions diff --git a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift index 3b060f5c..90a5cbb8 100644 --- a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift +++ b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift @@ -8,7 +8,6 @@ import UIKit - class ImagePostDetailTableViewController: UITableViewController { @IBOutlet weak var imageView: UIImageView! @@ -77,6 +76,8 @@ class ImagePostDetailTableViewController: UITableViewController { let voicePostAction = UIAlertAction(title: "Voice", style: .default) { _ in let storyboard = UIStoryboard(name: "Main", bundle: nil) let vc = storyboard.instantiateViewController(withIdentifier: "AudioCommentController") as! AudioCommentViewController + vc.post = self.post + vc.delegate = self self.navigationController?.pushViewController(vc, animated: true) } @@ -94,6 +95,9 @@ class ImagePostDetailTableViewController: UITableViewController { } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + + let cell = tableView.dequeueReusableCell(withIdentifier: "CommentCell", for: indexPath) let comment = post?.comments[indexPath.row + 1] @@ -103,4 +107,14 @@ class ImagePostDetailTableViewController: UITableViewController { return cell } + + @IBAction func undwindSegue(_ sender: UIStoryboardSegue){} +} + +extension ImagePostDetailTableViewController: VoiceCommentAddedDelegate { + func reloadData() { + tableView.reloadData() + } + + } diff --git a/LambdaTimeline/View Controllers/ImagePostViewController.swift b/LambdaTimeline/View Controllers/ImagePostViewController.swift index 24352ef1..b0e242fe 100644 --- a/LambdaTimeline/View Controllers/ImagePostViewController.swift +++ b/LambdaTimeline/View Controllers/ImagePostViewController.swift @@ -138,7 +138,7 @@ class ImagePostViewController: ShiftableViewController { return } - postController.createImagePost(with: title, image: image, ratio: image.ratio, audioURL: <#URL?#>) + postController.createImagePost(with: title, image: image, ratio: image.ratio, audioURL: nil) navigationController?.popViewController(animated: true) } diff --git a/LambdaTimeline/View Controllers/PostsCollectionViewController.swift b/LambdaTimeline/View Controllers/PostsCollectionViewController.swift index 671c9f09..55c81303 100644 --- a/LambdaTimeline/View Controllers/PostsCollectionViewController.swift +++ b/LambdaTimeline/View Controllers/PostsCollectionViewController.swift @@ -37,7 +37,7 @@ class PostsCollectionViewController: UICollectionViewController, UICollectionVie // MARK: UICollectionViewDataSource override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return postController?.posts.count ?? 0 + return postController.posts.count } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { @@ -85,7 +85,6 @@ class PostsCollectionViewController: UICollectionViewController, UICollectionVie override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "AddImagePost" { let destinationVC = segue.destination as? ImagePostViewController - destinationVC?.postController = postController } else if segue.identifier == "ViewImagePost" { @@ -93,7 +92,6 @@ class PostsCollectionViewController: UICollectionViewController, UICollectionVie guard let indexPath = collectionView.indexPathsForSelectedItems?.first else { return } - destinationVC?.postController = postController destinationVC?.post = postController.posts[indexPath.row] } } diff --git a/LambdaTimeline/View Controllers/SignInViewController.swift b/LambdaTimeline/View Controllers/SignInViewController.swift index c81bb748..997311f6 100644 --- a/LambdaTimeline/View Controllers/SignInViewController.swift +++ b/LambdaTimeline/View Controllers/SignInViewController.swift @@ -38,7 +38,6 @@ class SignInViewController: UIViewController { if segue.identifier == "ModalPostsVC" { guard let postsVC = (segue.destination as? UINavigationController)?.topViewController as? PostsCollectionViewController else { return } - postsVC.postController = postController } } } diff --git a/LambdaTimeline/Views/AudioCommentCell.swift b/LambdaTimeline/Views/AudioCommentCell.swift new file mode 100644 index 00000000..7f32fe0b --- /dev/null +++ b/LambdaTimeline/Views/AudioCommentCell.swift @@ -0,0 +1,9 @@ +// +// AudioCommentCell.swift +// LambdaTimeline +// +// Created by Clayton Watkins on 9/4/20. +// Copyright © 2020 Lambda School. All rights reserved. +// + +import Foundation From 6b4d063d2cbcc19c2c1404792bfc0297a5536cfb Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Fri, 4 Sep 2020 17:40:38 -0700 Subject: [PATCH 17/20] App crashes when trying to play audio from cell. States that the url doesn't exist. --- LambdaTimeline.xcodeproj/project.pbxproj | 8 ++-- LambdaTimeline/Storyboards/Main.storyboard | 12 ++++-- .../AudioCommentViewController.swift | 8 ++-- .../ImagePostDetailTableViewController.swift | 26 ++++++++----- LambdaTimeline/Views/AudioCommentCell.swift | 9 ----- .../Views/AudioCommentTableViewCell.swift | 37 +++++++++++++++++++ 6 files changed, 71 insertions(+), 29 deletions(-) delete mode 100644 LambdaTimeline/Views/AudioCommentCell.swift create mode 100644 LambdaTimeline/Views/AudioCommentTableViewCell.swift diff --git a/LambdaTimeline.xcodeproj/project.pbxproj b/LambdaTimeline.xcodeproj/project.pbxproj index 69e712f6..eb09e671 100644 --- a/LambdaTimeline.xcodeproj/project.pbxproj +++ b/LambdaTimeline.xcodeproj/project.pbxproj @@ -8,7 +8,7 @@ /* Begin PBXBuildFile section */ 0B43785B25017D92009599C4 /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B43785A25017D92009599C4 /* UIImage+Scaling.swift */; }; - 0B8396BD25030775009DF3ED /* AudioCommentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8396BC25030775009DF3ED /* AudioCommentCell.swift */; }; + 0B8396BF250307D2009DF3ED /* AudioCommentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8396BE250307D2009DF3ED /* AudioCommentTableViewCell.swift */; }; 0B88760C2502E5ED00B6AAED /* AudioVisualizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B88760B2502E5ED00B6AAED /* AudioVisualizer.swift */; }; 0B88760E2502E65600B6AAED /* AudioCommentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B88760D2502E65600B6AAED /* AudioCommentViewController.swift */; }; 4646377C216FDE4B00E7FF73 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4646377B216FDE4B00E7FF73 /* AppDelegate.swift */; }; @@ -30,7 +30,7 @@ /* Begin PBXFileReference section */ 0B43785A25017D92009599C4 /* UIImage+Scaling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Scaling.swift"; sourceTree = ""; }; - 0B8396BC25030775009DF3ED /* AudioCommentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioCommentCell.swift; sourceTree = ""; }; + 0B8396BE250307D2009DF3ED /* AudioCommentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioCommentTableViewCell.swift; sourceTree = ""; }; 0B88760B2502E5ED00B6AAED /* AudioVisualizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioVisualizer.swift; sourceTree = ""; }; 0B88760D2502E65600B6AAED /* AudioCommentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioCommentViewController.swift; sourceTree = ""; }; 46463778216FDE4B00E7FF73 /* LambdaTimeline.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LambdaTimeline.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -146,7 +146,7 @@ isa = PBXGroup; children = ( 46CFE7022171572600E7FF73 /* ImagePostCollectionViewCell.swift */, - 0B8396BC25030775009DF3ED /* AudioCommentCell.swift */, + 0B8396BE250307D2009DF3ED /* AudioCommentTableViewCell.swift */, ); path = Views; sourceTree = ""; @@ -244,11 +244,11 @@ files = ( 0B88760C2502E5ED00B6AAED /* AudioVisualizer.swift in Sources */, 0B88760E2502E65600B6AAED /* AudioCommentViewController.swift in Sources */, + 0B8396BF250307D2009DF3ED /* AudioCommentTableViewCell.swift in Sources */, 46A0366D2170158900E7FF73 /* SignInViewController.swift in Sources */, 46CFE6F92170862C00E7FF73 /* ShiftableViewController.swift in Sources */, 4646377C216FDE4B00E7FF73 /* AppDelegate.swift in Sources */, 46CFE6F521707D0000E7FF73 /* ImagePostViewController.swift in Sources */, - 0B8396BD25030775009DF3ED /* AudioCommentCell.swift in Sources */, 0B43785B25017D92009599C4 /* UIImage+Scaling.swift in Sources */, 46463790216FFD1B00E7FF73 /* Post.swift in Sources */, 46D571F82173FC2700E7FF73 /* ImagePostDetailTableViewController.swift in Sources */, diff --git a/LambdaTimeline/Storyboards/Main.storyboard b/LambdaTimeline/Storyboards/Main.storyboard index 1619b2bf..b94cc30c 100644 --- a/LambdaTimeline/Storyboards/Main.storyboard +++ b/LambdaTimeline/Storyboards/Main.storyboard @@ -396,13 +396,13 @@ - - + @@ -464,6 +464,9 @@ @@ -474,6 +477,9 @@ + + + diff --git a/LambdaTimeline/View Controllers/AudioCommentViewController.swift b/LambdaTimeline/View Controllers/AudioCommentViewController.swift index 7d94630c..5492cea5 100644 --- a/LambdaTimeline/View Controllers/AudioCommentViewController.swift +++ b/LambdaTimeline/View Controllers/AudioCommentViewController.swift @@ -175,13 +175,13 @@ class AudioCommentViewController: UIViewController { func createNewRecordingURL() -> URL { let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! - - let name = ISO8601DateFormatter.string(from: Date(), timeZone: .current, formatOptions: .withInternetDateTime) - let file = documents.appendingPathComponent(name, isDirectory: false).appendingPathExtension("caf") + + let file = documents.appendingPathComponent("AudioComment" + "\(Date())", isDirectory: false).appendingPathExtension("caf") print("recording URL: \(file)") - + return file + } diff --git a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift index 90a5cbb8..1cb169e5 100644 --- a/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift +++ b/LambdaTimeline/View Controllers/ImagePostDetailTableViewController.swift @@ -95,17 +95,25 @@ class ImagePostDetailTableViewController: UITableViewController { } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - - - - let cell = tableView.dequeueReusableCell(withIdentifier: "CommentCell", for: indexPath) - let comment = post?.comments[indexPath.row + 1] - cell.textLabel?.text = comment?.text - cell.detailTextLabel?.text = comment?.author - - return cell + if comment?.audioURL != nil { + guard let cell = tableView.dequeueReusableCell(withIdentifier: "AudioCommentCell", for: indexPath) as? AudioCommentTableViewCell else { return UITableViewCell()} + let comment = post?.comments[indexPath.row + 1] + cell.recordingURL = comment?.audioURL + cell.usernameLabel.text = comment?.author + return cell + } else { + + let cell = tableView.dequeueReusableCell(withIdentifier: "CommentCell", for: indexPath) + + let comment = post?.comments[indexPath.row + 1] + + cell.textLabel?.text = comment?.text + cell.detailTextLabel?.text = comment?.author + + return cell + } } @IBAction func undwindSegue(_ sender: UIStoryboardSegue){} diff --git a/LambdaTimeline/Views/AudioCommentCell.swift b/LambdaTimeline/Views/AudioCommentCell.swift deleted file mode 100644 index 7f32fe0b..00000000 --- a/LambdaTimeline/Views/AudioCommentCell.swift +++ /dev/null @@ -1,9 +0,0 @@ -// -// AudioCommentCell.swift -// LambdaTimeline -// -// Created by Clayton Watkins on 9/4/20. -// Copyright © 2020 Lambda School. All rights reserved. -// - -import Foundation diff --git a/LambdaTimeline/Views/AudioCommentTableViewCell.swift b/LambdaTimeline/Views/AudioCommentTableViewCell.swift new file mode 100644 index 00000000..d168dd72 --- /dev/null +++ b/LambdaTimeline/Views/AudioCommentTableViewCell.swift @@ -0,0 +1,37 @@ +// +// AudioCommentTableViewCell.swift +// LambdaTimeline +// +// Created by Clayton Watkins on 9/4/20. +// Copyright © 2020 Lambda School. All rights reserved. +// + +import UIKit +import AVFoundation + +class AudioCommentTableViewCell: UITableViewCell { + + var recordingURL: URL? + var audioPlayer: AVAudioPlayer? + + @IBOutlet weak var usernameLabel: UILabel! + + func prepareAudioSession() throws { + let session = AVAudioSession.sharedInstance() + try session.setCategory(.playback, options: [.defaultToSpeaker]) + try session.setActive(true, options: []) // can fail if on a phone call, for instance + } + + @IBAction func playButtonTapped(_ sender: Any) { + do { + try prepareAudioSession() + guard let commentURL = self.recordingURL else { return } + print(commentURL) + audioPlayer = try AVAudioPlayer(contentsOf: commentURL) + guard let audioPlayer = audioPlayer else { return } + audioPlayer.play() + } catch { + preconditionFailure("Failure to load audio file: \(error)") + } + } +} From 71ca678f3e6c6ea60f89e36feaba731e5e367347 Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Fri, 4 Sep 2020 19:15:47 -0700 Subject: [PATCH 18/20] Can add Voice Comments, but new ones ovvewrite the old ones --- .../AudioCommentViewController.swift | 69 ++++++++++++------- .../Views/AudioCommentTableViewCell.swift | 15 ++-- 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/LambdaTimeline/View Controllers/AudioCommentViewController.swift b/LambdaTimeline/View Controllers/AudioCommentViewController.swift index 5492cea5..ce6bb05f 100644 --- a/LambdaTimeline/View Controllers/AudioCommentViewController.swift +++ b/LambdaTimeline/View Controllers/AudioCommentViewController.swift @@ -35,13 +35,12 @@ class AudioCommentViewController: UIViewController { } weak var timer: Timer? - - var recordingURL: URL? var audioRecorder: AVAudioRecorder? let postController = PostController.shared var post: Post! var delegate: VoiceCommentAddedDelegate? + var recordingURL: URL? private lazy var timeIntervalFormatter: DateComponentsFormatter = { // NOTE: DateComponentFormatter is good for minutes/hours/seconds @@ -54,18 +53,16 @@ class AudioCommentViewController: UIViewController { return formatting }() - // MARK: - View Controller Lifecycle override func viewDidLoad() { super.viewDidLoad() -// Use a font that won't jump around as values change + // Use a font that won't jump around as values change timeElapsedLabel.font = UIFont.monospacedDigitSystemFont(ofSize: timeElapsedLabel.font.pointSize, weight: .regular) timeRemainingLabel.font = UIFont.monospacedDigitSystemFont(ofSize: timeRemainingLabel.font.pointSize, weight: .regular) - loadAudio() } @@ -135,12 +132,12 @@ class AudioCommentViewController: UIViewController { } func loadAudio() { -// let songURL = Bundle.main.url(forResource: "piano", withExtension: "mp3")! -// do { -// audioPlayer = try AVAudioPlayer(contentsOf: songURL) -// } catch { -// preconditionFailure("Failure to load audio file: \(error)") -// } + // let songURL = Bundle.main.url(forResource: "piano", withExtension: "mp3")! + // do { + // audioPlayer = try AVAudioPlayer(contentsOf: songURL) + // } catch { + // preconditionFailure("Failure to load audio file: \(error)") + // } } func prepareAudioSession() throws { @@ -173,16 +170,32 @@ class AudioCommentViewController: UIViewController { audioRecorder?.isRecording ?? false } - func createNewRecordingURL() -> URL { - let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! - - let file = documents.appendingPathComponent("AudioComment" + "\(Date())", isDirectory: false).appendingPathExtension("caf") - - print("recording URL: \(file)") - - return file - - } +// func createNewRecordingURL() -> URL { +// let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! +// +// let name = ISO8601DateFormatter.string(from: Date(), timeZone: .current, formatOptions: .withInternetDateTime) +// let file = documents.appendingPathComponent(name, isDirectory: false).appendingPathExtension("caf") +// +// print("recording URL: \(file)") +// +// return file +// } + + + + // func getDocumentsDirectory() -> URL + // { + // let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) + // let documentsDirectory = paths[0] + // return documentsDirectory + // } + // + // func getFileUrl() -> URL + // { + // let filename = "myRecording.m4a" + // let filePath = getDocumentsDirectory().appendingPathComponent(filename) + // return filePath + // } func requestPermissionOrStartRecording() { @@ -216,6 +229,14 @@ class AudioCommentViewController: UIViewController { } } + func newRecordingURL() -> URL { + let fm = FileManager.default + let documentsDir = try! fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) + +// let randomNumber = Int.random(in: 0...1_000_00) + + return documentsDir.appendingPathComponent("TestRecording").appendingPathExtension("caf") + } func startRecording() { do{ @@ -225,7 +246,7 @@ class AudioCommentViewController: UIViewController { return } - recordingURL = createNewRecordingURL() + recordingURL = newRecordingURL() let format = AVAudioFormat(standardFormatWithSampleRate: 44_100, channels: 1)! do { @@ -247,8 +268,8 @@ class AudioCommentViewController: UIViewController { } @IBAction func saveRecording(_ sender: Any) { - let commentUrl = createNewRecordingURL() - self.postController.addAudioComment(with: commentUrl, to: &self.post) + let commentURL = newRecordingURL() + self.postController.addAudioComment(with: commentURL, to: &self.post) self.delegate?.reloadData() } diff --git a/LambdaTimeline/Views/AudioCommentTableViewCell.swift b/LambdaTimeline/Views/AudioCommentTableViewCell.swift index d168dd72..5fbd839d 100644 --- a/LambdaTimeline/Views/AudioCommentTableViewCell.swift +++ b/LambdaTimeline/Views/AudioCommentTableViewCell.swift @@ -23,15 +23,18 @@ class AudioCommentTableViewCell: UITableViewCell { } @IBAction func playButtonTapped(_ sender: Any) { + print(recordingURL!) do { try prepareAudioSession() - guard let commentURL = self.recordingURL else { return } - print(commentURL) - audioPlayer = try AVAudioPlayer(contentsOf: commentURL) - guard let audioPlayer = audioPlayer else { return } - audioPlayer.play() + if let recordingURL = recordingURL{ + print(recordingURL) + audioPlayer = try AVAudioPlayer(contentsOf: recordingURL) + guard let audioPlayer = self.audioPlayer else { return } + audioPlayer.play() + } + } catch { - preconditionFailure("Failure to load audio file: \(error)") + preconditionFailure("Failure to load audio file at path \(recordingURL!): \(error)") } } } From 81f9ee5f68e575f41b381b75d73409483cdd4df5 Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Sat, 5 Sep 2020 20:55:33 -0700 Subject: [PATCH 19/20] Fixed issue with audio comments not being pulled from their url. Project meets MVP. --- .../AudioCommentViewController.swift | 55 +++---------------- 1 file changed, 8 insertions(+), 47 deletions(-) diff --git a/LambdaTimeline/View Controllers/AudioCommentViewController.swift b/LambdaTimeline/View Controllers/AudioCommentViewController.swift index ce6bb05f..8bdb3317 100644 --- a/LambdaTimeline/View Controllers/AudioCommentViewController.swift +++ b/LambdaTimeline/View Controllers/AudioCommentViewController.swift @@ -63,7 +63,6 @@ class AudioCommentViewController: UIViewController { weight: .regular) timeRemainingLabel.font = UIFont.monospacedDigitSystemFont(ofSize: timeRemainingLabel.font.pointSize, weight: .regular) - loadAudio() } func updateViews() { @@ -131,15 +130,6 @@ class AudioCommentViewController: UIViewController { audioPlayer?.isPlaying ?? false } - func loadAudio() { - // let songURL = Bundle.main.url(forResource: "piano", withExtension: "mp3")! - // do { - // audioPlayer = try AVAudioPlayer(contentsOf: songURL) - // } catch { - // preconditionFailure("Failure to load audio file: \(error)") - // } - } - func prepareAudioSession() throws { let session = AVAudioSession.sharedInstance() try session.setCategory(.playAndRecord, options: [.defaultToSpeaker]) @@ -170,33 +160,6 @@ class AudioCommentViewController: UIViewController { audioRecorder?.isRecording ?? false } -// func createNewRecordingURL() -> URL { -// let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! -// -// let name = ISO8601DateFormatter.string(from: Date(), timeZone: .current, formatOptions: .withInternetDateTime) -// let file = documents.appendingPathComponent(name, isDirectory: false).appendingPathExtension("caf") -// -// print("recording URL: \(file)") -// -// return file -// } - - - - // func getDocumentsDirectory() -> URL - // { - // let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) - // let documentsDirectory = paths[0] - // return documentsDirectory - // } - // - // func getFileUrl() -> URL - // { - // let filename = "myRecording.m4a" - // let filePath = getDocumentsDirectory().appendingPathComponent(filename) - // return filePath - // } - func requestPermissionOrStartRecording() { switch AVAudioSession.sharedInstance().recordPermission { @@ -230,13 +193,13 @@ class AudioCommentViewController: UIViewController { } func newRecordingURL() -> URL { - let fm = FileManager.default - let documentsDir = try! fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) - -// let randomNumber = Int.random(in: 0...1_000_00) - - return documentsDir.appendingPathComponent("TestRecording").appendingPathExtension("caf") - } + let fm = FileManager.default + let documentsDir = try! fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) + + let randomId = Int.random(in: 0...1_000_00) + + return documentsDir.appendingPathComponent("TestRecording" + "\(randomId)").appendingPathExtension("caf") + } func startRecording() { do{ @@ -268,8 +231,7 @@ class AudioCommentViewController: UIViewController { } @IBAction func saveRecording(_ sender: Any) { - let commentURL = newRecordingURL() - self.postController.addAudioComment(with: commentURL, to: &self.post) + self.postController.addAudioComment(with: recordingURL!, to: &self.post) self.delegate?.reloadData() } @@ -321,7 +283,6 @@ extension AudioCommentViewController: AVAudioRecorderDelegate { if let recordingURL = recordingURL { audioPlayer = try? AVAudioPlayer(contentsOf: recordingURL) } - recordingURL = nil cancelTimer() } From e0ef5fa59f248ad48404d50a0dbe1ee0029a4b21 Mon Sep 17 00:00:00 2001 From: Clayton Watkins Date: Sat, 5 Sep 2020 20:56:10 -0700 Subject: [PATCH 20/20] Fixed text alignment --- .../View Controllers/AudioCommentViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LambdaTimeline/View Controllers/AudioCommentViewController.swift b/LambdaTimeline/View Controllers/AudioCommentViewController.swift index 8bdb3317..4e906c66 100644 --- a/LambdaTimeline/View Controllers/AudioCommentViewController.swift +++ b/LambdaTimeline/View Controllers/AudioCommentViewController.swift @@ -196,7 +196,7 @@ class AudioCommentViewController: UIViewController { let fm = FileManager.default let documentsDir = try! fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) - let randomId = Int.random(in: 0...1_000_00) + let randomId = Int.random(in: 0...1_000_00) return documentsDir.appendingPathComponent("TestRecording" + "\(randomId)").appendingPathExtension("caf") }