Implement thread list long press actions, fix #5310

This commit is contained in:
ismailgulek 2022-01-05 13:26:13 +03:00
parent a69738266c
commit 36d1873c98
No known key found for this signature in database
GPG key ID: E96336D42D9470A9
9 changed files with 131 additions and 5 deletions

View file

@ -69,6 +69,10 @@ extension ThreadListCoordinator: ThreadListViewModelCoordinatorDelegate {
self.delegate?.threadListCoordinatorDidSelectThread(self, thread: thread)
}
func threadListViewModelDidSelectThreadViewInRoom(_ viewModel: ThreadListViewModelProtocol, thread: MXThread) {
self.delegate?.threadListCoordinatorDidSelectRoom(self, roomId: thread.roomId, eventId: thread.id)
}
func threadListViewModelDidCancel(_ viewModel: ThreadListViewModelProtocol) {
self.delegate?.threadListCoordinatorDidCancel(self)
}

View file

@ -21,6 +21,7 @@ import Foundation
protocol ThreadListCoordinatorDelegate: AnyObject {
func threadListCoordinatorDidLoadThreads(_ coordinator: ThreadListCoordinatorProtocol)
func threadListCoordinatorDidSelectThread(_ coordinator: ThreadListCoordinatorProtocol, thread: MXThread)
func threadListCoordinatorDidSelectRoom(_ coordinator: ThreadListCoordinatorProtocol, roomId: String, eventId: String)
func threadListCoordinatorDidCancel(_ coordinator: ThreadListCoordinatorProtocol)
}

View file

@ -25,5 +25,9 @@ enum ThreadListViewAction {
case showFilterTypes
case selectFilterType(_ type: ThreadListFilterType)
case selectThread(_ index: Int)
case longPressThread(_ index: Int)
case actionViewInRoom
case actionCopyLinkToThread
case actionShare
case cancel
}

View file

@ -20,9 +20,11 @@
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="X8K-NO-SQ3">
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<gestureRecognizers/>
<connections>
<outlet property="dataSource" destination="V8j-Lb-PgC" id="FCQ-5E-AuZ"/>
<outlet property="delegate" destination="V8j-Lb-PgC" id="Kxs-vj-1RW"/>
<outletCollection property="gestureRecognizers" destination="OxP-Mp-c6Z" appends="YES" id="371-L6-Skg"/>
</connections>
</tableView>
<view contentMode="scaleToFill" placeholderIntrinsicWidth="414" placeholderIntrinsicHeight="818" translatesAutoresizingMaskIntoConstraints="NO" id="7VY-m9-wCS" customClass="ThreadListEmptyView" customModule="Riot" customModuleProvider="target">
@ -52,6 +54,11 @@
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="zK0-v6-7Wt" userLabel="First Responder" sceneMemberID="firstResponder"/>
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="OxP-Mp-c6Z">
<connections>
<action selector="longPressed:" destination="V8j-Lb-PgC" id="rvv-ml-CSq"/>
</connections>
</pongPressGestureRecognizer>
</objects>
<point key="canvasLocation" x="-3198.5507246376815" y="-647.54464285714278"/>
</scene>

View file

@ -147,15 +147,19 @@ final class ThreadListViewController: UIViewController {
case .idle:
break
case .loading:
self.renderLoading()
renderLoading()
case .loaded:
self.renderLoaded()
renderLoaded()
case .empty(let viewModel):
self.renderEmptyView(withViewModel: viewModel)
renderEmptyView(withViewModel: viewModel)
case .showingFilterTypes:
self.renderShowingFilterTypes()
renderShowingFilterTypes()
case .showingLongPressActions:
renderShowingLongPressActions()
case .share(let string):
renderShare(string)
case .error(let error):
self.render(error: error)
render(error: error)
}
}
@ -214,6 +218,44 @@ final class ThreadListViewController: UIViewController {
self.present(alertController, animated: true, completion: nil)
}
private func renderShowingLongPressActions() {
let controller = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
controller.addAction(UIAlertAction(title: VectorL10n.roomEventActionViewInRoom,
style: .default,
handler: { [weak self] action in
guard let self = self else { return }
self.viewModel.process(viewAction: .actionViewInRoom)
}))
controller.addAction(UIAlertAction(title: VectorL10n.threadCopyLinkToThread,
style: .default,
handler: { [weak self] action in
guard let self = self else { return }
self.viewModel.process(viewAction: .actionCopyLinkToThread)
}))
controller.addAction(UIAlertAction(title: VectorL10n.roomEventActionShare,
style: .default,
handler: { [weak self] action in
guard let self = self else { return }
self.viewModel.process(viewAction: .actionShare)
}))
controller.addAction(UIAlertAction(title: VectorL10n.cancel,
style: .cancel,
handler: nil))
self.present(controller, animated: true, completion: nil)
}
private func renderShare(_ string: String) {
let activityVC = UIActivityViewController(activityItems: [string],
applicationActivities: nil)
activityVC.modalTransitionStyle = .coverVertical
present(activityVC, animated: true, completion: nil)
}
private func render(error: Error) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
@ -225,6 +267,22 @@ final class ThreadListViewController: UIViewController {
private func filterButtonTapped(_ sender: UIBarButtonItem) {
self.viewModel.process(viewAction: .showFilterTypes)
}
@IBAction private func longPressed(_ sender: UILongPressGestureRecognizer) {
guard sender.state == .began else {
return
}
let point = sender.location(in: threadsTableView)
guard let indexPath = threadsTableView.indexPathForRow(at: point) else {
return
}
guard let cell = threadsTableView.cellForRow(at: indexPath) else {
return
}
if cell.isHighlighted {
viewModel.process(viewAction: .longPressThread(indexPath.row))
}
}
}

View file

@ -31,6 +31,7 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
private var roomState: MXRoomState?
private var currentOperation: MXHTTPOperation?
private var longPressedThread: MXThread?
// MARK: Public
@ -73,6 +74,14 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
loadData()
case .selectThread(let index):
selectThread(index)
case .longPressThread(let index):
longPressThread(index)
case .actionViewInRoom:
actionViewInRoom()
case .actionCopyLinkToThread:
actionCopyLinkToThread()
case .actionShare:
actionShare()
case .cancel:
cancelOperations()
coordinatorDelegate?.threadListViewModelDidCancel(self)
@ -264,6 +273,42 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
coordinatorDelegate?.threadListViewModelDidSelectThread(self, thread: thread)
}
private func longPressThread(_ index: Int) {
guard index < threads.count else {
return
}
longPressedThread = threads[index]
viewState = .showingLongPressActions
}
private func actionViewInRoom() {
guard let thread = longPressedThread else {
return
}
coordinatorDelegate?.threadListViewModelDidSelectThreadViewInRoom(self, thread: thread)
longPressedThread = nil
}
private func actionCopyLinkToThread() {
guard let thread = longPressedThread else {
return
}
if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId) {
MXKPasteboardManager.shared.pasteboard.string = permalink
}
longPressedThread = nil
}
private func actionShare() {
guard let thread = longPressedThread else {
return
}
if let permalink = MXTools.permalink(toEvent: thread.id, inRoom: thread.roomId) {
viewState = .share(permalink)
}
longPressedThread = nil
}
private func cancelOperations() {
self.currentOperation?.cancel()
}

View file

@ -25,6 +25,7 @@ protocol ThreadListViewModelViewDelegate: AnyObject {
protocol ThreadListViewModelCoordinatorDelegate: AnyObject {
func threadListViewModelDidLoadThreads(_ viewModel: ThreadListViewModelProtocol)
func threadListViewModelDidSelectThread(_ viewModel: ThreadListViewModelProtocol, thread: MXThread)
func threadListViewModelDidSelectThreadViewInRoom(_ viewModel: ThreadListViewModelProtocol, thread: MXThread)
func threadListViewModelDidCancel(_ viewModel: ThreadListViewModelProtocol)
}

View file

@ -25,5 +25,7 @@ enum ThreadListViewState {
case loaded
case empty(_ viewModel: ThreadListEmptyViewModel)
case showingFilterTypes
case showingLongPressActions
case share(_ string: String)
case error(Error)
}

View file

@ -151,6 +151,10 @@ extension ThreadsCoordinator: ThreadListCoordinatorDelegate {
self.add(childCoordinator: roomCoordinator)
}
func threadListCoordinatorDidSelectRoom(_ coordinator: ThreadListCoordinatorProtocol, roomId: String, eventId: String) {
self.delegate?.threadsCoordinatorDidSelect(self, roomId: roomId, eventId: eventId)
}
func threadListCoordinatorDidCancel(_ coordinator: ThreadListCoordinatorProtocol) {
self.delegate?.threadsCoordinatorDidComplete(self)
}