Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Card 'X' 버튼 이벤트 구현 #73

Merged
merged 16 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
11 changes: 10 additions & 1 deletion Projects/Domain/Src/Model/User/EmojiType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation

// MARK: - List
public struct EmojiType {
public struct EmojiType: Hashable {
public let identifier = UUID()
public let idx: Int
public let name, emojiCode: String
Expand All @@ -19,3 +19,12 @@ public struct EmojiType {
self.emojiCode = emojiCode
}
}

extension EmojiType {
public func hash(into hasher: inout Hasher) {
hasher.combine(identifier)
}
public static func == (lhs: EmojiType, rhs: EmojiType) -> Bool {
lhs.identifier == rhs.identifier
}
}
32 changes: 32 additions & 0 deletions Projects/Features/Falling/Interface/Src/Model/FallingUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,38 @@ public enum FallingProfileSection {
case profile
}

public enum FallingUserInfoSection: Int {
case interest
case ideal
case introduction

public var title: String {
switch self {
case .interest:
return "내 관심사"
case .ideal:
return "내 이상형"
case .introduction:
return "자기소개"
}
}
}

public enum FallingUserInfoItem: Hashable {
case interest(EmojiType)
case ideal(EmojiType)
case introduction(String)

public var item: Any {
switch self {
case .interest(let item), .ideal(let item):
return item
case .introduction(let item):
return item
}
}
}

public struct FallingUserInfo {
public let selectDailyFallingIdx, topicExpirationUnixTime: Int
public let userInfos: [FallingUser]
Expand Down
6 changes: 1 addition & 5 deletions Projects/Features/Falling/Src/Home/FallingHomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import UIKit
import Core
import DSKit

enum ElementKind: String {
case badge, header, footer
}

final class FallingHomeView: TFBaseView {
lazy var collectionView: UICollectionView = {
let flowLayout = UICollectionViewCompositionalLayout.verticalListLayout(withEstimatedHeight: ((UIWindow.keyWindow?.frame.width ?? 0) - 32) * 1.64)
Expand Down Expand Up @@ -69,7 +65,7 @@ extension NSCollectionLayoutSection {
heightDimension: .estimated(((UIWindow.keyWindow?.frame.width ?? 0) - 32) * 1.64))
let sectionFooter = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: footerSize,
elementKind: ElementKind.footer.rawValue,
elementKind: UICollectionView.elementKindSectionFooter,
alignment: .bottom
)

Expand Down
54 changes: 42 additions & 12 deletions Projects/Features/Falling/Src/Home/FallingHomeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import Core
import DSKit
import FallingInterface

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

final class FallingHomeViewController: TFBaseViewController {
private let viewModel: FallingHomeViewModel
private var dataSource: DataSource!
Expand Down Expand Up @@ -47,24 +53,25 @@ final class FallingHomeViewController: TFBaseViewController {

let initialTrigger = Driver<Void>.just(())
let timerOverTrigger = timeOverSubject.asDriverOnErrorJustEmpty()
let fallingCellButtonAction = PublishSubject<FallingCellButtonAction>()

let viewWillDisAppearTrigger = self.rx.viewWillDisAppear.map { _ in false }.asDriverOnErrorJustEmpty()
let timerActiveRelay = BehaviorRelay(value: true)
let cardDoubleTapTrigger = self.homeView.collectionView.rx
.tapGesture(configuration: { gestureRecognizer, delegate in
gestureRecognizer.numberOfTapsRequired = 2
})
.when(.recognized)
let profileDoubleTapTriggerObserver = PublishSubject<Void>()

let profileDoubleTapTrigger = profileDoubleTapTriggerObserver
.withLatestFrom(timerActiveRelay) { !$1 }
.asDriverOnErrorJustEmpty()

Driver.merge(cardDoubleTapTrigger, viewWillDisAppearTrigger)
Driver.merge(profileDoubleTapTrigger, viewWillDisAppearTrigger)
.drive(timerActiveRelay)
.disposed(by: disposeBag)

let input = FallingHomeViewModel.Input(
initialTrigger: initialTrigger,
timeOverTrigger: timerOverTrigger)
timeOverTrigger: timerOverTrigger,
cellButtonAction: fallingCellButtonAction.asDriverOnErrorJustEmpty()
)

let output = viewModel.transform(input: input)

Expand All @@ -77,14 +84,16 @@ final class FallingHomeViewController: TFBaseViewController {
.map { _, timerActiveFlag in timerActiveFlag }

cell.bind(
FallinguserCollectionViewCellModel(userDomain: item),
timerActiveTrigger,
scrollToNextObserver: timeOverSubject
FallingUserCollectionViewCellModel(userDomain: item),
timerActiveTrigger: timerActiveTrigger,
timeOverSubject: timeOverSubject,
profileDoubleTapTriggerObserver: profileDoubleTapTriggerObserver,
fallingCellButtonAction: fallingCellButtonAction
)
}

let footerRegistration = UICollectionView.SupplementaryRegistration
<UICollectionReusableView>(elementKind: ElementKind.footer.rawValue) { _,_,_ in }
<UICollectionReusableView>(elementKind: UICollectionView.elementKindSectionFooter) { _,_,_ in }

dataSource = DataSource(collectionView: homeView.collectionView, cellProvider: { collectionView, indexPath, itemIdentifier in
return collectionView.dequeueConfiguredReusableCell(using: profileCellRegistration, for: indexPath, item: itemIdentifier)
Expand All @@ -105,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 @@ -117,6 +126,27 @@ final class FallingHomeViewController: TFBaseViewController {
animated: true
)})
.disposed(by: self.disposeBag)

output.infoButtonAction
.drive(with: self) { owner, indexPath in
guard let cell = owner.homeView.collectionView.cellForItem(at: indexPath) as? FallingUserCollectionViewCell
else { return }
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
52 changes: 38 additions & 14 deletions Projects/Features/Falling/Src/Home/FallingHomeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,43 +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 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 @@ -59,10 +66,27 @@ final class FallingHomeViewModel: ViewModelType {
updateScrollIndexTrigger
).withLatestFrom(currentIndexRelay.asDriver(onErrorJustReturn: 0)
.map { IndexPath(row: $0, section: 0) })


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
nextCardIndexPath: nextCardIndexPath,
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
Loading