Skip to content
This repository was archived by the owner on Sep 8, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Secretly.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
30C77CB6266AF48300A888DC /* CurrentUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C77CB5266AF48300A888DC /* CurrentUser.swift */; };
30C77CB8266BD44300A888DC /* CreatePostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C77CB7266BD44300A888DC /* CreatePostViewController.swift */; };
30FD0E722659645A006E309A /* Faker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FD0E712659645A006E309A /* Faker.swift */; };
88FFFB2726E7207000373DEE /* Like.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FFFB2626E7207000373DEE /* Like.swift */; };
88FFFB2926E7219600373DEE /* LikeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88FFFB2826E7219600373DEE /* LikeService.swift */; };
E021984723FA35E00025C28E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E021984623FA35E00025C28E /* AppDelegate.swift */; };
E021984923FA35E00025C28E /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E021984823FA35E00025C28E /* SceneDelegate.swift */; };
E021984B23FA35E00025C28E /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E021984A23FA35E00025C28E /* WelcomeViewController.swift */; };
Expand Down Expand Up @@ -125,6 +127,8 @@
30C77CB5266AF48300A888DC /* CurrentUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentUser.swift; sourceTree = "<group>"; };
30C77CB7266BD44300A888DC /* CreatePostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePostViewController.swift; sourceTree = "<group>"; };
30FD0E712659645A006E309A /* Faker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Faker.swift; sourceTree = "<group>"; };
88FFFB2626E7207000373DEE /* Like.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Like.swift; sourceTree = "<group>"; };
88FFFB2826E7219600373DEE /* LikeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikeService.swift; sourceTree = "<group>"; };
E021984323FA35E00025C28E /* Secretly.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretly.app; sourceTree = BUILT_PRODUCTS_DIR; };
E021984623FA35E00025C28E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
E021984823FA35E00025C28E /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -222,6 +226,7 @@
30C77CAF266AD69700A888DC /* CurrentUserService.swift */,
304E06C726742BDA00A99128 /* CreatePostService.swift */,
304E06C926742CC500A99128 /* FeedService.swift */,
88FFFB2826E7219600373DEE /* LikeService.swift */,
);
path = Services;
sourceTree = "<group>";
Expand All @@ -248,6 +253,7 @@
307A30572661AD540020DF8B /* User.swift */,
30C77CB3266AF47300A888DC /* Credentials.swift */,
30C77CB5266AF48300A888DC /* CurrentUser.swift */,
88FFFB2626E7207000373DEE /* Like.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -428,6 +434,7 @@
E021984B23FA35E00025C28E /* WelcomeViewController.swift in Sources */,
3072FBDF2680FA5A00B35C8C /* ImageProcessor.swift in Sources */,
302BB622267E38E800FD74F5 /* PostInputViewController+UIImagePickerControllerDelegate.swift in Sources */,
88FFFB2726E7207000373DEE /* Like.swift in Sources */,
302B5845267E658E007133E6 /* HttpResponse.swift in Sources */,
302B584A267E658E007133E6 /* RestClient.swift in Sources */,
302B5848267E658E007133E6 /* HttpClient.swift in Sources */,
Expand Down Expand Up @@ -466,6 +473,7 @@
30C77CB6266AF48300A888DC /* CurrentUser.swift in Sources */,
302BB624267E3A8700FD74F5 /* PostInputViewController+UIColorPickerViewControllerDelegate.swift in Sources */,
304E06CF267468DA00A99128 /* UIColor+Pastel.swift in Sources */,
88FFFB2926E7219600373DEE /* LikeService.swift in Sources */,
304E06C42674133D00A99128 /* String+isBlank.swift in Sources */,
30BC8BA42662BDEF00F7E6A5 /* ImageStore.swift in Sources */,
3033795B267537490066D94A /* FeedCollectionViewController+UICollectionViewDataSourcePrefetching.swift in Sources */,
Expand Down
26 changes: 26 additions & 0 deletions Secretly/Models/Like.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Like.swift
// Secretly
//
// Created by Emanuel Flores Martínez on 06/09/21.
// Copyright © 2021 3zcurdia. All rights reserved.
//

import Foundation

struct Like: Restable {
let id: Int?
let createdAt: String?
let updatedAt: String?

init() {
self.id = nil
self.createdAt = nil
self.updatedAt = nil
}

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
}
}
6 changes: 6 additions & 0 deletions Secretly/Models/Post.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ struct Post: Restable {
let longitude: Double?
let createdAt: Date?
let updatedAt: Date?
var likesCount: Int?
var liked: Bool?

init(content: String, backgroundColor: String, latitude: Double? = nil, longitude: Double? = nil, image: UIImage? = nil) {
self.content = content
Expand All @@ -34,6 +36,8 @@ struct Post: Restable {
self.commentsCount = nil
self.createdAt = nil
self.updatedAt = nil
self.likesCount = nil
self.liked = nil
}

func encode(to encoder: Encoder) throws {
Expand All @@ -43,5 +47,7 @@ struct Post: Restable {
try container.encode(imageData, forKey: .imageData)
try container.encode(latitude, forKey: .latitude)
try container.encode(longitude, forKey: .longitude)
try container.encode(likesCount, forKey: .likesCount)
try container.encode(liked, forKey: .liked)
}
}
14 changes: 14 additions & 0 deletions Secretly/Network/RestClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ struct RestClient<T: Restable> {
complete(newResult)
}
}

func create(complete: @escaping (Result<T?, Error>)-> Void) throws {
client.post(path: path, body: nil) { result in
let newResult = result.flatMap { parse(data: $0)}
complete(newResult)
}
}

func update(model: T, complete: @escaping (Result<T?, Error>) -> Void) throws {
let data = try encoder.encode(model)
Expand All @@ -73,6 +80,13 @@ struct RestClient<T: Restable> {
complete(newResult)
}
}

func delete(complete: @escaping (Result<T?, Error>) -> Void) {
client.delete(path: path) { result in
let newResult = result.flatMap { parse(data: $0) }
complete(newResult)
}
}

private func parseList(data: Data?) -> Result<[T], Error> {
if let data = data {
Expand Down
33 changes: 33 additions & 0 deletions Secretly/Services/LikeService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// LikeService.swift
// Secretly
//
// Created by Emanuel Flores Martínez on 06/09/21.
// Copyright © 2021 3zcurdia. All rights reserved.
//

import Foundation

struct LikeService {
let endpoint: RestClient<Like>?

init(post: Post?) {
guard let post = post, let postId = post.id else {
self.endpoint = nil
return
}
self.endpoint = RestClient<Like>(client: AmacaConfig.shared.httpClient, path: "api/v1/posts/\(postId)/likes")
}

func likePost(complete: @escaping(Result<Like?, Error>) -> Void) {
try? endpoint?.create { result in
DispatchQueue.main.async { complete(result) }
}
}

func dislikePost(complete: @escaping(Result<Like?, Error>) -> Void) {
endpoint?.delete { result in
DispatchQueue.main.async { complete(result) }
}
}
}
47 changes: 46 additions & 1 deletion Secretly/Views/PostCollectionViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,56 @@
import UIKit

class PostCollectionViewCell: UICollectionViewCell {
// MARK: - Properties
static let reuseIdentifier = "feedPostCell"
var likeService: LikeService?
var post: Post? {
didSet {
updateView()
updateView()
likeService = LikeService(post: post)
}
}
@IBOutlet weak var authorView: AuthorView!
@IBOutlet weak var contentLabel: UILabel!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var likeState: UIImageView!
@IBOutlet weak var likesCounter: UILabel!
@IBOutlet weak var commentCounter: UILabel!

override func awakeFromNib() {
super.awakeFromNib()

let tapLike = UITapGestureRecognizer(target: self, action: #selector(handleLike))
self.likeState.addGestureRecognizer(tapLike)

let doubleTapImage = UITapGestureRecognizer(target: self, action: #selector(handleLike))
doubleTapImage.numberOfTapsRequired = 2
self.imageView.addGestureRecognizer(doubleTapImage)
}

// MARK: - Actions
@objc func handleLike() {
post?.liked?.toggle()
guard let postLiked = post?.liked, let postLikesCount = post?.likesCount else { return }
if postLiked {
self.likeService?.likePost { [weak self] _ in
guard let self = self else { return }
if postLikesCount > 0 {
self.post?.likesCount! += 1
}
self.setupLike()
}
} else {
self.likeService?.dislikePost { [weak self] _ in
guard let self = self else { return }
self.post?.likesCount! -= 1
self.setupLike()
}
}

}

// MARK: - Helper functions
func updateView() {
imageView.image = nil
guard let post = post else { return }
Expand All @@ -37,5 +71,16 @@ class PostCollectionViewCell: UICollectionViewCell {
ImageLoader.load(postImg.mediumUrl) { img in self.imageView.image = img }
}
self.authorView.author = post.user
setupLike()
}

private func setupLike() {
let imageName = post?.liked ?? false ? "heart.fill" : "heart"
likeState.image = UIImage(systemName: imageName)
if post?.likesCount == 1 {
likesCounter.text = "\(post?.likesCount ?? 1) like"
} else {
likesCounter.text = "\(post?.likesCount ?? 0) likes"
}
}
}
16 changes: 14 additions & 2 deletions Secretly/Views/PostCollectionViewCell.xib
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<rect key="frame" x="0.0" y="0.0" width="400" height="300"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="LcI-IM-E3b">
<imageView clipsSubviews="YES" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="LcI-IM-E3b">
<rect key="frame" x="0.0" y="0.0" width="400" height="300"/>
<constraints>
<constraint firstAttribute="height" constant="300" id="FVk-cX-Y87"/>
Expand All @@ -30,7 +30,7 @@
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="heart" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="qBu-h3-372">
<imageView clipsSubviews="YES" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="heart" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="qBu-h3-372">
<rect key="frame" x="3" y="278.5" width="20" height="17.5"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
Expand Down Expand Up @@ -62,13 +62,23 @@
<constraint firstAttribute="height" constant="40" id="FP9-i4-4aV"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0 likes" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2qn-h1-wXL" userLabel="Likes Counter">
<rect key="frame" x="26" y="280" width="40" height="14"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="xYS-Us-YeF"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</view>
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="gUg-yt-vKP" secondAttribute="trailing" id="1Ox-jh-Fdw"/>
<constraint firstItem="LcI-IM-E3b" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="ALT-n0-JLg"/>
<constraint firstAttribute="trailing" secondItem="ier-Sw-bbQ" secondAttribute="trailing" constant="3" id="Chd-rw-tMw"/>
<constraint firstItem="2qn-h1-wXL" firstAttribute="centerY" secondItem="qBu-h3-372" secondAttribute="centerY" id="GtO-fn-JTD"/>
<constraint firstItem="LcI-IM-E3b" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="Saq-lM-0ue"/>
<constraint firstAttribute="trailing" secondItem="Mh0-Gr-U1B" secondAttribute="trailing" constant="20" id="TmC-rH-rgp"/>
<constraint firstItem="gUg-yt-vKP" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="Udj-7I-U3z"/>
Expand All @@ -77,6 +87,7 @@
<constraint firstAttribute="bottom" secondItem="ier-Sw-bbQ" secondAttribute="bottom" constant="6" id="dEi-5s-5Xo"/>
<constraint firstItem="ier-Sw-bbQ" firstAttribute="leading" secondItem="Zus-SL-Va3" secondAttribute="trailing" constant="3" id="dc0-TJ-Axz"/>
<constraint firstAttribute="bottom" secondItem="LcI-IM-E3b" secondAttribute="bottom" id="ic7-9y-GCI"/>
<constraint firstItem="2qn-h1-wXL" firstAttribute="leading" secondItem="qBu-h3-372" secondAttribute="trailing" constant="3" id="ltp-U9-ysj"/>
<constraint firstItem="gUg-yt-vKP" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="mch-9a-c32"/>
<constraint firstAttribute="trailing" secondItem="LcI-IM-E3b" secondAttribute="trailing" id="mm7-gQ-FEH"/>
<constraint firstItem="Mh0-Gr-U1B" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="20" id="pwh-eS-Ehf"/>
Expand All @@ -90,6 +101,7 @@
<outlet property="contentLabel" destination="Mh0-Gr-U1B" id="tTs-p1-j7k"/>
<outlet property="imageView" destination="LcI-IM-E3b" id="vWk-OE-zm9"/>
<outlet property="likeState" destination="qBu-h3-372" id="Qyd-rc-8ZQ"/>
<outlet property="likesCounter" destination="2qn-h1-wXL" id="i90-3B-Lin"/>
</connections>
<point key="canvasLocation" x="389.85507246376812" y="182.8125"/>
</collectionViewCell>
Expand Down