From 2c35e58f3104380fa3217934ee8a9e9d7bc30a92 Mon Sep 17 00:00:00 2001 From: "rookie.w" Date: Sat, 16 Jan 2021 13:59:09 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=94=A8=20messageCell=20=ED=95=98?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dear-World.xcodeproj/project.pbxproj | 4 + .../Scene/Discover/Cell/LikeButton.swift | 73 +++++++++++ .../Discover/Cell/MessageTableViewCell.swift | 122 +++++++++++++++--- 3 files changed, 182 insertions(+), 17 deletions(-) create mode 100644 Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/LikeButton.swift diff --git a/Dear-World/Dear-World.xcodeproj/project.pbxproj b/Dear-World/Dear-World.xcodeproj/project.pbxproj index 292475b..52ddbae 100644 --- a/Dear-World/Dear-World.xcodeproj/project.pbxproj +++ b/Dear-World/Dear-World.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 121BDB592597652A0062B15A /* MessageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121BDB582597652A0062B15A /* MessageTableViewCell.swift */; }; 121BDB672597982F0062B15A /* DiscoverReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121BDB662597982F0062B15A /* DiscoverReactor.swift */; }; 121BDB8E259829840062B15A /* CountrySelectController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121BDB8D259829840062B15A /* CountrySelectController.swift */; }; + 1221913B25B19EB8001D0D10 /* heartfull.json in Resources */ = {isa = PBXBuildFile; fileRef = 1221913A25B19EB8001D0D10 /* heartfull.json */; }; 12257E1825A622750007E65E /* SortTypeSelectController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12257E1725A622750007E65E /* SortTypeSelectController.swift */; }; 1263E09725A1C87400E3F121 /* Message.API.Countries.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1263E09625A1C87400E3F121 /* Message.API.Countries.swift */; }; 1263E09C25A1C8DD00E3F121 /* Message.Model.Countries.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1263E09B25A1C8DD00E3F121 /* Message.Model.Countries.swift */; }; @@ -115,6 +116,7 @@ 121BDB582597652A0062B15A /* MessageTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageTableViewCell.swift; sourceTree = ""; }; 121BDB662597982F0062B15A /* DiscoverReactor.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = DiscoverReactor.swift; sourceTree = ""; tabWidth = 2; }; 121BDB8D259829840062B15A /* CountrySelectController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountrySelectController.swift; sourceTree = ""; }; + 1221913A25B19EB8001D0D10 /* heartfull.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = heartfull.json; path = ../../../../Downloads/heartfull.json; sourceTree = ""; }; 12257E1725A622750007E65E /* SortTypeSelectController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SortTypeSelectController.swift; sourceTree = ""; }; 1263E09625A1C87400E3F121 /* Message.API.Countries.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.API.Countries.swift; sourceTree = ""; }; 1263E09B25A1C8DD00E3F121 /* Message.Model.Countries.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.Model.Countries.swift; sourceTree = ""; }; @@ -372,6 +374,7 @@ isa = PBXGroup; children = ( 39658F9F259ADE770050D180 /* splash_1x.json */, + 1221913A25B19EB8001D0D10 /* heartfull.json */, 395825B625948EE4007325AB /* Colors.xcassets */, 3958258325948E43007325AB /* Assets.xcassets */, 3958258525948E43007325AB /* LaunchScreen.storyboard */, @@ -739,6 +742,7 @@ 39518C7725A8FA2400F777D1 /* GoogleService-Info.plist in Resources */, 395825B725948EE4007325AB /* Colors.xcassets in Resources */, 3958258425948E43007325AB /* Assets.xcassets in Resources */, + 1221913B25B19EB8001D0D10 /* heartfull.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/LikeButton.swift b/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/LikeButton.swift new file mode 100644 index 0000000..90b21fe --- /dev/null +++ b/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/LikeButton.swift @@ -0,0 +1,73 @@ +// +// LikeButton.swift +// Dear-World +// +// Created by rookie.w on 2021/01/15. +// + +import UIKit +import Lottie +import RxSwift + +class LikeButton: UIView { + enum Progress: CGFloat { + case likeDefault = 30 + case unlikeDefault = 1 + case likeTouchEnd = 15 + case unlikeTouchEnd = 60 + + func percent() -> CGFloat { + self.rawValue / 60 + } + } + + let disposeBag: DisposeBag = DisposeBag() + let animationView: AnimationView = AnimationView(animation: Animation.named("heartfull")) + var messageId: Int + init(isLike: Bool, messageId: Int) { + self.messageId = messageId + super.init(frame: .null) + setupUI(isLike: isLike) + bind() + } + func setupUI(isLike: Bool) { + self.addSubview(animationView) + self.translatesAutoresizingMaskIntoConstraints = false + self.clipsToBounds = false + animationView.snp.makeConstraints { + $0.top.bottom.leading.trailing.equalToSuperview() + } + self.animationView.currentProgress = isLike ? Progress.likeDefault.percent() : Progress.unlikeDefault.percent() + } + func bind() { + self.rx.tapGesture() + .skip(1) + .throttle(.milliseconds(1000), latest: false, scheduler: MainScheduler.instance) + .flatMap { [weak self] _ -> Observable in + guard let id = self?.messageId else { + return Observable.just(false) + } + return Network.request(Message.API.Like(messageId: id)) + .map { $0?.isLiked } + } + .subscribe(onNext: { [weak self] isLike in + self?.tap(isLike!) + }) + .disposed(by: self.disposeBag) + } + @objc func tap(_ isLike: Bool) { + animationView.pause() + if isLike { + self.animationView.play(fromProgress: Progress.unlikeDefault.percent(), toProgress: Progress.likeTouchEnd.percent()) + } else { + self.animationView.play(fromProgress: Progress.likeDefault.percent(), toProgress: Progress.unlikeTouchEnd.percent()) + } + } + override init(frame: CGRect) { + self.messageId = 0 + super.init(frame: frame) + } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/MessageTableViewCell.swift b/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/MessageTableViewCell.swift index 7d6a0d8..34d320c 100644 --- a/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/MessageTableViewCell.swift +++ b/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/MessageTableViewCell.swift @@ -8,8 +8,20 @@ import RxCocoa import RxSwift import UIKit +import Lottie final class MessageTableViewCell: UITableViewCell { + private enum HeartProgress: CGFloat { + case likeDefault = 30 + case unlikeDefault = 1 + case likeTouchEnd = 15 + case unlikeTouchEnd = 60 + + func percent() -> CGFloat { + self.rawValue / 60 + } + } + let disposeBag: DisposeBag = DisposeBag() // MARK: πŸ–Ό UI let emojiImageView: UIImageView = UIImageView() @@ -17,9 +29,9 @@ final class MessageTableViewCell: UITableViewCell { let countryLabel: UILabel = UILabel() let countryFlagImageView: UIImageView = UIImageView() let detailTextView: UITextView = UITextView() - let likeView: UIImageView = UIImageView() - let likeCountLabel: UILabel = UILabel() let shareButton: UIButton = UIButton() + let likeView: AnimationView = AnimationView(animation: Animation.named("heartfull")) + let likeCountLabel: UILabel = UILabel() var likeCount: Int = 0 { didSet { self.likeCountLabel.text = "\(likeCount)" @@ -27,7 +39,7 @@ final class MessageTableViewCell: UITableViewCell { } var isLike: Bool = false { didSet { - self.likeView.image = isLike ? UIImage(named: "heart_liked") : UIImage(named: "heart") + self.likeView.currentProgress = isLike ? HeartProgress.likeDefault.percent() : HeartProgress.unlikeDefault.percent() self.likeCountLabel.textColor = isLike ? .loveRed : .grayWhite } } @@ -130,15 +142,16 @@ final class MessageTableViewCell: UITableViewCell { } self.likeView.do { - $0.image = UIImage(named: "heart") + $0.translatesAutoresizingMaskIntoConstraints = false + $0.clipsToBounds = false } mainView.addSubview(likeView) - self.likeView.snp.makeConstraints { - $0.leading.equalToSuperview().inset(30) - $0.top.equalTo(detailTextView.snp.bottom).offset(19) - $0.bottom.equalToSuperview().inset(24) - $0.height.equalTo(17) - $0.width.equalTo(20) + likeView.snp.makeConstraints { + $0.leading.equalToSuperview().inset(20) + $0.top.equalTo(detailTextView.snp.bottom).offset(7) + $0.bottom.equalToSuperview().inset(13) + $0.height.equalTo(40) + $0.width.equalTo(40) } self.likeCountLabel.do { @@ -148,8 +161,8 @@ final class MessageTableViewCell: UITableViewCell { mainView.addSubview(self.likeCountLabel) self.likeCountLabel.snp.makeConstraints { $0.centerY.equalTo(likeView.snp.centerY) - $0.height.equalTo(14) - $0.leading.equalTo(likeView.snp.trailing).offset(5) + $0.height.equalTo(17) + $0.leading.equalTo(likeView.snp.trailing).offset(-5) } self.shareButton.do { @@ -169,12 +182,12 @@ final class MessageTableViewCell: UITableViewCell { } } - // MARK: πŸ”— Bind private func bind() { self.likeView .rx.tapGesture() .debug() - .throttle(.milliseconds(300), scheduler: MainScheduler.instance) + .skip(1) + .throttle(.milliseconds(1000), latest: false, scheduler: MainScheduler.instance) .flatMap { [weak self] _ -> Observable in guard let id = self?.messageId else { return Observable.just(false) @@ -183,10 +196,85 @@ final class MessageTableViewCell: UITableViewCell { .map { $0?.isLiked } } .filterNil() - .subscribe (onNext: {[weak self] isLike in - self?.isLike = isLike - self?.likeCount += (isLike ? 1 : -1) + .subscribe(onNext: { [weak self] isLike in + guard let likeView = self?.likeView else { return } + likeView.pause() + if !isLike { + self?.likeCount -= 1 + self?.likeCountLabel.textColor = .grayWhite + } + likeView.play( + // TODO : 각 상황에 λŒ€ν•œ 값듀을 enum으둜 μ •μ˜ν• κ²ƒ + fromProgress: isLike ? HeartProgress.unlikeDefault.percent() : HeartProgress.likeDefault.percent(), + toProgress: isLike ? HeartProgress.likeTouchEnd.percent() : HeartProgress.unlikeTouchEnd.percent()) { (completed) in + if completed && isLike{ + self?.likeCount += 1 + self?.likeCountLabel.textColor = .loveRed + } + } }) .disposed(by: self.disposeBag) } } +//class Fdf: UIView { +// enum Progress: CGFloat { +// case likeDefault = 30 +// case unlikeDefault = 1 +// case likeTouchEnd = 15 +// case unlikeTouchEnd = 60 +// +// func percent() -> CGFloat { +// self.rawValue / 60 +// } +// } +// +// let disposeBag: DisposeBag = DisposeBag() +// let animationView: AnimationView = AnimationView(animation: Animation.named("heartfull")) +// var messageId: Int +// init(isLike: Bool, messageId: Int) { +// self.messageId = messageId +// super.init(frame: .null) +// setupUI(isLike: isLike) +// bind() +// } +// func setupUI(isLike: Bool) { +// self.addSubview(animationView) +// self.translatesAutoresizingMaskIntoConstraints = false +// self.clipsToBounds = false +// animationView.snp.makeConstraints { +// $0.top.bottom.leading.trailing.equalToSuperview() +// } +// self.animationView.currentProgress = isLike ? Progress.likeDefault.percent() : Progress.unlikeDefault.percent() +// } +// func bind() { +// self.rx.tapGesture() +// .skip(1) +// .throttle(.milliseconds(1000), latest: false, scheduler: MainScheduler.instance) +// .flatMap { [weak self] _ -> Observable in +// guard let id = self?.messageId else { +// return Observable.just(false) +// } +// return Network.request(Message.API.Like(messageId: id)) +// .map { $0?.isLiked } +// } +// .subscribe(onNext: { [weak self] isLike in +// self?.tap(isLike!) +// }) +// .disposed(by: self.disposeBag) +// } +// @objc func tap(_ isLike: Bool) { +// animationView.pause() +// if isLike { +// self.animationView.play(fromProgress: Progress.unlikeDefault.percent(), toProgress: Progress.likeTouchEnd.percent()) +// } else { +// self.animationView.play(fromProgress: Progress.likeDefault.percent(), toProgress: Progress.unlikeTouchEnd.percent()) +// } +// } +// override init(frame: CGRect) { +// self.messageId = 0 +// super.init(frame: frame) +// } +// required init?(coder: NSCoder) { +// fatalError("init(coder:) has not been implemented") +// } +//} From ca75d3390598a7a06a3eb7dbe4ffe28da1904886 Mon Sep 17 00:00:00 2001 From: "rookie.w" Date: Sat, 16 Jan 2021 14:01:46 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=90=9B=20cell=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EA=B5=AD=EA=B8=B0=EB=9E=91=20=EB=82=98=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=EC=9D=B4=20=EA=B2=B9=EC=B9=98=EB=8A=94=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Scene/Discover/Cell/MessageTableViewCell.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/MessageTableViewCell.swift b/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/MessageTableViewCell.swift index 34d320c..68285e9 100644 --- a/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/MessageTableViewCell.swift +++ b/Dear-World/Dear-World/Source/Presentation/Scene/Discover/Cell/MessageTableViewCell.swift @@ -122,8 +122,8 @@ final class MessageTableViewCell: UITableViewCell { } mainView.addSubview(self.countryLabel) self.countryLabel.snp.makeConstraints { - $0.bottom.equalTo(emojiView.snp.bottom) - $0.leading.equalTo(emojiView.snp.trailing).offset(10) + $0.centerY.equalTo(countryFlagImageView) + $0.leading.equalTo(countryFlagImageView.snp.trailing).offset(5) $0.trailing.lessThanOrEqualToSuperview() }