diff --git a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6abad0a50..cd64251b6 100644 --- a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,7 +23,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift", "state" : { - "revision" : "a4a7ad46b76cfb8de4695c5fd211a735cb438e1a" + "revision" : "b8d55afebfaae94b32bc3deeb1607eb150442e1f" } }, { diff --git a/Riot/Modules/Room/RoomViewController.swift b/Riot/Modules/Room/RoomViewController.swift index dc17e93ed..d1745dc6b 100644 --- a/Riot/Modules/Room/RoomViewController.swift +++ b/Riot/Modules/Room/RoomViewController.swift @@ -15,6 +15,7 @@ // import UIKit +import WysiwygComposer extension RoomViewController { // MARK: - Override @@ -290,17 +291,28 @@ private extension RoomViewController { } extension RoomViewController: ComposerLinkActionBridgePresenterDelegate { + func didRequestLinkOperation(_ linkOperation: WysiwygLinkOperation) { + dismissPresenter { [weak self] in + self?.wysiwygInputToolbar?.performLinkOperation(linkOperation) + } + } + func didDismissInteractively() { - self.cleanup() + cleanup() } func didCancel() { + dismissPresenter(completion: nil) + } + + private func dismissPresenter(completion: (() -> Void)?) { self.composerLinkActionBridgePresenter?.dismiss(animated: true) { [weak self] in + completion?() self?.cleanup() } } private func cleanup() { - self.composerLinkActionBridgePresenter = nil + composerLinkActionBridgePresenter = nil } } diff --git a/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift b/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift index 3399acce4..b282b608e 100644 --- a/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift +++ b/Riot/Modules/Room/Views/WYSIWYGInputToolbar/WysiwygInputToolbarView.swift @@ -212,6 +212,13 @@ class WysiwygInputToolbarView: MXKRoomInputToolbarView, NibLoadable, HtmlRoomInp wysiwygViewModel.maximised = false } + func performLinkOperation(_ linkOperation: WysiwygLinkOperation) { + if let selectionToRestore = viewModel.selectionToRestore { + wysiwygViewModel.attributedContent.selection = selectionToRestore + } + wysiwygViewModel.applyLinkOperation(linkOperation) + } + // MARK: - Private @objc private func keyboardWillShow(_ notification: Notification) { diff --git a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Coodinator/ComposerLinkActionBridgePresenter.swift b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Coodinator/ComposerLinkActionBridgePresenter.swift index f7486d50b..b0c69c221 100644 --- a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Coodinator/ComposerLinkActionBridgePresenter.swift +++ b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Coodinator/ComposerLinkActionBridgePresenter.swift @@ -20,6 +20,7 @@ import WysiwygComposer protocol ComposerLinkActionBridgePresenterDelegate: AnyObject { func didCancel() func didDismissInteractively() + func didRequestLinkOperation(_ linkOperation: WysiwygLinkOperation) } final class ComposerLinkActionBridgePresenter: NSObject { @@ -41,6 +42,8 @@ final class ComposerLinkActionBridgePresenter: NSObject { self?.delegate?.didCancel() case .didDismissInteractively: self?.delegate?.didDismissInteractively() + case let .didRequestLinkOperation(linkOperation): + self?.delegate?.didRequestLinkOperation(linkOperation) } } let presentable = composerLinkActionCoordinator.toPresentable() diff --git a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Coodinator/ComposerLinkActionCoordinator.swift b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Coodinator/ComposerLinkActionCoordinator.swift index ae9eb099f..c3bd7406e 100644 --- a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Coodinator/ComposerLinkActionCoordinator.swift +++ b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Coodinator/ComposerLinkActionCoordinator.swift @@ -20,6 +20,7 @@ import WysiwygComposer enum ComposerLinkActionCoordinatorAction { case didTapCancel case didDismissInteractively + case didRequestLinkOperation(_ linkOperation: WysiwygLinkOperation) } final class ComposerLinkActionCoordinator: NSObject, Coordinator, Presentable { @@ -42,10 +43,12 @@ final class ComposerLinkActionCoordinator: NSObject, Coordinator, Presentable { switch result { case .cancel: self?.callback?(.didTapCancel) + case let .performOperation(linkOperation): + self?.callback?(.didRequestLinkOperation(linkOperation)) } } } - + func toPresentable() -> UIViewController { hostingController } diff --git a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Model/ComposerLinkActionModel.swift b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Model/ComposerLinkActionModel.swift index 722b80ce6..c91462a09 100644 --- a/RiotSwiftUI/Modules/Room/Composer/LinkAction/Model/ComposerLinkActionModel.swift +++ b/RiotSwiftUI/Modules/Room/Composer/LinkAction/Model/ComposerLinkActionModel.swift @@ -25,6 +25,7 @@ enum ComposerLinkActionViewAction: Equatable { enum ComposerLinkActionViewModelResult: Equatable { case cancel + case performOperation(_ linkOperation: WysiwygLinkOperation) } // MARK: View diff --git a/RiotSwiftUI/Modules/Room/Composer/LinkAction/ViewModel/ComposerLinkActionViewModel.swift b/RiotSwiftUI/Modules/Room/Composer/LinkAction/ViewModel/ComposerLinkActionViewModel.swift index 8c07669c1..9683ac621 100644 --- a/RiotSwiftUI/Modules/Room/Composer/LinkAction/ViewModel/ComposerLinkActionViewModel.swift +++ b/RiotSwiftUI/Modules/Room/Composer/LinkAction/ViewModel/ComposerLinkActionViewModel.swift @@ -21,9 +21,9 @@ typealias ComposerLinkActionViewModelType = StateStoreViewModel Void)? @@ -33,10 +33,8 @@ final class ComposerLinkActionViewModel: ComposerLinkActionViewModelType, Compos init(from linkAction: LinkAction) { let initialViewState: ComposerLinkActionViewState let simpleBindings = ComposerLinkActionBindings(text: "", linkUrl: "") - // TODO: Add translations switch linkAction { - case .edit: - let link = "https://element.io" + case let .edit(link): initialViewState = .init( linkAction: .edit(link: link), bindings: .init( @@ -57,8 +55,26 @@ final class ComposerLinkActionViewModel: ComposerLinkActionViewModelType, Compos switch viewAction { case .cancel: callback?(.cancel) - case .save, .remove: - break + case .remove: + callback?(.performOperation(.removeLinks)) + case .save: + switch state.linkAction { + case .createWithText: + callback?( + .performOperation( + .createLink( + urlString: state.bindings.linkUrl, + text: state.bindings.text + ) + ) + ) + case .create, .edit: + callback?( + .performOperation( + .setLink(urlString: state.bindings.linkUrl) + ) + ) + } } } } diff --git a/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift b/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift index ffe187abe..46efbe878 100644 --- a/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift +++ b/RiotSwiftUI/Modules/Room/Composer/Model/ComposerModels.swift @@ -142,6 +142,7 @@ enum ComposerViewAction: Equatable { case cancel case contentDidChange(isEmpty: Bool) case linkTapped(linkAction: LinkAction) + case storeSelection(selection: NSRange) } enum ComposerViewModelResult: Equatable { diff --git a/RiotSwiftUI/Modules/Room/Composer/View/Composer.swift b/RiotSwiftUI/Modules/Room/Composer/View/Composer.swift index 4afd6e391..f5b7e179e 100644 --- a/RiotSwiftUI/Modules/Room/Composer/View/Composer.swift +++ b/RiotSwiftUI/Modules/Room/Composer/View/Composer.swift @@ -227,6 +227,7 @@ struct Composer: View { sendMediaButton FormattingToolbar(formatItems: formatItems) { type in if type.action == .link { + storeCurrentSelection() sendLinkAction() } else { wysiwygViewModel.apply(type.action) @@ -247,6 +248,10 @@ struct Composer: View { } } + private func storeCurrentSelection() { + viewModel.send(viewAction: .storeSelection(selection: wysiwygViewModel.attributedContent.selection)) + } + private func sendLinkAction() { let linkAction = wysiwygViewModel.getLinkAction() viewModel.send(viewAction: .linkTapped(linkAction: linkAction)) diff --git a/RiotSwiftUI/Modules/Room/Composer/ViewModel/ComposerViewModel.swift b/RiotSwiftUI/Modules/Room/Composer/ViewModel/ComposerViewModel.swift index b9275709d..a78018f60 100644 --- a/RiotSwiftUI/Modules/Room/Composer/ViewModel/ComposerViewModel.swift +++ b/RiotSwiftUI/Modules/Room/Composer/ViewModel/ComposerViewModel.swift @@ -22,7 +22,7 @@ final class ComposerViewModel: ComposerViewModelType, ComposerViewModelProtocol // MARK: - Properties // MARK: Private - + // MARK: Public var callback: ((ComposerViewModelResult) -> Void)? @@ -76,6 +76,8 @@ final class ComposerViewModel: ComposerViewModelType, ComposerViewModelProtocol state.bindings.focused } + var selectionToRestore: NSRange? + // MARK: - Public override func process(viewAction: ComposerViewAction) { @@ -86,6 +88,8 @@ final class ComposerViewModel: ComposerViewModelType, ComposerViewModelProtocol callback?(.contentDidChange(isEmpty: isEmpty)) case let .linkTapped(linkAction): callback?(.linkTapped(LinkAction: linkAction)) + case let .storeSelection(selection): + selectionToRestore = selection } } diff --git a/RiotSwiftUI/Modules/Room/Composer/ViewModel/ComposerViewModelProtocol.swift b/RiotSwiftUI/Modules/Room/Composer/ViewModel/ComposerViewModelProtocol.swift index 0d23be3cc..cb600c104 100644 --- a/RiotSwiftUI/Modules/Room/Composer/ViewModel/ComposerViewModelProtocol.swift +++ b/RiotSwiftUI/Modules/Room/Composer/ViewModel/ComposerViewModelProtocol.swift @@ -25,6 +25,7 @@ protocol ComposerViewModelProtocol { var placeholder: String? { get set } var isFocused: Bool { get } var isLandscapePhone: Bool { get set } + var selectionToRestore: NSRange? { get } func dismissKeyboard() func showKeyboard() diff --git a/project.yml b/project.yml index 12b4bc027..ff7756c0a 100644 --- a/project.yml +++ b/project.yml @@ -53,7 +53,7 @@ packages: branch: main WysiwygComposer: url: https://github.com/matrix-org/matrix-wysiwyg-composer-swift - revision: a4a7ad46b76cfb8de4695c5fd211a735cb438e1a + revision: b8d55afebfaae94b32bc3deeb1607eb150442e1f DeviceKit: url: https://github.com/devicekit/DeviceKit majorVersion: 4.7.0