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 @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
1445C8C226EAD8C600769390 /* Like.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1445C8C126EAD8C600769390 /* Like.swift */; };
1445C8C626EAD9F700769390 /* LikeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1445C8C526EAD9F700769390 /* LikeService.swift */; };
302B5845267E658E007133E6 /* HttpResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B583D267E658E007133E6 /* HttpResponse.swift */; };
302B5846267E658E007133E6 /* AmacaConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B583E267E658E007133E6 /* AmacaConfig.swift */; };
302B5847267E658E007133E6 /* StatusCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B583F267E658E007133E6 /* StatusCode.swift */; };
Expand Down Expand Up @@ -76,6 +78,8 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
1445C8C126EAD8C600769390 /* Like.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Like.swift; sourceTree = "<group>"; };
1445C8C526EAD9F700769390 /* LikeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikeService.swift; sourceTree = "<group>"; };
302B583D267E658E007133E6 /* HttpResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpResponse.swift; sourceTree = "<group>"; };
302B583E267E658E007133E6 /* AmacaConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AmacaConfig.swift; sourceTree = "<group>"; };
302B583F267E658E007133E6 /* StatusCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusCode.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -222,6 +226,7 @@
30C77CAF266AD69700A888DC /* CurrentUserService.swift */,
304E06C726742BDA00A99128 /* CreatePostService.swift */,
304E06C926742CC500A99128 /* FeedService.swift */,
1445C8C526EAD9F700769390 /* LikeService.swift */,
);
path = Services;
sourceTree = "<group>";
Expand All @@ -248,6 +253,7 @@
307A30572661AD540020DF8B /* User.swift */,
30C77CB3266AF47300A888DC /* Credentials.swift */,
30C77CB5266AF48300A888DC /* CurrentUser.swift */,
1445C8C126EAD8C600769390 /* 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 */,
1445C8C226EAD8C600769390 /* 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 */,
1445C8C626EAD9F700769390 /* LikeService.swift in Sources */,
304E06C42674133D00A99128 /* String+isBlank.swift in Sources */,
30BC8BA42662BDEF00F7E6A5 /* ImageStore.swift in Sources */,
3033795B267537490066D94A /* FeedCollectionViewController+UICollectionViewDataSourcePrefetching.swift in Sources */,
Expand Down
19 changes: 19 additions & 0 deletions Secretly/Models/Like.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Like.swift
// Secretly
//
// Created by Orlando Ortega on 09/09/21.
// Copyright © 2021 3zcurdia. All rights reserved.
//

import Foundation

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

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

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

func encode(to encoder: Encoder) throws {
Expand All @@ -43,5 +47,17 @@ struct Post: Restable {
try container.encode(imageData, forKey: .imageData)
try container.encode(latitude, forKey: .latitude)
try container.encode(longitude, forKey: .longitude)
try container.encode(likeCount, forKey: .likeCount)
try container.encode(liked, forKey: .liked)
}

mutating func onLikeOrDislike(likeOrUnlike lou: Bool) {
if lou {
likeCount = (likeCount ?? 0) + 1
liked = true
} else {
likeCount = (likeCount ?? 0) - 1
liked = false
}
}
}
6 changes: 5 additions & 1 deletion Secretly/Network/HttpResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ struct HttpResponse {
}

func result(for data: Data?) -> Result<Data?, Error> {
return status.result().map { _ in data }
if let data = data, !data.isEmpty {
return status.result().map { (_) in data }
} else {
return status.result().map { _ in nil}
}
}
}
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 res = result.flatMap { parse(data: $0) }
complete(res)
}
}

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) throws {
client.delete(path: path) { (result) in
let res = result.flatMap { parse(data: $0) }
complete(res)
}
}

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

import Foundation

struct LikeService {
var likeEndpoint: RestClient<Like>?
var isLiked = false

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

mutating func likeOrDislikePost(complete: @escaping(Result<Like?, Error>) -> Void) {
if !isLiked {
isLiked = !isLiked
try? likeEndpoint?.create(complete: { (res) in
DispatchQueue.main.async {
complete(res)
}
})
} else {
isLiked = !isLiked
try? likeEndpoint?.delete(complete: { (res) in
DispatchQueue.main.async {
complete(res)
}
})
}
}
}
33 changes: 32 additions & 1 deletion Secretly/Views/PostCollectionViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ import UIKit

class PostCollectionViewCell: UICollectionViewCell {
static let reuseIdentifier = "feedPostCell"
var likeService: LikeService?
var post: Post? {
didSet {
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 commentCounter: UILabel!
@IBOutlet weak var likeCount: UILabel!
@IBOutlet weak var likeBtn: UIButton!

override func awakeFromNib() {
super.awakeFromNib()
Expand All @@ -38,4 +41,32 @@ class PostCollectionViewCell: UICollectionViewCell {
}
self.authorView.author = post.user
}

@IBAction func onLikeTapped(_ sender: UIButton) {
var lod = false
likeService?.likeOrDislikePost(complete: { [unowned self] res in
switch res {
case .success(nil):
likeBtn.setImage(UIImage(systemName: "heart"), for: .normal)
post?.onLikeOrDislike(likeOrUnlike: lod)
lod = !lod
if(post?.likeCount ?? 0 > 0) {
self.likeCount.text = "\(post?.likeCount ?? 0) Likes"
} else {
self.likeCount.text = ""
}
case .success:
likeBtn.setImage(UIImage(systemName: "heart.fill"), for: .normal)
post?.onLikeOrDislike(likeOrUnlike: lod)
lod = !lod
if(post?.likeCount ?? 0 > 0) {
self.likeCount.text = "\(post?.likeCount ?? 0) Likes"
} else {
self.likeCount.text = ""
}
case .failure:
print("Request failed, cause: \(res)")
}
})
}
}
42 changes: 28 additions & 14 deletions Secretly/Views/PostCollectionViewCell.xib
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
Expand Down Expand Up @@ -30,14 +30,6 @@
<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">
<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>
<constraint firstAttribute="width" constant="20" id="FZr-RK-fSl"/>
<constraint firstAttribute="height" constant="20" id="aph-kx-k7x"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1200 " lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ier-Sw-bbQ">
<rect key="frame" x="370" y="282" width="27" height="12"/>
<constraints>
Expand All @@ -62,36 +54,58 @@
<constraint firstAttribute="height" constant="40" id="FP9-i4-4aV"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RIs-k8-OnQ">
<rect key="frame" x="0.0" y="267" width="33" height="33"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" image="heart" catalog="system"/>
<connections>
<action selector="onLikeTapped:" destination="gTV-IL-0wX" eventType="touchUpInside" id="zfx-2t-wDs"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3 Likes" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TYg-Lb-wVt">
<rect key="frame" x="33" y="267" width="97" height="33"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="10"/>
<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="RIs-k8-OnQ" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="4Ct-Mr-cnQ"/>
<constraint firstItem="RIs-k8-OnQ" firstAttribute="top" secondItem="Mh0-Gr-U1B" secondAttribute="bottom" constant="102.5" id="8sa-Ow-t6r"/>
<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="TYg-Lb-wVt" firstAttribute="top" secondItem="Mh0-Gr-U1B" secondAttribute="bottom" constant="102.5" id="Okx-Ta-vYn"/>
<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="Zus-SL-Va3" firstAttribute="leading" secondItem="TYg-Lb-wVt" secondAttribute="trailing" constant="217" id="UVS-sM-De5"/>
<constraint firstItem="gUg-yt-vKP" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="Udj-7I-U3z"/>
<constraint firstItem="qBu-h3-372" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="3" id="Wk2-tC-y2S"/>
<constraint firstItem="Mh0-Gr-U1B" firstAttribute="centerY" secondItem="gTV-IL-0wX" secondAttribute="centerY" id="cdi-uV-CwA"/>
<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 firstItem="Zus-SL-Va3" firstAttribute="leading" secondItem="RIs-k8-OnQ" secondAttribute="trailing" constant="314" id="eWt-0a-DAa"/>
<constraint firstAttribute="bottom" secondItem="LcI-IM-E3b" secondAttribute="bottom" id="ic7-9y-GCI"/>
<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"/>
<constraint firstAttribute="bottom" secondItem="RIs-k8-OnQ" secondAttribute="bottom" id="sS3-rd-WFF"/>
<constraint firstAttribute="bottom" secondItem="Zus-SL-Va3" secondAttribute="bottom" constant="2" id="t8V-mY-lku"/>
<constraint firstAttribute="bottom" secondItem="qBu-h3-372" secondAttribute="bottom" constant="3" id="wei-7x-Bcq"/>
<constraint firstItem="TYg-Lb-wVt" firstAttribute="leading" secondItem="RIs-k8-OnQ" secondAttribute="trailing" id="wrj-W6-uNa"/>
<constraint firstAttribute="bottom" secondItem="TYg-Lb-wVt" secondAttribute="bottom" id="yVA-18-afy"/>
</constraints>
<size key="customSize" width="400" height="300"/>
<connections>
<outlet property="authorView" destination="gUg-yt-vKP" id="cZF-pT-x7d"/>
<outlet property="commentCounter" destination="ier-Sw-bbQ" id="Kr2-a4-New"/>
<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="likeBtn" destination="RIs-k8-OnQ" id="SrG-GA-TWO"/>
<outlet property="likeCount" destination="TYg-Lb-wVt" id="R0c-q4-7Wq"/>
</connections>
<point key="canvasLocation" x="389.85507246376812" y="182.8125"/>
<point key="canvasLocation" x="92.753623188405811" y="148.66071428571428"/>
</collectionViewCell>
</objects>
<resources>
Expand Down