Skip to content

Commit

Permalink
Merge pull request #1307 from wakmusic/1306-long-press-edit-mode
Browse files Browse the repository at this point in the history
๐Ÿ”€ :: (#1306) Long Press ํŽธ์ง‘๋ชจ๋“œ ์ง„์ž…์  ์ถ”๊ฐ€
  • Loading branch information
baekteun authored Oct 12, 2024
2 parents 3832e01 + 4a29ebb commit e7a1146
Show file tree
Hide file tree
Showing 16 changed files with 189 additions and 122 deletions.
8 changes: 4 additions & 4 deletions Projects/App/Support/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
<false/>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>naversearchapp</string>
<string>naversearchthirdlogin</string>
<string>naversearchapp</string>
<string>naversearchthirdlogin</string>
<string>youtube</string>
<string>youtubemusic</string>
</array>
Expand All @@ -74,8 +74,8 @@
<string>$(BASE_DEV_URL)</string>
<key>BASE_PROD_URL</key>
<string>$(BASE_PROD_URL)</string>
<key>CDN_DOMAIN_URL</key>
<string>$(CDN_DOMAIN_URL)</string>
<key>CDN_DOMAIN_URL</key>
<string>$(CDN_DOMAIN_URL)</string>
<key>GOOGLE_CLIENT_ID</key>
<string>$(GOOGLE_CLIENT_ID)</string>
<key>GOOGLE_URL_SCHEME</key>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ final class MyPlaylistDetailReactor: Reactor {
case editButtonDidTap
case privateButtonDidTap
case completionButtonDidTap
case didLongPressedPlaylist(IndexPath)
case restore
case itemDidMoved(Int, Int)
case forceSave
Expand Down Expand Up @@ -120,6 +121,9 @@ final class MyPlaylistDetailReactor: Reactor {
case .editButtonDidTap:
return beginEditing()

case let .didLongPressedPlaylist(indexPath):
return didLongPressedPlaylist(indexPath: indexPath)

case .privateButtonDidTap:
return updatePrivate()

Expand Down Expand Up @@ -244,6 +248,14 @@ private extension MyPlaylistDetailReactor {
])
}

func didLongPressedPlaylist(indexPath: IndexPath) -> Observable<Mutation> {
guard !currentState.isEditing else { return .empty() }
return .concat(
beginEditing(),
updateItemSelected(indexPath.row)
)
}

func endEditingWithSave() -> Observable<Mutation> {
let state = currentState
let currentPlaylists = state.playlistModels
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ final class MyPlaylistDetailViewController: BaseReactorViewController<MyPlaylist
$0.tableHeaderView = headerView
$0.separatorStyle = .none
$0.contentInset = .init(top: .zero, left: .zero, bottom: 60.0, right: .zero)
$0.allowsSelectionDuringEditing = true
}

private lazy var completionButton: RectangleButton = RectangleButton().then {
Expand Down Expand Up @@ -159,10 +160,6 @@ final class MyPlaylistDetailViewController: BaseReactorViewController<MyPlaylist
}
}

override func configureUI() {
super.configureUI()
}

override func bind(reactor: MyPlaylistDetailReactor) {
super.bind(reactor: reactor)
tableView.rx.setDelegate(self)
Expand Down Expand Up @@ -256,13 +253,17 @@ final class MyPlaylistDetailViewController: BaseReactorViewController<MyPlaylist

tableView.rx.itemSelected
.bind(with: self) { owner, indexPath in
if owner.reactor?.currentState.isEditing == true {
owner.tableView.deselectRow(at: IndexPath(row: indexPath.row, section: 0), animated: false)
owner.reactor?.action.onNext(.itemDidTap(indexPath.row))
} else {
guard let model = owner.dataSource.itemIdentifier(for: indexPath) else { return }

guard let model = owner.dataSource.itemIdentifier(for: indexPath) else { return }

PlayState.shared.append(item: .init(id: model.id, title: model.title, artist: model.artist))
let playlistIDs = PlayState.shared.currentPlaylist
.map(\.id)
owner.songDetailPresenter.present(ids: playlistIDs, selectedID: model.id)
PlayState.shared.append(item: .init(id: model.id, title: model.title, artist: model.artist))
let playlistIDs = PlayState.shared.currentPlaylist
.map(\.id)
owner.songDetailPresenter.present(ids: playlistIDs, selectedID: model.id)
}
}
.disposed(by: disposeBag)
}
Expand Down Expand Up @@ -533,6 +534,21 @@ extension MyPlaylistDetailViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false // ํŽธ์ง‘๋ชจ๋“œ ์‹œ ์…€์˜ ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ์—†์• ๋ ค๋ฉด false๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.
}

func tableView(
_ tableView: UITableView,
contextMenuConfigurationForRowAt indexPath: IndexPath,
point: CGPoint
) -> UIContextMenuConfiguration? {
if reactor?.currentState.isEditing == true {
return nil
} else {
return UIContextMenuConfiguration(identifier: nil, previewProvider: { [reactor] in
reactor?.action.onNext(.didLongPressedPlaylist(indexPath))
return nil
})
}
}
}

/// ์ „์ฒด์žฌ์ƒ , ๋žœ๋ค ์žฌ์ƒ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ
Expand Down Expand Up @@ -585,11 +601,6 @@ extension MyPlaylistDetailViewController: PlaylistTableViewCellDelegate {
playPlatform: model.title.isContainShortsTagTitle ? .youtube : .automatic
).play()
}

func superButtonTapped(index: Int) {
tableView.deselectRow(at: IndexPath(row: index, section: 0), animated: false)
reactor?.action.onNext(.itemDidTap(index))
}
}

/// swipe pop ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ , ํŽธ์ง‘๋ชจ๋“œ ์‹œ ๋ง‰๊ธฐ
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,21 @@ extension PlaylistViewController: UITableViewDelegate {
}
return proposedDestinationIndexPath
}

public func tableView(
_ tableView: UITableView,
contextMenuConfigurationForRowAt indexPath: IndexPath,
point: CGPoint
) -> UIContextMenuConfiguration? {
if output.editState.value == true {
return nil
} else {
return UIContextMenuConfiguration(identifier: nil, previewProvider: { [didLongPressedSongSubject] in
didLongPressedSongSubject.onNext(indexPath.row)
return nil
})
}
}
}

extension PlaylistViewController: PlaylistTableViewCellDelegate {
Expand All @@ -132,8 +147,4 @@ extension PlaylistViewController: PlaylistTableViewCellDelegate {
playPlatform: model.title.isContainShortsTagTitle ? .youtube : .automatic
).play()
}

func superButtonTapped(index: Int) {
tappedCellIndex.onNext(index)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public final class PlaylistViewController: UIViewController, SongCartViewType {
var isSelectedAllSongs = PublishSubject<Bool>()
var tappedAddPlaylist = PublishSubject<Void>()
var tappedRemoveSongs = PublishSubject<Void>()
var didLongPressedSongSubject = PublishSubject<Int>()

private(set) var containSongsFactory: any ContainSongsFactory
private(set) var songDetailPresenter: any SongDetailPresentable
Expand All @@ -48,7 +49,8 @@ public final class PlaylistViewController: UIViewController, SongCartViewType {
selectAllSongsButtonDidTapEvent: isSelectedAllSongs.asObservable(),
addPlaylistButtonDidTapEvent: tappedAddPlaylist.asObservable(),
removeSongsButtonDidTapEvent: tappedRemoveSongs.asObservable(),
itemMovedEvent: playlistView.playlistTableView.rx.itemMoved.asObservable()
itemMovedEvent: playlistView.playlistTableView.rx.itemMoved.asObservable(),
didLongPressedSongEvent: didLongPressedSongSubject
)
lazy var output = self.viewModel.transform(from: input)

Expand Down Expand Up @@ -220,18 +222,31 @@ private extension PlaylistViewController {

playlistView.playlistTableView.rx.itemSelected
.withLatestFrom(output.playlists) { ($0, $1) }
.map { $0.1[$0.0.row] }
.bind(with: self, onNext: { [songDetailPresenter] owner, item in
let currentSongs = output.playlists.value
.map(\.id)

owner.dismiss(animated: true) {
songDetailPresenter.present(
ids: Array(currentSongs),
selectedID: item.id
)
.bind(with: self) { [
songDetailPresenter,
isEditingSubject = output.editState,
tappedCellIndex
] owner, item in

let isEditing = isEditingSubject.value
let (indexPath, playlists) = item

if isEditing {
tappedCellIndex.onNext(indexPath.row)
} else {
guard let selectedSong = playlists[safe: indexPath.row] else { return }

let currentSongs = playlists
.map(\.id)

owner.dismiss(animated: true) {
songDetailPresenter.present(
ids: Array(currentSongs),
selectedID: selectedSong.id
)
}
}
})
}
.disposed(by: disposeBag)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ final class PlaylistViewModel: ViewModelType {
let addPlaylistButtonDidTapEvent: Observable<Void>
let removeSongsButtonDidTapEvent: Observable<Void>
let itemMovedEvent: Observable<(sourceIndex: IndexPath, destinationIndex: IndexPath)>
let didLongPressedSongEvent: Observable<Int>
}

struct Output {
Expand Down Expand Up @@ -152,6 +153,23 @@ final class PlaylistViewModel: ViewModelType {
playlists.insert(movedData, at: destIndex)
output.playlists.accept(playlists)
}.disposed(by: disposeBag)

input.didLongPressedSongEvent
.compactMap { output.playlists.value[safe: $0] }
.bind(with: self) { owner, item in
owner.isEditing.toggle()

var mutableSelectedSongIds = output.selectedSongIds.value
if mutableSelectedSongIds.contains(item.id) {
mutableSelectedSongIds.remove(item.id)
} else {
mutableSelectedSongIds.insert(item.id)
}

output.editState.send(owner.isEditing)
output.selectedSongIds.accept(mutableSelectedSongIds)
}
.disposed(by: disposeBag)
}

private func bindTableView(output: Output) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public final class PlaylistView: UIView {
$0.sectionHeaderTopPadding = 0
$0.backgroundColor = DesignSystemAsset.BlueGrayColor.blueGray100.color
$0.showsVerticalScrollIndicator = true
$0.allowsSelectionDuringEditing = true
}

override init(frame: CGRect) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import UIKit
import Utility

internal protocol PlaylistTableViewCellDelegate: AnyObject {
func superButtonTapped(index: Int)
func playButtonDidTap(model: PlaylistItemModel)
}

Expand Down Expand Up @@ -78,10 +77,6 @@ internal class PlaylistTableViewCell: UITableViewCell {
fatalError("")
}

override func prepareForReuse() {
super.prepareForReuse()
}

private func configureContents() {
self.backgroundColor = .clear
self.contentView.addSubview(self.thumbnailImageView)
Expand Down Expand Up @@ -110,11 +105,6 @@ internal class PlaylistTableViewCell: UITableViewCell {
$0.centerY.equalTo(contentView.snp.centerY)
$0.right.equalTo(contentView.snp.right).offset(-20)
}

superButton.snp.makeConstraints {
$0.left.top.bottom.equalToSuperview()
$0.right.equalToSuperview()
}
}
}

Expand Down Expand Up @@ -151,10 +141,6 @@ extension PlaylistTableViewCell {
owner.delegate?.playButtonDidTap(model: song)
}
.disposed(by: disposeBag)

superButton.addAction { [weak self] in
self?.delegate?.superButtonTapped(index: self?.model.index ?? 0)
}
}

private func updateButtonHidden(isEditing: Bool) {
Expand All @@ -163,7 +149,6 @@ extension PlaylistTableViewCell {
} else {
playImageView.isHidden = false
}
superButton.isHidden = !isEditing
}

private func updateConstraintPlayImageView(isEditing: Bool) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ final class LikeStorageReactor: Reactor {
case itemMoved(ItemMovedEvent)
case songDidTap(Int)
case tapAll(isSelecting: Bool)
case didLongPressedPlaylist(IndexPath)
case playDidTap(song: FavoriteSongEntity)
case addToPlaylistButtonDidTap // ๋…ธ๋ž˜๋‹ด๊ธฐ
case presentAddToPlaylistPopup
Expand Down Expand Up @@ -104,6 +105,9 @@ final class LikeStorageReactor: Reactor {
case let .songDidTap(index):
return changeSelectingState(index)

case let .didLongPressedPlaylist(indexPath):
return didLongPressedPlaylist(indexPath: indexPath)

case let .playDidTap(song):
return playWithAddToCurrentPlaylist(song: song)

Expand Down Expand Up @@ -285,6 +289,13 @@ extension LikeStorageReactor {
return .just(.showAddToPlaylistPopup(selectedItemIDs))
}

func didLongPressedPlaylist(indexPath: IndexPath) -> Observable<Mutation> {
guard !currentState.isEditing else { return .empty() }
storageCommonService.isEditingState.onNext(true)
changeSelectingState(indexPath.row)
return .just(.switchEditingState(true))
}

func presentAddToPlaylistPopup() -> Observable<Mutation> {
guard var tmp = currentState.dataSource.first?.items else {
LogManager.printError("favorite datasource is empty")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ final class ListStorageReactor: Reactor {
case viewDidLoad
case refresh
case itemMoved(ItemMovedEvent)
case cellDidTap(Int)
case listDidTap(IndexPath)
case didSelectPlaylist(IndexPath)
case didLongPressedPlaylist(IndexPath)
case playDidTap(Int)
case tapAll(isSelecting: Bool)
case loginButtonDidTap
Expand Down Expand Up @@ -117,11 +117,11 @@ final class ListStorageReactor: Reactor {
case let .itemMoved((sourceIndex, destinationIndex)):
return updateOrder(src: sourceIndex.row, dest: destinationIndex.row)

case let .cellDidTap(index):
return changeSelectingState(index)
case let .didSelectPlaylist(indexPath):
return didSelectPlaylistCell(indexPath: indexPath)

case let .listDidTap(indexPath):
return showDetail(indexPath)
case let .didLongPressedPlaylist(indexPath):
return didLongPressedPlaylist(indexPath: indexPath)

case let .playDidTap(index):
return playWithAddToCurrentPlaylist(index)
Expand Down Expand Up @@ -333,6 +333,23 @@ extension ListStorageReactor {
)
}

func didLongPressedPlaylist(indexPath: IndexPath) -> Observable<Mutation> {
guard !currentState.isEditing else { return .empty() }
storageCommonService.isEditingState.onNext(true)
return .concat(
changeSelectingState(indexPath.row),
.just(.switchEditingState(true))
)
}

func didSelectPlaylistCell(indexPath: IndexPath) -> Observable<Mutation> {
if currentState.isEditing {
return changeSelectingState(indexPath.row)
} else {
return showDetail(indexPath)
}
}

func showDetail(_ indexPath: IndexPath) -> Observable<Mutation> {
let selectedList = currentState.dataSource[indexPath.section].items[indexPath.row]
let key = selectedList.key
Expand Down
Loading

0 comments on commit e7a1146

Please sign in to comment.