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
26 changes: 19 additions & 7 deletions Secretly.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
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 */; };
5B89708B269A491D0080C464 /* Like.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B89708A269A491D0080C464 /* Like.swift */; };
5B89708D269A4A3E0080C464 /* LikeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B89708C269A4A3E0080C464 /* LikeService.swift */; };
5B897092269A913A0080C464 /* LikeServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B897091269A913A0080C464 /* LikeServiceTest.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 +128,9 @@
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>"; };
5B89708A269A491D0080C464 /* Like.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Like.swift; sourceTree = "<group>"; };
5B89708C269A4A3E0080C464 /* LikeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikeService.swift; sourceTree = "<group>"; };
5B897091269A913A0080C464 /* LikeServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikeServiceTest.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 @@ -199,8 +205,8 @@
children = (
307A305C2661CD510020DF8B /* PostCollectionViewCell.swift */,
307A305D2661CD510020DF8B /* PostCollectionViewCell.xib */,
307A306426629B990020DF8B /* AuthorView.swift */,
302BB61B267D7CC800FD74F5 /* PreviewPostVIew.swift */,
307A306426629B990020DF8B /* AuthorView.swift */,
);
path = Views;
sourceTree = "<group>";
Expand All @@ -222,6 +228,7 @@
30C77CAF266AD69700A888DC /* CurrentUserService.swift */,
304E06C726742BDA00A99128 /* CreatePostService.swift */,
304E06C926742CC500A99128 /* FeedService.swift */,
5B89708C269A4A3E0080C464 /* LikeService.swift */,
);
path = Services;
sourceTree = "<group>";
Expand All @@ -248,6 +255,7 @@
307A30572661AD540020DF8B /* User.swift */,
30C77CB3266AF47300A888DC /* Credentials.swift */,
30C77CB5266AF48300A888DC /* CurrentUser.swift */,
5B89708A269A491D0080C464 /* Like.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -299,6 +307,7 @@
children = (
E021985D23FA35E20025C28E /* SecretlyTests.swift */,
E021985F23FA35E20025C28E /* Info.plist */,
5B897091269A913A0080C464 /* LikeServiceTest.swift */,
);
path = SecretlyTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -428,6 +437,7 @@
E021984B23FA35E00025C28E /* WelcomeViewController.swift in Sources */,
3072FBDF2680FA5A00B35C8C /* ImageProcessor.swift in Sources */,
302BB622267E38E800FD74F5 /* PostInputViewController+UIImagePickerControllerDelegate.swift in Sources */,
5B89708B269A491D0080C464 /* 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 +476,7 @@
30C77CB6266AF48300A888DC /* CurrentUser.swift in Sources */,
302BB624267E3A8700FD74F5 /* PostInputViewController+UIColorPickerViewControllerDelegate.swift in Sources */,
304E06CF267468DA00A99128 /* UIColor+Pastel.swift in Sources */,
5B89708D269A4A3E0080C464 /* LikeService.swift in Sources */,
304E06C42674133D00A99128 /* String+isBlank.swift in Sources */,
30BC8BA42662BDEF00F7E6A5 /* ImageStore.swift in Sources */,
3033795B267537490066D94A /* FeedCollectionViewController+UICollectionViewDataSourcePrefetching.swift in Sources */,
Expand All @@ -481,6 +492,7 @@
buildActionMask = 2147483647;
files = (
E021985E23FA35E20025C28E /* SecretlyTests.swift in Sources */,
5B897092269A913A0080C464 /* LikeServiceTest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -635,13 +647,13 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = D3XL2U7DQC;
DEVELOPMENT_TEAM = CF8GW6MT8Z;
INFOPLIST_FILE = Secretly/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = mx.unam.ioslab.Secretly;
PRODUCT_BUNDLE_IDENTIFIER = fernando.Secretly;
PRODUCT_NAME = Secretly;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
Expand All @@ -653,13 +665,13 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = D3XL2U7DQC;
DEVELOPMENT_TEAM = CF8GW6MT8Z;
INFOPLIST_FILE = Secretly/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = mx.unam.ioslab.Secretly;
PRODUCT_BUNDLE_IDENTIFIER = fernando.Secretly;
PRODUCT_NAME = Secretly;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
Expand All @@ -672,7 +684,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = D3XL2U7DQC;
DEVELOPMENT_TEAM = CF8GW6MT8Z;
INFOPLIST_FILE = SecretlyTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
LD_RUNPATH_SEARCH_PATHS = (
Expand All @@ -694,7 +706,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = D3XL2U7DQC;
DEVELOPMENT_TEAM = CF8GW6MT8Z;
INFOPLIST_FILE = SecretlyTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
LD_RUNPATH_SEARCH_PATHS = (
Expand Down
12 changes: 6 additions & 6 deletions Secretly/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>To add some context to your posts </string>
<key>NSCameraUsageDescription</key>
<string>To add some context to your posts</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>To georeference posts within a region </string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
Expand All @@ -26,6 +20,12 @@
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>To add some context to your posts</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>To georeference posts within a region </string>
<key>NSPhotoLibraryUsageDescription</key>
<string>To add some context to your posts </string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
Expand Down
15 changes: 15 additions & 0 deletions Secretly/Models/Like.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Like.swift
// Secretly
//
// Created by Proteco on 10/07/21.
// Copyright © 2021 3zcurdia. All rights reserved.
//

import Foundation

struct Like: Restable {
let id: Int
let createdAt: Date
let updatedAt: Date
}
6 changes: 5 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 likesCount: 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, liked: Bool, likesCount: Int? = nil) {
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.likesCount = nil
self.liked = false
}

func encode(to encoder: Encoder) throws {
Expand Down
15 changes: 14 additions & 1 deletion Secretly/Network/HttpResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ struct HttpResponse {
}

func result(for data: Data?) -> Result<Data?, Error> {
return status.result().map { _ in data }
//#if DEBUG
if let udata = data, !udata.isEmpty {
let currentData = String(data: udata, encoding: .utf8)
debugPrint("Response: \(status) \(self.httpUrlResponse.statusCode) \(self.httpUrlResponse.url!) -d \(String(describing: currentData))")
} else {
debugPrint("Response: \(status) \(self.httpUrlResponse.statusCode) \(self.httpUrlResponse.url!)")
}
//#endif
if let udata = data, !udata.isEmpty {
return status.result().map { _ in data }
} else {
return status.result().map { _ in nil }
}
}

}
16 changes: 15 additions & 1 deletion Secretly/Network/RestClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,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 create(model: T, complete: @escaping (Result<T?, Error>) -> Void) throws {
let data = try encoder.encode(model)
Expand All @@ -61,7 +68,14 @@ struct RestClient<T: Restable> {

func update(model: T, complete: @escaping (Result<T?, Error>) -> Void) throws {
let data = try encoder.encode(model)
client.put(path: "\(path)/\(model.id)", body: data) { result in
client.put(path: path, body: data) { result in
let newResult = result.flatMap { parse(data: $0) }
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)
}
Expand Down
42 changes: 42 additions & 0 deletions Secretly/Services/LikeService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// LikeService.swift
// Secretly
//
// Created by Proteco on 10/07/21.
// Copyright © 2021 3zcurdia. All rights reserved.
//

import Foundation

struct LikeService {
private var 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")
}

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

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

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

}
2 changes: 1 addition & 1 deletion Secretly/ViewControllers/CreatePostViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class CreatePostViewController: UIViewController {

@IBAction
func createPost(_ sender: Any?) {
let post = Post(content: contentField.text!, backgroundColor: colorField.text!)
let post = Post(content: contentField.text!, backgroundColor: colorField.text!, liked: false, likesCount: 0)
let postsEndpoint = RestClient<Post>(client: AmacaConfig.shared.httpClient, path: "/api/v1/posts")

do {
Expand Down
3 changes: 2 additions & 1 deletion Secretly/ViewControllers/PostInputViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ class PostInputViewController: UIViewController, UINavigationControllerDelegate
content: postText,
backgroundColor: previewPost.backgroundColor?.hexString ?? "#3366CC",
latitude: currentLocation?.latitude,
longitude: currentLocation?.longitude
longitude: currentLocation?.longitude,
liked: false
)
if let uimage = previewPost.image {
post.imageData = uimage.encodeBase64()
Expand Down
50 changes: 50 additions & 0 deletions Secretly/Views/PostCollectionViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,82 @@ 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 likeCounter: UILabel!

override func awakeFromNib() {
super.awakeFromNib()

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

let doubleTapImageView = UITapGestureRecognizer(target: self, action: #selector(doubleTapImageViewLike))
doubleTapImageView.numberOfTapsRequired = 2
self.imageView.isUserInteractionEnabled = true
self.imageView.addGestureRecognizer(doubleTapImageView)
}

func updateView() {
status()
imageView.image = nil
guard let post = post else { return }
if let color = UIColor(hex: post.backgroundColor) {
self.backgroundColor = color
}
self.contentLabel.text = post.content
self.commentCounter.text = String(describing: post.commentsCount ?? 0)
self.likeCounter.text = String(describing: post.likesCount ?? 0)
if let postImg = post.image {
ImageLoader.load(postImg.mediumUrl) { img in self.imageView.image = img }
}
self.authorView.author = post.user
}

func status() {
guard let post = post else {return}
if post.liked {
likeState.image = UIImage(systemName: "heart.fill")
} else {
likeState.image = UIImage(systemName: "heart")
}
}

@objc private func tapLike(){
self.like()
}

@objc private func doubleTapImageViewLike(_ gesture: UITapGestureRecognizer){
self.like()
}

private func like(){
guard let post = post, let id = post.id else {return}
let updateLike = Like(id: id, createdAt: Date(), updatedAt: Date())
if !post.liked {
likeService?.create(updateLike) { result in
self.post?.liked = true
self.likeState.image = UIImage(systemName: "heart.fill")
self.likeCounter.text = String(describing: post.likesCount! + 1)
}
} else {
likeService?.delete(updateLike) { result in
self.post?.liked = false
self.likeState.image = UIImage(systemName: "heart")
self.likeCounter.text = String(describing: post.likesCount ?? 0 - 1)
}
}
}

}
Loading