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

게시글 삭제 기능 구현 및 BoardBottomSheet 추상화 #369

Merged
merged 3 commits into from
May 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions PLUB.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
BA2173B929F57A97000D72B1 /* DeleteImageUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA2173B829F57A97000D72B1 /* DeleteImageUseCase.swift */; };
BA2173BB29F61955000D72B1 /* UploadArchiveUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA2173BA29F61955000D72B1 /* UploadArchiveUseCase.swift */; };
BA2173BD29F61A36000D72B1 /* EditArchiveUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA2173BC29F61A36000D72B1 /* EditArchiveUseCase.swift */; };
BA2553282A0F961600194B5A /* DeleteFeedUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA2553272A0F961600194B5A /* DeleteFeedUseCase.swift */; };
BA3001E429FF98E300C3FB89 /* DeleteArchiveUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3001E329FF98E300C3FB89 /* DeleteArchiveUseCase.swift */; };
BA340E1629782207002BAF2C /* IntroduceTagCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA340E1529782207002BAF2C /* IntroduceTagCollectionViewCell.swift */; };
BA340E1C297822CC002BAF2C /* IntroduceCategoryInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA340E1B297822CC002BAF2C /* IntroduceCategoryInfoView.swift */; };
Expand Down Expand Up @@ -558,6 +559,7 @@
BA2173B829F57A97000D72B1 /* DeleteImageUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteImageUseCase.swift; sourceTree = "<group>"; };
BA2173BA29F61955000D72B1 /* UploadArchiveUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadArchiveUseCase.swift; sourceTree = "<group>"; };
BA2173BC29F61A36000D72B1 /* EditArchiveUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditArchiveUseCase.swift; sourceTree = "<group>"; };
BA2553272A0F961600194B5A /* DeleteFeedUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteFeedUseCase.swift; sourceTree = "<group>"; };
BA3001E329FF98E300C3FB89 /* DeleteArchiveUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteArchiveUseCase.swift; sourceTree = "<group>"; };
BA340E1529782207002BAF2C /* IntroduceTagCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroduceTagCollectionViewCell.swift; sourceTree = "<group>"; };
BA340E1B297822CC002BAF2C /* IntroduceCategoryInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroduceCategoryInfoView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1377,6 +1379,7 @@
isa = PBXGroup;
children = (
BA57F3F529ED30D200A9F790 /* DeleteCommentUseCase.swift */,
BA2553272A0F961600194B5A /* DeleteFeedUseCase.swift */,
BA5EC6C529EFD4E5000A68B7 /* EditCommentUseCase.swift */,
BAB2E56D29E30F96006B7BDC /* GetCommentsUseCase.swift */,
BA5F050129F7D26500A3FA14 /* GetFeedDetailUseCase.swift */,
Expand Down Expand Up @@ -2798,6 +2801,7 @@
705F81C329AFAA3B00830C4F /* BoardViewController.swift in Sources */,
BAE5D3352975B10F00268D44 /* ReissuanceRequest.swift in Sources */,
BA57F3FA29ED4EEC00A9F790 /* ArchiveUploadViewModel.swift in Sources */,
BA2553282A0F961600194B5A /* DeleteFeedUseCase.swift in Sources */,
70197B6E29535BAA000503F6 /* HomeViewModel.swift in Sources */,
BA5D9ED929E3F16900F06AB5 /* ArchiveContent.swift in Sources */,
70F1DFE0297A90AE00F9BC83 /* MeetingService.swift in Sources */,
Expand Down
29 changes: 29 additions & 0 deletions PLUB/Sources/UseCases/Feeds/DeleteFeedUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// DeleteFeedUseCase.swift
// PLUB
//
// Created by 홍승현 on 2023/05/13.
//

import RxSwift

protocol DeleteFeedUseCase {
func execute() -> Observable<Void>
}

final class DefaultDeleteFeedUseCase: DeleteFeedUseCase {

private let plubbingID: Int
private let feedID: Int

init(plubbingID: Int, feedID: Int) {
self.plubbingID = plubbingID
self.feedID = feedID
}


func execute() -> Observable<Void> {
FeedsService.shared.deleteFeed(plubbingID: plubbingID, feedID: feedID)
.map { _ in Void() }
}
}
13 changes: 10 additions & 3 deletions PLUB/Sources/Views/Home/Clipboard/BoardDetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,18 @@ final class BoardDetailViewController: BaseViewController {

viewModel.showBoardBottomSheetObservable
.subscribe(with: self) { owner, tuple in
let (accessType, isPinned) = tuple
let viewController = BoardBottomSheetViewController(accessType: accessType, isPinned: isPinned)
let (bottomSheetType, accessType, isPinned) = tuple
let viewController = bottomSheetType.init(accessType: accessType, isPinned: isPinned)
viewController.delegate = owner
owner.present(viewController, animated: true)
}
.disposed(by: disposeBag)

viewModel.popViewControllerByMySelfObservable
.subscribe(with: self) { owner, _ in
owner.navigationController?.popViewController(animated: true)
}
.disposed(by: disposeBag)
}
}

Expand Down Expand Up @@ -211,7 +217,8 @@ extension BoardDetailViewController: CommentOptionBottomSheetDelegate {

extension BoardDetailViewController: BoardBottomSheetDelegate {
func selectedBoardSheetType(type: BoardBottomSheetType) {
PLUBToast.makeToast(text: "\(type)")
viewModel.boardOptionObserver.onNext(type)
dismiss(animated: true)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ protocol BoardDetailViewModelType: BoardDetailViewModel {
/// 댓(답)글, 댓글 수정, 댓글 삭제의 옵션을 처리할 경우 해당 옵저버를 이용합니다.
var commentOptionObserver: AnyObserver<CommentOption> { get }

var boardOptionObserver: AnyObserver<BoardBottomSheetType> { get }

//Output

/// 수정할 댓글의 정보를 전달합니다.
Expand All @@ -42,7 +44,9 @@ protocol BoardDetailViewModelType: BoardDetailViewModel {

var showCommentBottomSheetObservable: Observable<(commentID: Int, userType: CommentOptionBottomSheetViewController.UserAccessType)> { get }

var showBoardBottomSheetObservable: Observable<(BoardBottomSheetViewController.AccessType, Bool)> { get }
var showBoardBottomSheetObservable: Observable<(BoardBottomSheetViewControllerType.Type, BoardBottomSheetViewController.AccessType, Bool)> { get }

var popViewControllerByMySelfObservable: Observable<Void> { get }
}

protocol FeedLikeDelegate: AnyObject {
Expand Down Expand Up @@ -77,12 +81,13 @@ final class BoardDetailViewModel {

// MARK: Use Cases

private let deleteFeedUseCase: DeleteFeedUseCase
private let getFeedDetailUseCase: GetFeedDetailUseCase
private let getCommentsUseCase: GetCommentsUseCase
private let postCommentUseCase: PostCommentUseCase
private let getCommentsUseCase: GetCommentsUseCase
private let postCommentUseCase: PostCommentUseCase
private let deleteCommentUseCase: DeleteCommentUseCase
private let editCommentUseCase: EditCommentUseCase
private let likeFeedUseCase: LikeFeedUseCase
private let editCommentUseCase: EditCommentUseCase
private let likeFeedUseCase: LikeFeedUseCase

// MARK: Subjects

Expand All @@ -92,34 +97,40 @@ final class BoardDetailViewModel {
private let decoratorNameSubject = PublishSubject<(labelText: String, buttonText: String)>()
private let bottomCellSubject = PublishSubject<(collectionViewHeight: CGFloat, offset: CGFloat)>()
private let showCommentBottomSheetSubject = PublishSubject<(commentID: Int, userType: CommentOptionBottomSheetViewController.UserAccessType)>()
private let boardBottomSheetParameterSubject = ReplaySubject<(BoardBottomSheetViewController.AccessType, Bool)>.create(bufferSize: 1)
private let boardBottomSheetParameterSubject = PublishSubject<(BoardBottomSheetViewControllerType.Type, BoardBottomSheetViewController.AccessType, Bool)>()
private let boardOptionTappedSubject = PublishSubject<Void>()
private let popViewControllerByMySelfSubject = PublishSubject<Void>()
private let boardOptionInputSubject = PublishSubject<BoardBottomSheetType>()
private let targetIDSubject = BehaviorSubject<Int?>(value: nil)
private let deleteIDSubject = PublishSubject<Int>()
private let commentOptionSubject = BehaviorSubject<CommentOption>(value: .commentOrReply)

// MARK: - Initializations

init(
boardBottomSheetController: BoardBottomSheetViewControllerType.Type,
deleteFeedUseCase: DeleteFeedUseCase,
getFeedDetailUseCase: GetFeedDetailUseCase,
getCommentsUseCase: GetCommentsUseCase,
postCommentUseCase: PostCommentUseCase,
deleteCommentUseCase: DeleteCommentUseCase,
editCommentUseCase: EditCommentUseCase,
likeFeedUseCase: LikeFeedUseCase
) {
self.deleteFeedUseCase = deleteFeedUseCase
self.getFeedDetailUseCase = getFeedDetailUseCase
self.getCommentsUseCase = getCommentsUseCase
self.postCommentUseCase = postCommentUseCase
self.deleteCommentUseCase = deleteCommentUseCase
self.editCommentUseCase = editCommentUseCase
self.likeFeedUseCase = likeFeedUseCase

fetchInitialStateUI()
fetchInitialStateUI(boardBottomSheetController: boardBottomSheetController)
createComments()
pagingSetup()
deleteComments()
editComments()
boardOptionProcess()
}

private let disposeBag = DisposeBag()
Expand All @@ -130,7 +141,7 @@ final class BoardDetailViewModel {
extension BoardDetailViewModel {

/// 댓글 정보를 가져와 초기 상태의 UI를 업데이트합니다.
private func fetchInitialStateUI() {
private func fetchInitialStateUI(boardBottomSheetController: BoardBottomSheetViewControllerType.Type) {

let feedObservable = getFeedDetailUseCase.execute()

Expand All @@ -157,7 +168,7 @@ extension BoardDetailViewModel {
} else {
accessType = .normal
}
owner.boardBottomSheetParameterSubject.onNext((accessType, tuple.feed.isPinned))
owner.boardBottomSheetParameterSubject.onNext((boardBottomSheetController, accessType, tuple.feed.isPinned))

owner.comments.formUnion(tuple.comments) // 댓글 삽입
owner.setCollectionView(tuple.collectionView, content: tuple.feed.toBoardModel)
Expand Down Expand Up @@ -297,6 +308,20 @@ extension BoardDetailViewModel {
}
.disposed(by: disposeBag)
}

/// 게시글 설정 파이프라인입니다.
/// 게시글 삭제, 게시글 수정, 게시글 신고 로직이 들어가 있습니다.
private func boardOptionProcess() {
let sharedBoardOptionSubject = boardOptionInputSubject.share()

sharedBoardOptionSubject
.filter { $0 == .delete }
.flatMap { [deleteFeedUseCase] _ in deleteFeedUseCase.execute() }
.do { _ in PLUBToast.makeToast(text: "게시글이 삭제되었습니다.") }
.bind(to: popViewControllerByMySelfSubject)
.disposed(by: disposeBag)

}
}

// MARK: - BoardDetailViewModelType
Expand Down Expand Up @@ -329,6 +354,10 @@ extension BoardDetailViewModel: BoardDetailViewModelType {
commentOptionSubject.asObserver()
}

var boardOptionObserver: AnyObserver<BoardBottomSheetType> {
boardOptionInputSubject.asObserver()
}

// Output

var editCommentTextObservable: Observable<String> {
Expand All @@ -343,10 +372,14 @@ extension BoardDetailViewModel: BoardDetailViewModelType {
showCommentBottomSheetSubject.asObservable()
}

var showBoardBottomSheetObservable: Observable<(BoardBottomSheetViewController.AccessType, Bool)> {
var showBoardBottomSheetObservable: Observable<(BoardBottomSheetViewControllerType.Type, BoardBottomSheetViewController.AccessType, Bool)> {
boardOptionTappedSubject
.withLatestFrom(boardBottomSheetParameterSubject)
}

var popViewControllerByMySelfObservable: Observable<Void> {
popViewControllerByMySelfSubject.asObservable()
}
}

// MARK: - Diffable DataSource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ final class BoardDetailViewModelWithFeedsFactory: BoardDetailViewModelFactory {

static func make(plubbingID: Int, feedID: Int) -> BoardDetailViewModelType {
return BoardDetailViewModel(
boardBottomSheetController: BoardBottomSheetViewController.self,
deleteFeedUseCase: DefaultDeleteFeedUseCase(plubbingID: plubbingID, feedID: feedID),
getFeedDetailUseCase: DefaultGetFeedDetailUseCase(plubbingID: plubbingID, feedID: feedID),
getCommentsUseCase: DefaultGetCommentsUseCase(plubbingID: plubbingID, feedID: feedID),
postCommentUseCase: DefaultPostCommentUseCase(plubbingID: plubbingID, feedID: feedID),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,24 @@ protocol BoardBottomSheetDelegate: AnyObject {
func selectedBoardSheetType(type: BoardBottomSheetType)
}


// MARK: 바텀시트 추상화

protocol BoardBottomSheetViewControllerType: BottomSheetViewController {

init(accessType: BoardBottomSheetViewController.AccessType, isPinned: Bool)

var delegate: BoardBottomSheetDelegate? { get set }
}

enum BoardBottomSheetType {
case fix // 클립보드 고정
case modify // 게시글 수정
case report // 게시글 신고
case delete // 게시글 삭제
}

final class BoardBottomSheetViewController: BottomSheetViewController {
final class BoardBottomSheetViewController: BottomSheetViewController, BoardBottomSheetViewControllerType {

// MARK: - Properties

Expand Down