Skip to content
This repository has been archived by the owner on Aug 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #57 from k-nh/feature/home
Browse files Browse the repository at this point in the history
기능추가🔧 #56: 좋아요(북마크) 관련 api 연동 및 MVVM 리팩토링
  • Loading branch information
k-nh authored Jun 25, 2022
2 parents 04f7eb0 + 1c0b77a commit 7e92355
Show file tree
Hide file tree
Showing 15 changed files with 2,649 additions and 2,519 deletions.
8 changes: 8 additions & 0 deletions EatDa.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@
FDB4068B283E3EB2003C70A8 /* SignIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB4068A283E3EB2003C70A8 /* SignIn.swift */; };
FDB7906D2805A704008621D1 /* RestaurantTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB7906C2805A704008621D1 /* RestaurantTableViewCell.swift */; };
FDB7906E2805A783008621D1 /* ReviewFeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0CF62C27A12BDA00BDEA53 /* ReviewFeedViewController.swift */; };
FDBC11E3285D7C4500FCADF4 /* LikeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDBC11E2285D7C4500FCADF4 /* LikeViewModel.swift */; };
FDBC11E5285D85BF00FCADF4 /* BasicModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDBC11E4285D85BF00FCADF4 /* BasicModel.swift */; };
FDD8DDCD27A423450072034C /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD8DDCC27A423450072034C /* HomeViewController.swift */; };
FDD8DDD027A423740072034C /* FilterButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD8DDCF27A423740072034C /* FilterButtonView.swift */; };
FDD8DDD327A426C40072034C /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD8DDD227A426C40072034C /* UIColor.swift */; };
Expand Down Expand Up @@ -190,6 +192,8 @@
FDB40686283E14D5003C70A8 /* TokenUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenUtils.swift; sourceTree = "<group>"; };
FDB4068A283E3EB2003C70A8 /* SignIn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignIn.swift; sourceTree = "<group>"; };
FDB7906C2805A704008621D1 /* RestaurantTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestaurantTableViewCell.swift; sourceTree = "<group>"; };
FDBC11E2285D7C4500FCADF4 /* LikeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikeViewModel.swift; sourceTree = "<group>"; };
FDBC11E4285D85BF00FCADF4 /* BasicModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicModel.swift; sourceTree = "<group>"; };
FDD8DDCC27A423450072034C /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = "<group>"; };
FDD8DDCF27A423740072034C /* FilterButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterButtonView.swift; sourceTree = "<group>"; };
FDD8DDD227A426C40072034C /* UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -359,6 +363,7 @@
FD022E432833ADF600FC32E9 /* Entities */ = {
isa = PBXGroup;
children = (
FDBC11E4285D85BF00FCADF4 /* BasicModel.swift */,
FDE30735284640EA00EA15CF /* RestaurantListModel.swift */,
FD022E442833ADFE00FC32E9 /* MapDetailModel.swift */,
FD9D38E528533D3C005A0C86 /* SearchLogModel.swift */,
Expand Down Expand Up @@ -456,6 +461,7 @@
isa = PBXGroup;
children = (
FD63EA9827CCEDD600DFBD0B /* LikeViewController.swift */,
FDBC11E2285D7C4500FCADF4 /* LikeViewModel.swift */,
FD63EA9A27CCEDEB00DFBD0B /* LikeHeaderView.swift */,
FDB7906C2805A704008621D1 /* RestaurantTableViewCell.swift */,
);
Expand Down Expand Up @@ -893,10 +899,12 @@
FDD8DDD027A423740072034C /* FilterButtonView.swift in Sources */,
FD94861827A9598C009BE666 /* AroundSectionView.swift in Sources */,
FD9D4F7027B4EBA70005205E /* UIView.swift in Sources */,
FDBC11E5285D85BF00FCADF4 /* BasicModel.swift in Sources */,
FD6FBDAB28379E2500BD7E20 /* CustomAnnotation.swift in Sources */,
FDE3075E28473FC600EA15CF /* SearchDetailViewModel.swift in Sources */,
FD94861627A95987009BE666 /* RecommendSectionView.swift in Sources */,
FD9C6F4E27C10A75005D88A6 /* FilterSectionViewModel.swift in Sources */,
FDBC11E3285D7C4500FCADF4 /* LikeViewModel.swift in Sources */,
FDD8DDCD27A423450072034C /* HomeViewController.swift in Sources */,
F0E4285B27FC8EDC00C623E1 /* WritePostViewController.swift in Sources */,
F0B279E6282816AA000B35FF /* TermsViewController.swift in Sources */,
Expand Down
37 changes: 32 additions & 5 deletions EatDa/Global/DesignSystem/UIComponent/Button/LikeButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
//

import UIKit
import RxSwift

class LikeButton: UIButton {
private var isLiked = false
let disposeBag = DisposeBag()

var id: Int = 0
var isLiked:Bool = false

private let unlikedImage = UIImage(named: "heart")
private let likedImage = UIImage(named: "heart_fill")
Expand All @@ -20,18 +24,26 @@ class LikeButton: UIButton {
super.init(frame: frame)

setImage(unlikedImage, for: .normal)
bind(RestaurantListViewModel())
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

public func flipLikedState() {
isLiked = !isLiked
animate()
public func setLikedState(_ restaurantId: Int, _ state: Bool) {
id = restaurantId
isLiked = state
if state {
setImage(likedImage, for: .normal)
} else {
setImage(unlikedImage, for: .normal)
}
}


private func animate() {
func flipLikedState() {
isLiked = !isLiked
UIView.animate(withDuration: 0.1, animations: {
let newImage = self.isLiked ? self.likedImage : self.unlikedImage
let newScale = self.isLiked ? self.likedScale : self.unlikedScale
Expand All @@ -43,4 +55,19 @@ class LikeButton: UIButton {
})
})
}

func bind(_ viewModel: RestaurantListViewModel) {
self.rx.tap
.map {
self.flipLikedState()
return (self.id, self.isLiked)
}
.bind(to: viewModel.likeButtonTapped)
.disposed(by: disposeBag)

viewModel.likeButtonTapped
.subscribe(onNext: { button in
viewModel.tapLikeButton(button.0, button.1)
}).disposed(by: disposeBag)
}
}
13 changes: 13 additions & 0 deletions EatDa/Global/Network/Entities/BasicModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// BasicModel.swift
// EatDa
//
// Created by 김나희 on 6/18/22.
//

import Foundation

struct BasicModel: Decodable {
let code: Int
let message: String
}
3 changes: 2 additions & 1 deletion EatDa/Global/Network/Entities/RestaurantListModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ struct RestaurantListModel: Decodable {
let explanation: String?
let imgUrl: String?
let distance: Int?
let hashTagRestaurants: String?
let hashTags: [String]
let liked: Bool
}
19 changes: 18 additions & 1 deletion EatDa/Global/Network/Service/RestaurantListNetwork.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,25 @@ import Foundation
import RxSwift

struct RestaurantListNetwork {
let disposeBag = DisposeBag()

func getLikedRestaurantValue() -> Observable<[RestaurantListModel]> {
let apiCall = API<[RestaurantListModel]>(url: APIConstants.GET_LIKED_RESTAURANT, method: .get, parameters: [:])
return apiCall.fetchWithRx()
}

func postLikedRestaurant(_ restaurantId: Int) {
let apiCall = API<BasicModel>(url: APIConstants.GET_LIKED_RESTAURANT+"/"+String(restaurantId), method: .post, parameters: [:])
apiCall.fetch(completion: { _ in return })
}

func deleteLikedRestaurant(_ restaurantId: Int) {
let apiCall = API<BasicModel>(url: APIConstants.GET_LIKED_RESTAURANT+"/"+String(restaurantId), method: .delete, parameters: ["restaurantId": restaurantId])
apiCall.fetch(completion: { _ in return })
}

func getRecommendRestaurantValue() -> Observable<[RestaurantListModel]> {
let apiCall = API<[RestaurantListModel]>(url: APIConstants.GET_RECOMMEND_RESTAURANT, method: .get, parameters: ["page": 1])
let apiCall = API<[RestaurantListModel]>(url: APIConstants.GET_RECOMMEND_RESTAURANT, method: .get, parameters: ["lastPage": 0])
return apiCall.fetchWithRx()
}

Expand Down
7 changes: 7 additions & 0 deletions EatDa/Global/Network/Util/APIResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ struct APIConstants {

// MARK: DETAIL
static let GET_RESTAURANT_DETAIL = "/restaurant/"

// MARK: LIKE
static let GET_LIKED_RESTAURANT = "/restaurant/bookmark"
}

class API<T: Decodable> {
Expand Down Expand Up @@ -69,6 +72,8 @@ class API<T: Decodable> {
}
}

print("요청: ", self.fetchURL)

AF.request(self.fetchURL,
method: self.method,
parameters: self.parameters,
Expand All @@ -79,6 +84,8 @@ class API<T: Decodable> {
if self.fetchURL == APIConstants.BASE_URL + APIConstants.POST_SIGN_IN {
guard let accessToken = response.response?.allHeaderFields["Authorization"] as? String else { return }
guard let refreshToken = response.response?.allHeaderFields["X-Refresh-Token"] as? String else { return }
print(accessToken)
print(refreshToken)
// 로그인 시 토큰 키체인에 저장
TokenUtils.create(key: Const.KeyChainKey.accessToken, token: accessToken)
TokenUtils.create(key: Const.KeyChainKey.refreshToken, token: refreshToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ extension RecommendCollectionViewCell {
func setData(_ data: RestaurantListModel){
self.titleLabel.text = data.name ?? ""
self.descriptionLabel.text = data.explanation ?? ""
self.hashTagLabel.text = data.hashTagRestaurants ?? ""
//self.hashTagLabel.text = data.hashTags ?? ""
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import RxSwift

final class RecommendSectionView: UIView {
let disposeBag = DisposeBag()
let isFetchedData = PublishSubject<RestaurantListData>()
let isFetchedData = PublishSubject<RestaurantListModel>()

// MARK: UIComponents
private lazy var subTitleLabel: UILabel = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
//

import UIKit
import RxSwift

final class RestaurantListCell: UITableViewCell {
var disposeBag = DisposeBag()

var thumnailImageView: UIImageView = {
let image = UIImageView(image: UIImage(named: "res"))
Expand Down Expand Up @@ -65,23 +67,23 @@ final class RestaurantListCell: UITableViewCell {
return label
}()

let likeImageView: UIImageView = {
let image = UIImageView(image: UIImage(named: "like_fill"))
// 눌렀을때 event 추가 필요
let likeButton: LikeButton = {
let button = LikeButton()

return image
return button
}()

override func layoutSubviews() {
super.layoutSubviews()

setupLayout()
}

}

extension RestaurantListCell {
func setupLayout(){
[thumnailImageView, titleLabel, districtLabel, hashtagLabel1, hashtagLabel2, likeImageView]
[thumnailImageView, titleLabel, districtLabel, hashtagLabel1, hashtagLabel2, likeButton]
.forEach { contentView.addSubview($0) }

thumnailImageView.snp.makeConstraints {
Expand Down Expand Up @@ -114,7 +116,7 @@ extension RestaurantListCell {
$0.height.equalTo(27.0)
}

likeImageView.snp.makeConstraints {
likeButton.snp.makeConstraints {
$0.trailing.equalToSuperview().inset(25.34)
$0.centerY.equalToSuperview()
}
Expand All @@ -123,6 +125,8 @@ extension RestaurantListCell {
func setData(_ data: RestaurantListModel){
self.titleLabel.text = data.name ?? ""
self.districtLabel.text = "\(String(describing: data.distance))"
self.hashtagLabel1.text = data.hashTagRestaurants ?? ""
//self.hashtagLabel1.text = data.hashTags ?? ""
self.likeButton.setLikedState(data.id ?? 0, data.liked)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,23 @@ import RxCocoa

struct RestaurantListViewModel {
let recommendRestaurantData: Driver<[RestaurantListModel]>


let likeButtonTapped = PublishRelay<(Int, Bool)>()

init(model: RestaurantListNetwork = RestaurantListNetwork()) {
let recommendDetailListViewData = model.getRecommendRestaurantValue()
//let aroundDetailListViewData = model.getAroundRestaurantValue()

self.recommendRestaurantData = recommendDetailListViewData
.asDriver(onErrorJustReturn: [])
}

func tapLikeButton(_ id: Int, _ isLiked: Bool){
let model = RestaurantListNetwork()
if isLiked {
model.postLikedRestaurant(id)
} else {
model.deleteLikedRestaurant(id)
}
}
}
5 changes: 3 additions & 2 deletions EatDa/Scenes/Like/LikeHeaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ final class LikeHeaderView: UITableViewHeaderFooterView {

private lazy var totalCountLabel: UILabel = {
let label = UILabel()
// 수정필요 - 나중에 api 연결해서 바인딩
label.text = "총 4개"
label.textColor = .label
label.font = .systemFont(ofSize: 12.0)

Expand All @@ -41,6 +39,9 @@ final class LikeHeaderView: UITableViewHeaderFooterView {
fatalError("init(coder:) has not been implemented")
}

func setupData(_ dataCount: Int) {
totalCountLabel.text = "\(dataCount)"
}
}

// MARK: private
Expand Down
Loading

0 comments on commit 7e92355

Please sign in to comment.