From 8a2b71d63defaf841a4e20208c9e0ad12d484148 Mon Sep 17 00:00:00 2001 From: LeeSeungmin Date: Fri, 22 Mar 2024 17:07:45 +0900 Subject: [PATCH 1/7] =?UTF-8?q?Update:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20refuse=20->=20reject=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{card_refuse.imageset => card_reject.imageset}/Contents.json | 0 .../{card_refuse.imageset => card_reject.imageset}/Union.svg | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/{card_refuse.imageset => card_reject.imageset}/Contents.json (100%) rename Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/{card_refuse.imageset => card_reject.imageset}/Union.svg (100%) diff --git a/Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/card_refuse.imageset/Contents.json b/Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/card_reject.imageset/Contents.json similarity index 100% rename from Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/card_refuse.imageset/Contents.json rename to Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/card_reject.imageset/Contents.json diff --git a/Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/card_refuse.imageset/Union.svg b/Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/card_reject.imageset/Union.svg similarity index 100% rename from Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/card_refuse.imageset/Union.svg rename to Projects/Modules/DesignSystem/Resources/Image.xcassets/Icons/card_icon/card_reject.imageset/Union.svg From 9f6f7f2da3e43fd81670f3ec58c6b8950e164a91 Mon Sep 17 00:00:00 2001 From: LeeSeungmin Date: Fri, 22 Mar 2024 17:12:18 +0900 Subject: [PATCH 2/7] =?UTF-8?q?[#72]Refactor:=20exported=20import=EB=A1=9C?= =?UTF-8?q?=20=EB=A1=9C=ED=8B=B0=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC?= =?UTF-8?q?=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/Modules/DesignSystem/Src/DesignSystem.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Projects/Modules/DesignSystem/Src/DesignSystem.swift b/Projects/Modules/DesignSystem/Src/DesignSystem.swift index 36ceb5ef..c4d73460 100644 --- a/Projects/Modules/DesignSystem/Src/DesignSystem.swift +++ b/Projects/Modules/DesignSystem/Src/DesignSystem.swift @@ -15,5 +15,6 @@ import Foundation @_exported import RxKeyboard @_exported import SnapKit @_exported import Then +@_exported import Lottie From 65d480ab5cf28ea863e14119062739cee832d075 Mon Sep 17 00:00:00 2001 From: LeeSeungmin Date: Fri, 22 Mar 2024 17:22:09 +0900 Subject: [PATCH 3/7] =?UTF-8?q?Update:=20refuse=20->=20reject=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Falling/Src/Subviews/CardButton.swift | 22 +++++++++---------- .../Src/Subviews/UserInfoBoxView.swift | 6 ++--- .../Src/Coordinator/LikeCoordinating.swift | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Projects/Features/Falling/Src/Subviews/CardButton.swift b/Projects/Features/Falling/Src/Subviews/CardButton.swift index 5dca3e38..bae55dd2 100644 --- a/Projects/Features/Falling/Src/Subviews/CardButton.swift +++ b/Projects/Features/Falling/Src/Subviews/CardButton.swift @@ -37,21 +37,21 @@ final class CardButton: UIButton { } enum CardButtonType { - case info, refuse, like + case info, reject, like var normalImage: UIImage? { switch self { case .info: return DSKitAsset.Image.Icons.cardInfo.image -// .resize(targetSize: .card)? + // .resize(targetSize: .card)? .withTintColor(DSKitAsset.Color.neutral50.color) - case .refuse: - return DSKitAsset.Image.Icons.cardRefuse.image -// .resize(targetSize: .card)? + case .reject: + return DSKitAsset.Image.Icons.cardReject.image + // .resize(targetSize: .card)? .withTintColor(DSKitAsset.Color.neutral50.color) case .like: return DSKitAsset.Image.Icons.cardLike.image -// .resize(targetSize: .card)? + // .resize(targetSize: .card)? .withTintColor(DSKitAsset.Color.error.color) } } @@ -60,15 +60,15 @@ final class CardButton: UIButton { switch self { case .info: return DSKitAsset.Image.Icons.cardInfo.image -// .resize(targetSize: .card)? + // .resize(targetSize: .card)? .withTintColor(DSKitAsset.Color.neutral50.color) - case .refuse: - return DSKitAsset.Image.Icons.cardRefuse.image -// .resize(targetSize: .card)? + case .reject: + return DSKitAsset.Image.Icons.cardReject.image + // .resize(targetSize: .card)? .withTintColor(DSKitAsset.Color.neutral50.color) case .like: return DSKitAsset.Image.Icons.cardLike.image -// .resize(targetSize: .card)? + // .resize(targetSize: .card)? .withTintColor(DSKitAsset.Color.neutral50.color) } } diff --git a/Projects/Features/Falling/Src/Subviews/UserInfoBoxView.swift b/Projects/Features/Falling/Src/Subviews/UserInfoBoxView.swift index 88736fe4..cd135d45 100644 --- a/Projects/Features/Falling/Src/Subviews/UserInfoBoxView.swift +++ b/Projects/Features/Falling/Src/Subviews/UserInfoBoxView.swift @@ -56,9 +56,7 @@ final class UserInfoBoxView: TFBaseView { }() lazy var infoButton = CardButton(type: .info) - - lazy var refuseButton = CardButton(type: .refuse) - + lazy var rejectButton = CardButton(type: .reject) lazy var likeButton = CardButton(type: .like) private lazy var spacerView = UIView() @@ -91,7 +89,7 @@ final class UserInfoBoxView: TFBaseView { $0.leading.trailing.equalToSuperview() } - [infoButton, spacerView, refuseButton, likeButton].forEach { subView in + [infoButton, spacerView, rejectButton, likeButton].forEach { subView in buttonStackView.addArrangedSubview(subView) subView.snp.makeConstraints { $0.size.equalTo(58) diff --git a/Projects/Features/Like/Interface/Src/Coordinator/LikeCoordinating.swift b/Projects/Features/Like/Interface/Src/Coordinator/LikeCoordinating.swift index e4f5df61..d34e7565 100644 --- a/Projects/Features/Like/Interface/Src/Coordinator/LikeCoordinating.swift +++ b/Projects/Features/Like/Interface/Src/Coordinator/LikeCoordinating.swift @@ -27,7 +27,7 @@ public enum LikeCoordinatorAction { case chatRoom case meetMoody case backBtnTap - case toRefuseBtnTap + case toRejectBtnTap case toChatBtnTap } From 5659dae9accb4276e31fb07c0f7d027052dccbbf Mon Sep 17 00:00:00 2001 From: LeeSeungmin Date: Fri, 22 Mar 2024 17:40:26 +0900 Subject: [PATCH 4/7] =?UTF-8?q?[#72]Feat:=20'x'=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - timer 클래스 생성 - timer에서 start()함수를 호출하면 disposable의 타이머 구독 생성 - pause에서는 현재 시간을 갱신하고 disposable의 구독을 해제하고 참조도 제거 - 로티 애니메이션 추가 - 디자인 변경으로 유저 카드 흔들리는 애니메이션 제거 - timeStart로 dimview를 hidden했었으나 currentTime이 BehaviorRelay로 되어 있어서 최초에 한 번 호출로 인해 dimview가 사라짐 - isTimerActive에서 처리하도록 해서 문제 해결 --- .../Cell/FallingUserCollectionViewCell.swift | 58 +++++---- .../FallinguserCollectionViewCellModel.swift | 118 +++++++++--------- 2 files changed, 89 insertions(+), 87 deletions(-) diff --git a/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift b/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift index a4017c66..d9523960 100644 --- a/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift +++ b/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift @@ -57,6 +57,14 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { return pauseView }() + lazy var rejectLottieView: LottieAnimationView = { + let lottieAnimationView = LottieAnimationView() + lottieAnimationView.animation = AnimationAsset.unlike.animation + lottieAnimationView.isHidden = true + lottieAnimationView.contentMode = .scaleAspectFit + return lottieAnimationView + }() + lazy var userInfoCollectionView: UserInfoCollectionView = { let collectionView = UserInfoCollectionView() collectionView.layer.cornerRadius = 20 @@ -69,11 +77,7 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { override func makeUI() { self.layer.cornerRadius = 20 - self.contentView.addSubview(profileCollectionView) - self.contentView.addSubview(cardTimeView) - self.contentView.addSubview(userInfoBoxView) - self.contentView.addSubview(userInfoCollectionView) - self.contentView.addSubview(pauseView) + self.contentView.addSubviews([profileCollectionView, cardTimeView, userInfoBoxView, userInfoBoxView, userInfoCollectionView, rejectLottieView, pauseView]) profileCollectionView.snp.makeConstraints { $0.edges.equalToSuperview() @@ -100,6 +104,11 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { $0.edges.equalToSuperview() } + self.rejectLottieView.snp.makeConstraints { + $0.center.equalToSuperview() + $0.width.height.equalTo(188) // TODO: 사이즈 수정 예정 + } + self.profileCollectionView.showDimView() self.setDataSource() @@ -111,14 +120,20 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { } func bind( - _ viewModel: FallinguserCollectionViewCellModel, + _ viewModel: FallingUserCollectionViewCellModel, timerActiveTrigger: Driver, timeOverSubject: PublishSubject, profileDoubleTapTriggerObserver: PublishSubject, fallingCellButtonAction: O ) where O: ObserverType, O.Element == FallingCellButtonAction { - let input = FallinguserCollectionViewCellModel.Input( - timerActiveTrigger: timerActiveTrigger + let rejectButtonTrigger = userInfoBoxView.rejectButton.rx.tap.mapToVoid().asDriverOnErrorJustEmpty() + + let likeButtonTrigger = userInfoBoxView.likeButton.rx.tap.mapToVoid().asDriverOnErrorJustEmpty() + + let input = FallingUserCollectionViewCellModel.Input( + timerActiveTrigger: timerActiveTrigger, + rejectButtonTrigger: rejectButtonTrigger, + likeButtonTrigger: likeButtonTrigger ) let output = viewModel @@ -132,17 +147,14 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { .drive(self.rx.timeState) .disposed(by: self.disposeBag) - output.timeStart - .drive(with: self) { owner, _ in - owner.profileCollectionView.hiddenDimView() - } - .disposed(by: disposeBag) - output.timeZero .drive(timeOverSubject) .disposed(by: disposeBag) output.isTimerActive + .do(onNext: { _ in + self.profileCollectionView.hiddenDimView() + }) .drive(pauseView.rx.isHidden) .disposed(by: disposeBag) @@ -175,24 +187,20 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { .disposed(by: disposeBag) userInfoBoxView.infoButton.rx.tap.asDriver() - .scan(true, accumulator: { value, _ in - return !value - }) + .scan(true) { value, _ in return !value } .drive(userInfoCollectionView.rx.isHidden) .disposed(by: disposeBag) - userInfoBoxView.refuseButton.rx.tapGesture() - .when(.recognized) + output.rejectButtonAction .compactMap { [weak self] _ in self?.indexPath } - .map { FallingCellButtonAction.refuse($0) } - .bind(to: fallingCellButtonAction) + .map { FallingCellButtonAction.reject($0) } + .drive(fallingCellButtonAction) .disposed(by: disposeBag) - userInfoBoxView.likeButton.rx.tapGesture() - .when(.recognized) + output.likeButtonAction .compactMap { [weak self] _ in self?.indexPath } .map { FallingCellButtonAction.like($0) } - .bind(to: fallingCellButtonAction) + .drive(fallingCellButtonAction) .disposed(by: disposeBag) } @@ -262,8 +270,6 @@ extension Reactive where Base: FallingUserCollectionViewCell { base.cardTimeView.timerView.dotLayer.position = base.dotPosition(progress: strokeEnd, rect: base.cardTimeView.timerView.bounds) base.cardTimeView.timerView.strokeLayer.strokeEnd = strokeEnd - - base.profileCollectionView.transform = base.profileCollectionView.transform.rotated(by: timeState.rotateAngle) } } diff --git a/Projects/Features/Falling/Src/Subviews/Cell/FallinguserCollectionViewCellModel.swift b/Projects/Features/Falling/Src/Subviews/Cell/FallinguserCollectionViewCellModel.swift index 0db5ab21..09bc9106 100644 --- a/Projects/Features/Falling/Src/Subviews/Cell/FallinguserCollectionViewCellModel.swift +++ b/Projects/Features/Falling/Src/Subviews/Cell/FallinguserCollectionViewCellModel.swift @@ -1,5 +1,5 @@ // -// FallinguserCollectionViewCellModel.swift +// FallingUserCollectionViewCellModel.swift // FallingInterface // // Created by SeungMin on 1/11/24. @@ -89,46 +89,40 @@ enum TimeState { return round((value / 2 - 1) / 5 * 1000) / 1000 } } +} + +final private class Timer { + private var disposable: Disposable? = nil - // .pi / 360 => 1도 - var rotateAngle: CGFloat { - switch self { - case .four: - // 8 10 => 초당 0.5도 (편도 / 2 1회) - return .pi / 360 / 200 - case .three(let value): - // 6 8 => 초당 2도 (왕복 1회) - let time = round((4-value/2) * 100) / 100 - if time <= 0.5 { return -.pi / 360 / 50 } - else { return .pi / 360 / 50 } - case .two(let value): - // 4 6 => 초당 4도 (왕복 2회) - let time = round((3-value/2) * 100) / 100 - if time <= 0.25 { return -.pi / 360 / 25 } - else if 0.25 < time && time <= 0.5 { return .pi / 360 / 25 } - else if 0.5 < time && time <= 0.75 { return -.pi / 360 / 25 } - else { return .pi / 360 / 25 } - case .one(let value): - // 2 4 => 초당 8도 (왕복 4회) - let time = round((2-value/2) * 1000) / 1000 - if time <= 0.125 { return -.pi / 360 / 12.5 } - else if 0.125 < time && time <= 0.25 { return .pi / 360 / 12.5 } - else if 0.25 < time && time <= 0.375 { return -.pi / 360 / 12.5 } - else if 0.375 < time && time <= 0.5 { return .pi / 360 / 12.5 } - else if 0.5 < time && time <= 0.625 { return -.pi / 360 / 12.5 } - else if 0.625 < time && time <= 0.75 { return .pi / 360 / 12.5 } - else if 0.75 < time && time <= 0.875 { return -.pi / 360 / 12.5 } - else { return .pi / 360 / 12.5 } - case .zero: - // 1 2 => 초당 1도 - return -.pi / 360 / 100 - default: - return 0 + let currentTime = BehaviorRelay(value: 13.0) + private var startTime: Double + + init(startTime: Double) { + self.startTime = startTime + } + + func start() { + guard disposable == nil else { return } + + disposable = Observable.interval(.milliseconds(10), + scheduler: MainScheduler.instance) + .take(Int(startTime * 100) + 1) + .map { [weak self] value in + guard let self = self else { return 0.0 } + return round((self.startTime * 100 - Double(value))) / 100 } + .debug() + .bind(to: currentTime) + } + + func pause() { + startTime = currentTime.value + disposable?.dispose() + disposable = nil } } -final class FallinguserCollectionViewCellModel: ViewModelType { +final class FallingUserCollectionViewCellModel: ViewModelType { let userDomain: FallingUser init(userDomain: FallingUser) { @@ -139,53 +133,55 @@ final class FallinguserCollectionViewCellModel: ViewModelType { struct Input { let timerActiveTrigger: Driver + let rejectButtonTrigger: Driver + let likeButtonTrigger: Driver } struct Output { let user: Driver let timeState: Driver - let timeStart: Driver let timeZero: Driver let isTimerActive: Driver + let rejectButtonAction: Driver + let likeButtonAction: Driver } func transform(input: Input) -> Output { - var currentTime: Double = 13.0 - var startTime: Double = 13.0 + let timer = Timer(startTime: 13.0) let user = Driver.just(self.userDomain) let timerActiveTrigger = input.timerActiveTrigger - .asObservable() - let timer = timerActiveTrigger - .flatMapLatest { value in + let rejectButtonAction = input.rejectButtonTrigger + .do(onNext: { _ in + timer.pause() + timer.currentTime.accept(-1.0) // reject 시에는 0.5초 후에 넘어 가야하는 제약이 있어서, 0초로 설정하지 않았고, reject 버튼 이벤트에 대한 처리는 상위 뷰에서 따로 처리하고 있음. + }) + + let likeButtonAction = input.likeButtonTrigger + + let timeActiveAction = timerActiveTrigger + .do { value in if !value { - startTime = currentTime // 타이머가 멈췄을 때 현재 시간으로 갱신 - return Driver.just(currentTime) + timer.pause() } else { - return Observable.interval(.milliseconds(10), - scheduler: MainScheduler.instance) - .take(Int(startTime * 100) + 1) // 시간의 총 개수 - .map { value in - currentTime = round((startTime * 100 - Double(value))) / 100 // 현재 시간 갱신 - return currentTime - } - .debug() - .asDriver(onErrorJustReturn: currentTime) + timer.start() } - }.asDriver(onErrorJustReturn: currentTime) + } + + let time = timer.currentTime.asDriver(onErrorJustReturn: 0.0) + + let timeState = time.map { TimeState(rawValue: $0) } + let timeZero = time.filter { $0 == 0.0 }.map { _ in } + let isTimerActive = timeActiveAction.asDriver(onErrorJustReturn: true) - let timeState = timer.map { TimeState(rawValue: $0) } - let timeStart = timer.filter { $0 == 13.0 }.map { _ in } - let timeZero = timer.filter { $0 == 0.0 }.map { _ in } - let isTimerActive = timerActiveTrigger.asDriver(onErrorJustReturn: true) - return Output( user: user, timeState: timeState, - timeStart: timeStart, timeZero: timeZero, - isTimerActive: isTimerActive + isTimerActive: isTimerActive, + rejectButtonAction: rejectButtonAction, + likeButtonAction: likeButtonAction ) } } From dbebe0df2f4daeb8bbb00d157c380f6e6fc8cd0d Mon Sep 17 00:00:00 2001 From: LeeSeungmin Date: Fri, 22 Mar 2024 17:43:55 +0900 Subject: [PATCH 5/7] =?UTF-8?q?[#72]Feat:=20'X'=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=EC=8B=9C,=200.5=EC=B4=88=20=EB=92=A4?= =?UTF-8?q?=EC=97=90=20=EB=8B=A4=EC=9D=8C=20=ED=99=94=EB=A9=B4=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=84=98=EC=96=B4=EA=B0=80=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 로티 애니메이션이 0.5초 간 지속되도록 설정 - 'x' 버튼이 클릭된 셀의 indexPath를 받아서 vc에 전달 - 로티를 표시하고 timeOverSubject emit --- .../Src/Home/FallingHomeViewController.swift | 21 +++++++-- .../Src/Home/FallingHomeViewModel.swift | 46 ++++++++++++------- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/Projects/Features/Falling/Src/Home/FallingHomeViewController.swift b/Projects/Features/Falling/Src/Home/FallingHomeViewController.swift index a4b269a7..324ddfc8 100644 --- a/Projects/Features/Falling/Src/Home/FallingHomeViewController.swift +++ b/Projects/Features/Falling/Src/Home/FallingHomeViewController.swift @@ -13,7 +13,7 @@ import FallingInterface enum FallingCellButtonAction { case info(IndexPath) - case refuse(IndexPath) + case reject(IndexPath) case like(IndexPath) } @@ -84,7 +84,7 @@ final class FallingHomeViewController: TFBaseViewController { .map { _, timerActiveFlag in timerActiveFlag } cell.bind( - FallinguserCollectionViewCellModel(userDomain: item), + FallingUserCollectionViewCellModel(userDomain: item), timerActiveTrigger: timerActiveTrigger, timeOverSubject: timeOverSubject, profileDoubleTapTriggerObserver: profileDoubleTapTriggerObserver, @@ -114,7 +114,7 @@ final class FallingHomeViewController: TFBaseViewController { var snapshot = Snapshot() snapshot.appendSections([.profile]) snapshot.appendItems(list) - owner.dataSource.apply(snapshot) + owner.dataSource.apply(snapshot, animatingDifferences: true) }).disposed(by: disposeBag) output.nextCardIndexPath @@ -127,13 +127,26 @@ final class FallingHomeViewController: TFBaseViewController { )}) .disposed(by: self.disposeBag) - output.info + output.infoButtonAction .drive(with: self) { owner, indexPath in guard let cell = owner.homeView.collectionView.cellForItem(at: indexPath) as? FallingUserCollectionViewCell else { return } cell.userInfoCollectionView.isHidden.toggle() } .disposed(by: disposeBag) + + output.rejectButtonAction + .drive(with: self) { owner, indexPath in + guard let cell = owner.homeView.collectionView.cellForItem(at: indexPath) as? FallingUserCollectionViewCell else { return } + + cell.rejectLottieView.isHidden = false + cell.rejectLottieView.play() + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + timeOverSubject.onNext(()) + } + } + .disposed(by: disposeBag) } } diff --git a/Projects/Features/Falling/Src/Home/FallingHomeViewModel.swift b/Projects/Features/Falling/Src/Home/FallingHomeViewModel.swift index c339a2a6..bda43970 100644 --- a/Projects/Features/Falling/Src/Home/FallingHomeViewModel.swift +++ b/Projects/Features/Falling/Src/Home/FallingHomeViewModel.swift @@ -13,45 +13,50 @@ import RxCocoa import Foundation final class FallingHomeViewModel: ViewModelType { - + private let fallingUseCase: FallingUseCaseInterface - + // weak var delegate: FallingHomeDelegate? - + var disposeBag: DisposeBag = DisposeBag() - + struct Input { let initialTrigger: Driver let timeOverTrigger: Driver let cellButtonAction: Driver } - + struct Output { let userList: Driver<[FallingUser]> let nextCardIndexPath: Driver - let info: Driver + let infoButtonAction: Driver + let rejectButtonAction: Driver } - + init(fallingUseCase: FallingUseCaseInterface) { self.fallingUseCase = fallingUseCase } - + func transform(input: Input) -> Output { let currentIndexRelay = BehaviorRelay(value: 0) let timeOverTrigger = input.timeOverTrigger - + let snapshot = BehaviorRelay<[FallingUser]>(value: []) + let usersResponse = input.initialTrigger .flatMapLatest { [unowned self] _ in self.fallingUseCase.user(alreadySeenUserUUIDList: [], userDailyFallingCourserIdx: 1, size: 100) .asDriver(onErrorJustReturn: .init(selectDailyFallingIdx: 0, topicExpirationUnixTime: 0, userInfos: [])) } - - let userList = usersResponse.map { $0.userInfos }.asDriver() - + + let userList = usersResponse.map { + snapshot.accept($0.userInfos) + return $0.userInfos + }.asDriver() + let updateUserListTrigger = userList.map { _ in currentIndexRelay.accept(currentIndexRelay.value) } - + let updateScrollIndexTrigger = timeOverTrigger.withLatestFrom(currentIndexRelay.asDriver(onErrorJustReturn: 0)) { _, index in currentIndexRelay.accept(index + 1) } @@ -62,17 +67,26 @@ final class FallingHomeViewModel: ViewModelType { ).withLatestFrom(currentIndexRelay.asDriver(onErrorJustReturn: 0) .map { IndexPath(row: $0, section: 0) }) - let info = input.cellButtonAction + let infoButtonAction = input.cellButtonAction .compactMap { action -> IndexPath? in if case let .info(indexPath) = action { return indexPath } else { return nil } } - + + let rejectButtonAction = input.cellButtonAction + .compactMap { action -> IndexPath? in + if case let .reject(indexPath) = action { + return indexPath + } + return nil + } + return Output( userList: userList, nextCardIndexPath: nextCardIndexPath, - info: info + infoButtonAction: infoButtonAction, + rejectButtonAction: rejectButtonAction ) } } From 82618be07c50cc4c3c3484142ebbbada91a2c8e3 Mon Sep 17 00:00:00 2001 From: LeeSeungmin Date: Sun, 24 Mar 2024 10:22:10 +0900 Subject: [PATCH 6/7] =?UTF-8?q?Update:=20UserInfoCollectionView=20->=20Use?= =?UTF-8?q?rInfoView=EB=A1=9C=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Src/Home/FallingHomeViewController.swift | 2 +- .../Cell/FallingUserCollectionViewCell.swift | 22 +++++++++---------- .../Src/Subviews/UserInfoCollectionView.swift | 6 ++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Projects/Features/Falling/Src/Home/FallingHomeViewController.swift b/Projects/Features/Falling/Src/Home/FallingHomeViewController.swift index 324ddfc8..4bd83d76 100644 --- a/Projects/Features/Falling/Src/Home/FallingHomeViewController.swift +++ b/Projects/Features/Falling/Src/Home/FallingHomeViewController.swift @@ -131,7 +131,7 @@ final class FallingHomeViewController: TFBaseViewController { .drive(with: self) { owner, indexPath in guard let cell = owner.homeView.collectionView.cellForItem(at: indexPath) as? FallingUserCollectionViewCell else { return } - cell.userInfoCollectionView.isHidden.toggle() + cell.userInfoView.isHidden.toggle() } .disposed(by: disposeBag) diff --git a/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift b/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift index d9523960..b6e0cc24 100644 --- a/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift +++ b/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift @@ -65,19 +65,19 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { return lottieAnimationView }() - lazy var userInfoCollectionView: UserInfoCollectionView = { - let collectionView = UserInfoCollectionView() - collectionView.layer.cornerRadius = 20 - collectionView.clipsToBounds = true - collectionView.collectionView.backgroundColor = DSKitAsset.Color.DimColor.default.color - collectionView.isHidden = true - return collectionView + lazy var userInfoView: UserInfoView = { + let view = UserInfoView() + view.layer.cornerRadius = 20 + view.clipsToBounds = true + view.collectionView.backgroundColor = DSKitAsset.Color.DimColor.default.color + view.isHidden = true + return view }() override func makeUI() { self.layer.cornerRadius = 20 - self.contentView.addSubviews([profileCollectionView, cardTimeView, userInfoBoxView, userInfoBoxView, userInfoCollectionView, rejectLottieView, pauseView]) + self.contentView.addSubviews([profileCollectionView, cardTimeView, userInfoBoxView, userInfoBoxView, userInfoView, rejectLottieView, pauseView]) profileCollectionView.snp.makeConstraints { $0.edges.equalToSuperview() @@ -94,7 +94,7 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { $0.bottom.equalToSuperview().inset(12) } - userInfoCollectionView.snp.makeConstraints { + userInfoView.snp.makeConstraints { $0.leading.trailing.equalToSuperview().inset(10) $0.height.equalTo(300) $0.bottom.equalTo(userInfoBoxView.snp.top).offset(-8) @@ -188,7 +188,7 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { userInfoBoxView.infoButton.rx.tap.asDriver() .scan(true) { value, _ in return !value } - .drive(userInfoCollectionView.rx.isHidden) + .drive(userInfoView.rx.isHidden) .disposed(by: disposeBag) output.rejectButtonAction @@ -277,7 +277,7 @@ extension Reactive where Base: FallingUserCollectionViewCell { return Binder(self.base) { (base, user) in base.bind(userProfilePhotos: user.userProfilePhotos) base.userInfoBoxView.bind(user) - base.userInfoCollectionView.bind(user) + base.userInfoView.bind(user) } } } diff --git a/Projects/Features/Falling/Src/Subviews/UserInfoCollectionView.swift b/Projects/Features/Falling/Src/Subviews/UserInfoCollectionView.swift index 3c1d3a23..02abb225 100644 --- a/Projects/Features/Falling/Src/Subviews/UserInfoCollectionView.swift +++ b/Projects/Features/Falling/Src/Subviews/UserInfoCollectionView.swift @@ -1,5 +1,5 @@ // -// UserInfoCollectionView.swift +// UserInfoView.swift // Falling // // Created by Kanghos on 2023/10/09. @@ -12,7 +12,7 @@ import DSKit import FallingInterface import Domain -final class UserInfoCollectionView: TFBaseView { +final class UserInfoView: TFBaseView { private var dataSource: DataSource! lazy var reportButton: UIButton = { @@ -62,7 +62,7 @@ final class UserInfoCollectionView: TFBaseView { // MARK: DiffableDataSource -extension UserInfoCollectionView { +extension UserInfoView { typealias ModelType = FallingUserInfoItem typealias SectionType = FallingUserInfoSection typealias DataSource = UICollectionViewDiffableDataSource From 7501b369212bd74ff70c6cdfb43d2af6c0ba3a97 Mon Sep 17 00:00:00 2001 From: LeeSeungmin Date: Fri, 29 Mar 2024 20:21:20 +0900 Subject: [PATCH 7/7] =?UTF-8?q?[#25]Enhance:=20=EC=8B=A4=20=EB=94=94?= =?UTF-8?q?=EB=B0=94=EC=9D=B4=EC=8A=A4=EC=97=90=EC=84=9C=20=EC=95=A0?= =?UTF-8?q?=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=A0=9C=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=81=EC=9A=A9=20=EC=95=88=20=EB=90=98=EB=8A=94?= =?UTF-8?q?=20=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - progess를 셋째자리까지 표현하면 오차가 발생해서 원하는대로 애니메이션이 적용되지 않음. - 또한 각도를 30도로 하게 되면 점과 선의 거리가 멀어 보여서 18도로 설정 --- .../Subviews/Cell/FallingUserCollectionViewCell.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift b/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift index b6e0cc24..165a8284 100644 --- a/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift +++ b/Projects/Features/Falling/Src/Subviews/Cell/FallingUserCollectionViewCell.swift @@ -214,10 +214,10 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell { } func dotPosition(progress: CGFloat, rect: CGRect) -> CGPoint { - let progress = round(progress * 100) / 100 // 오차를 줄이기 위함 let radius = CGFloat(rect.height / 2 - cardTimeView.timerView.strokeLayer.lineWidth / 2) - - var angle = 2 * CGFloat.pi * progress - CGFloat.pi / 2 + CGFloat.pi / 6 // 두 원의 중점과 원점이 이루는 각도를 30도로 가정 + + // 3 / 2 pi(정점 각도) -> - 1 / 2 pi(정점) + var angle = 2 * CGFloat.pi * progress - CGFloat.pi / 2 + CGFloat.pi / 10 // 두 원의 중점과 원점이 이루는 각도를 18도로 가정 if angle <= -CGFloat.pi / 2 || CGFloat.pi * 1.5 <= angle { angle = -CGFloat.pi / 2 // 정점 각도 } @@ -266,7 +266,9 @@ extension Reactive where Base: FallingUserCollectionViewCell { base.cardTimeView.progressView.progress = timeState.getProgress - let strokeEnd = timeState.getProgress + // 소수점 3번 째자리까지 표시하면 오차가 발생해서 2번 째자리까지만 표시 + let strokeEnd = round(timeState.getProgress * 100) / 100 + base.cardTimeView.timerView.dotLayer.position = base.dotPosition(progress: strokeEnd, rect: base.cardTimeView.timerView.bounds) base.cardTimeView.timerView.strokeLayer.strokeEnd = strokeEnd