Skip to content

Commit

Permalink
Merge pull request #73 from THT-Team/Feature/reject_action
Browse files Browse the repository at this point in the history
User Card 'X' 버튼 이벤트 구현
  • Loading branch information
Minny27 authored Apr 17, 2024
2 parents e00764a + 7501b36 commit beba149
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 141 deletions.
23 changes: 18 additions & 5 deletions Projects/Features/Falling/Src/Home/FallingHomeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import FallingInterface

enum FallingCellButtonAction {
case info(IndexPath)
case refuse(IndexPath)
case reject(IndexPath)
case like(IndexPath)
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -127,11 +127,24 @@ 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()
cell.userInfoView.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)
}
Expand Down
46 changes: 30 additions & 16 deletions Projects/Features/Falling/Src/Home/FallingHomeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Void>
let timeOverTrigger: Driver<Void>
let cellButtonAction: Driver<FallingCellButtonAction>
}

struct Output {
let userList: Driver<[FallingUser]>
let nextCardIndexPath: Driver<IndexPath>
let info: Driver<IndexPath>
let infoButtonAction: Driver<IndexPath>
let rejectButtonAction: Driver<IndexPath>
}

init(fallingUseCase: FallingUseCaseInterface) {
self.fallingUseCase = fallingUseCase
}

func transform(input: Input) -> Output {
let currentIndexRelay = BehaviorRelay<Int>(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)
}
Expand All @@ -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
)
}
}
22 changes: 11 additions & 11 deletions Projects/Features/Falling/Src/Subviews/CardButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand All @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,27 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell {
return pauseView
}()

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 rejectLottieView: LottieAnimationView = {
let lottieAnimationView = LottieAnimationView()
lottieAnimationView.animation = AnimationAsset.unlike.animation
lottieAnimationView.isHidden = true
lottieAnimationView.contentMode = .scaleAspectFit
return lottieAnimationView
}()

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.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, userInfoView, rejectLottieView, pauseView])

profileCollectionView.snp.makeConstraints {
$0.edges.equalToSuperview()
Expand All @@ -90,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)
Expand All @@ -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()
Expand All @@ -111,14 +120,20 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell {
}

func bind<O>(
_ viewModel: FallinguserCollectionViewCellModel,
_ viewModel: FallingUserCollectionViewCellModel,
timerActiveTrigger: Driver<Bool>,
timeOverSubject: PublishSubject<Void>,
profileDoubleTapTriggerObserver: PublishSubject<Void>,
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
Expand All @@ -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)

Expand Down Expand Up @@ -175,24 +187,20 @@ final class FallingUserCollectionViewCell: TFBaseCollectionViewCell {
.disposed(by: disposeBag)

userInfoBoxView.infoButton.rx.tap.asDriver()
.scan(true, accumulator: { value, _ in
return !value
})
.drive(userInfoCollectionView.rx.isHidden)
.scan(true) { value, _ in return !value }
.drive(userInfoView.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)
}

Expand All @@ -206,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 // 정점 각도
}
Expand Down Expand Up @@ -258,20 +266,20 @@ 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

base.profileCollectionView.transform = base.profileCollectionView.transform.rotated(by: timeState.rotateAngle)
}
}

var user: Binder<FallingUser> {
return Binder(self.base) { (base, user) in
base.bind(userProfilePhotos: user.userProfilePhotos)
base.userInfoBoxView.bind(user)
base.userInfoCollectionView.bind(user)
base.userInfoView.bind(user)
}
}
}
Loading

0 comments on commit beba149

Please sign in to comment.