From ba686a2018793e1794d2e348b13b71f1d35de643 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 28 Jun 2019 18:16:27 +0200 Subject: [PATCH 1/6] Edits: Start history --- Riot.xcodeproj/project.pbxproj | 48 +++++ Riot/Generated/Storyboards.swift | 5 + .../EditHistory/EditHistoryCoordinator.swift | 67 +++++++ ...ditHistoryCoordinatorBridgePresenter.swift | 89 +++++++++ .../EditHistoryCoordinatorType.swift | 28 +++ .../Room/EditHistory/EditHistoryMessage.swift | 22 +++ .../EditHistory/EditHistoryViewAction.swift | 25 +++ .../EditHistoryViewController.storyboard | 92 +++++++++ .../EditHistoryViewController.swift | 185 ++++++++++++++++++ .../EditHistory/EditHistoryViewModel.swift | 128 ++++++++++++ .../EditHistoryViewModelType.swift | 38 ++++ .../EditHistory/EditHistoryViewState.swift | 26 +++ 12 files changed, 753 insertions(+) create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryCoordinator.swift create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryCoordinatorType.swift create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryMessage.swift create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryViewAction.swift create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryViewController.storyboard create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryViewController.swift create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryViewModelType.swift create mode 100644 Riot/Modules/Room/EditHistory/EditHistoryViewState.swift diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 21d874c54..5271276e5 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -75,6 +75,16 @@ 32891D712264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32891D6F2264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift */; }; 32891D75226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32891D73226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift */; }; 32891D76226728EF00C82226 /* DeviceVerificationDataLoadingViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32891D74226728EE00C82226 /* DeviceVerificationDataLoadingViewController.storyboard */; }; + 32A6001622C661100042C1D9 /* EditHistoryViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6000D22C661100042C1D9 /* EditHistoryViewState.swift */; }; + 32A6001722C661100042C1D9 /* EditHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6000E22C661100042C1D9 /* EditHistoryViewController.swift */; }; + 32A6001822C661100042C1D9 /* EditHistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6000F22C661100042C1D9 /* EditHistoryViewModel.swift */; }; + 32A6001922C661100042C1D9 /* EditHistoryViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6001022C661100042C1D9 /* EditHistoryViewModelType.swift */; }; + 32A6001A22C661100042C1D9 /* EditHistoryCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6001122C661100042C1D9 /* EditHistoryCoordinator.swift */; }; + 32A6001B22C661100042C1D9 /* EditHistoryViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6001222C661100042C1D9 /* EditHistoryViewAction.swift */; }; + 32A6001C22C661100042C1D9 /* EditHistoryViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32A6001322C661100042C1D9 /* EditHistoryViewController.storyboard */; }; + 32A6001D22C661100042C1D9 /* EditHistoryCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6001422C661100042C1D9 /* EditHistoryCoordinatorType.swift */; }; + 32A6001E22C661100042C1D9 /* EditHistoryCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6001522C661100042C1D9 /* EditHistoryCoordinatorBridgePresenter.swift */; }; + 32A6002022C66FCF0042C1D9 /* EditHistoryMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32A6001F22C66FCF0042C1D9 /* EditHistoryMessage.swift */; }; 32B1FEDB21A46F2C00637127 /* TermsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32B1FEDA21A46F2C00637127 /* TermsView.xib */; }; 32B94DF9228EC26400716A26 /* ReactionsMenuViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B94DF2228EC26400716A26 /* ReactionsMenuViewAction.swift */; }; 32B94DFA228EC26400716A26 /* ReactionsMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B94DF3228EC26400716A26 /* ReactionsMenuButton.swift */; }; @@ -607,6 +617,16 @@ 32891D6F2264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationVerifiedViewController.swift; sourceTree = ""; }; 32891D73226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationDataLoadingViewController.swift; sourceTree = ""; }; 32891D74226728EE00C82226 /* DeviceVerificationDataLoadingViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = DeviceVerificationDataLoadingViewController.storyboard; sourceTree = ""; }; + 32A6000D22C661100042C1D9 /* EditHistoryViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryViewState.swift; sourceTree = ""; }; + 32A6000E22C661100042C1D9 /* EditHistoryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryViewController.swift; sourceTree = ""; }; + 32A6000F22C661100042C1D9 /* EditHistoryViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryViewModel.swift; sourceTree = ""; }; + 32A6001022C661100042C1D9 /* EditHistoryViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryViewModelType.swift; sourceTree = ""; }; + 32A6001122C661100042C1D9 /* EditHistoryCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryCoordinator.swift; sourceTree = ""; }; + 32A6001222C661100042C1D9 /* EditHistoryViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryViewAction.swift; sourceTree = ""; }; + 32A6001322C661100042C1D9 /* EditHistoryViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = EditHistoryViewController.storyboard; sourceTree = ""; }; + 32A6001422C661100042C1D9 /* EditHistoryCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryCoordinatorType.swift; sourceTree = ""; }; + 32A6001522C661100042C1D9 /* EditHistoryCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditHistoryCoordinatorBridgePresenter.swift; sourceTree = ""; }; + 32A6001F22C66FCF0042C1D9 /* EditHistoryMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditHistoryMessage.swift; sourceTree = ""; }; 32B1FEDA21A46F2C00637127 /* TermsView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TermsView.xib; sourceTree = ""; }; 32B94DF2228EC26400716A26 /* ReactionsMenuViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactionsMenuViewAction.swift; sourceTree = ""; }; 32B94DF3228EC26400716A26 /* ReactionsMenuButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactionsMenuButton.swift; sourceTree = ""; }; @@ -1509,6 +1529,23 @@ path = js; sourceTree = ""; }; + 32A6000C22C661100042C1D9 /* EditHistory */ = { + isa = PBXGroup; + children = ( + 32A6000D22C661100042C1D9 /* EditHistoryViewState.swift */, + 32A6000E22C661100042C1D9 /* EditHistoryViewController.swift */, + 32A6000F22C661100042C1D9 /* EditHistoryViewModel.swift */, + 32A6001022C661100042C1D9 /* EditHistoryViewModelType.swift */, + 32A6001122C661100042C1D9 /* EditHistoryCoordinator.swift */, + 32A6001222C661100042C1D9 /* EditHistoryViewAction.swift */, + 32A6001322C661100042C1D9 /* EditHistoryViewController.storyboard */, + 32A6001422C661100042C1D9 /* EditHistoryCoordinatorType.swift */, + 32A6001522C661100042C1D9 /* EditHistoryCoordinatorBridgePresenter.swift */, + 32A6001F22C66FCF0042C1D9 /* EditHistoryMessage.swift */, + ); + path = EditHistory; + sourceTree = ""; + }; 32B94DF0228EC26400716A26 /* ReactionsMenu */ = { isa = PBXGroup; children = ( @@ -2085,6 +2122,7 @@ B1B5568E20EE6C4C00210D55 /* Room */ = { isa = PBXGroup; children = ( + 32A6000C22C661100042C1D9 /* EditHistory */, B1B5568F20EE6C4C00210D55 /* RoomViewController.h */, B1B556A020EE6C4C00210D55 /* RoomViewController.m */, B1B5569620EE6C4C00210D55 /* RoomViewController.xib */, @@ -3621,6 +3659,7 @@ B1B557C020EF5B4500210D55 /* RoomInputToolbarView.xib in Resources */, B1B5583D20EF6E7F00210D55 /* GroupRoomTableViewCell.xib in Resources */, B1B5572D20EE6C4D00210D55 /* RoomParticipantsViewController.xib in Resources */, + 32A6001C22C661100042C1D9 /* EditHistoryViewController.storyboard in Resources */, B1B5577220EE702800210D55 /* JitsiViewController.xib in Resources */, B1B557D720EF5EA900210D55 /* RoomActivitiesView.xib in Resources */, B1098BF821ECFE65000DDA48 /* KeyBackupSetupPassphraseViewController.storyboard in Resources */, @@ -3913,6 +3952,7 @@ B140B4A621F89E7600E3F5FE /* KeyBackupSetupCoordinatorBridgePresenter.swift in Sources */, B1B5577420EE702900210D55 /* WidgetViewController.m in Sources */, B139C21B21FE5B9200BB68EC /* KeyBackupRecoverFromPassphraseViewModel.swift in Sources */, + 32A6001E22C661100042C1D9 /* EditHistoryCoordinatorBridgePresenter.swift in Sources */, B1B5574A20EE6C4D00210D55 /* MediaPickerViewController.m in Sources */, B1B5598520EFC3E000210D55 /* RageShakeManager.m in Sources */, 3232ABA8225730E100AD6A5C /* DeviceVerificationStartViewState.swift in Sources */, @@ -3959,6 +3999,7 @@ B1B558DD20EF768F00210D55 /* RoomIncomingEncryptedTextMsgBubbleCell.m in Sources */, B1098BE521ECE1FC000DDA48 /* Storyboards.swift in Sources */, 3232ABC2225B996200AD6A5C /* Themable.swift in Sources */, + 32A6001B22C661100042C1D9 /* EditHistoryViewAction.swift in Sources */, 3232ABA7225730E100AD6A5C /* DeviceVerificationStartCoordinator.swift in Sources */, B1D4752721EE4E630067973F /* KeyboardAvoider.swift in Sources */, B1D4752821EE4E630067973F /* KeyboardNotification.swift in Sources */, @@ -4024,6 +4065,7 @@ B1B5572620EE6C4D00210D55 /* RoomFilesSearchViewController.m in Sources */, B1B5583120EF66BA00210D55 /* RoomIdOrAliasTableViewCell.m in Sources */, B1CA3A2921EF692B000D1D89 /* UIView.swift in Sources */, + 32A6001D22C661100042C1D9 /* EditHistoryCoordinatorType.swift in Sources */, F083BDFA1E7009ED00A9B29C /* RoomPreviewData.m in Sources */, B1B557B420EF5AEF00210D55 /* EventDetailsView.m in Sources */, B1B5577E20EE84BF00210D55 /* IncomingCallView.m in Sources */, @@ -4041,6 +4083,7 @@ B1C562CA2289C2690037F12A /* UIGestureRecognizer.swift in Sources */, B1C562CC228AB3510037F12A /* UIStackView.swift in Sources */, B1B557BE20EF5B4500210D55 /* RoomInputToolbarView.m in Sources */, + 32A6001922C661100042C1D9 /* EditHistoryViewModelType.swift in Sources */, B1B5573B20EE6C4D00210D55 /* FavouritesViewController.m in Sources */, B1B5579920EF575B00210D55 /* AuthInputsView.m in Sources */, B1B5597520EFB02A00210D55 /* InviteRecentTableViewCell.m in Sources */, @@ -4049,8 +4092,10 @@ B1B5573520EE6C4D00210D55 /* GroupDetailsViewController.m in Sources */, B10B3B5B2201DD740072C76B /* KeyBackupBannerCell.swift in Sources */, B1963B32228F1C6B00CBA17F /* BubbleReactionsViewModelType.swift in Sources */, + 32A6001722C661100042C1D9 /* EditHistoryViewController.swift in Sources */, B1098BFA21ECFE65000DDA48 /* KeyBackupSetupPassphraseViewModel.swift in Sources */, B1B5575220EE6C4D00210D55 /* RoomKeyRequestViewController.m in Sources */, + 32A6001A22C661100042C1D9 /* EditHistoryCoordinator.swift in Sources */, F083BD1E1E7009ED00A9B29C /* AppDelegate.m in Sources */, B1B558E620EF768F00210D55 /* RoomIncomingAttachmentWithoutSenderInfoBubbleCell.m in Sources */, B1098BFB21ECFE65000DDA48 /* KeyBackupSetupCoordinatorType.swift in Sources */, @@ -4060,6 +4105,7 @@ B1B557D820EF5EA900210D55 /* RoomActivitiesView.m in Sources */, B1B5596620EF9E9B00210D55 /* RoomTableViewCell.m in Sources */, B14F143322144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewModel.swift in Sources */, + 32A6001822C661100042C1D9 /* EditHistoryViewModel.swift in Sources */, B1B558D020EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */, B1B558CF20EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.m in Sources */, B140B4A221F87F7100E3F5FE /* OperationQueue.swift in Sources */, @@ -4129,6 +4175,7 @@ B1B558EE20EF768F00210D55 /* RoomOutgoingAttachmentBubbleCell.m in Sources */, 3232ABB52257BE6400AD6A5C /* DeviceVerificationVerifyCoordinatorType.swift in Sources */, 32BF994F21FA29A400698084 /* SettingsKeyBackupViewModel.swift in Sources */, + 32A6002022C66FCF0042C1D9 /* EditHistoryMessage.swift in Sources */, B1B5574920EE6C4D00210D55 /* RiotSplitViewController.m in Sources */, B1B5574E20EE6C4D00210D55 /* DirectoryServerPickerViewController.m in Sources */, B1D211E822C195B400D939BD /* ReactionMenuItemViewData.swift in Sources */, @@ -4154,6 +4201,7 @@ B1C562E8228C7CF20037F12A /* ContextualMenuItemView.swift in Sources */, B14F143022144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyCoordinatorType.swift in Sources */, B1E5368921FB1E20001F3AFF /* UIButton.swift in Sources */, + 32A6001622C661100042C1D9 /* EditHistoryViewState.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index b2aa4fda8..b8647542a 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -37,6 +37,11 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType(storyboard: DeviceVerificationVerifyViewController.self) } + internal enum EditHistoryViewController: StoryboardType { + internal static let storyboardName = "EditHistoryViewController" + + internal static let initialScene = InitialSceneType(storyboard: EditHistoryViewController.self) + } internal enum KeyBackupRecoverFromPassphraseViewController: StoryboardType { internal static let storyboardName = "KeyBackupRecoverFromPassphraseViewController" diff --git a/Riot/Modules/Room/EditHistory/EditHistoryCoordinator.swift b/Riot/Modules/Room/EditHistory/EditHistoryCoordinator.swift new file mode 100644 index 000000000..29dcb6500 --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryCoordinator.swift @@ -0,0 +1,67 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/EditHistory EditHistory +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation +import UIKit + +final class EditHistoryCoordinator: EditHistoryCoordinatorType { + + // MARK: - Properties + + // MARK: Private + + private var editHistoryViewModel: EditHistoryViewModelType + private let editHistoryViewController: EditHistoryViewController + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: EditHistoryCoordinatorDelegate? + + // MARK: - Setup + + init(aggregations: MXAggregations, + roomId: String, + eventId: String) { + + let editHistoryViewModel = EditHistoryViewModel(aggregations: aggregations, roomId: roomId, eventId: eventId) + let editHistoryViewController = EditHistoryViewController.instantiate(with: editHistoryViewModel) + self.editHistoryViewModel = editHistoryViewModel + self.editHistoryViewController = editHistoryViewController + } + + // MARK: - Public methods + + func start() { + self.editHistoryViewModel.coordinatorDelegate = self + } + + func toPresentable() -> UIViewController { + return self.editHistoryViewController + } +} + +// MARK: - EditHistoryViewModelCoordinatorDelegate +extension EditHistoryCoordinator: EditHistoryViewModelCoordinatorDelegate { + + func editHistoryViewModelDidClose(_ viewModel: EditHistoryViewModelType) { + self.delegate?.editHistoryCoordinatorDidComplete(self) + } +} diff --git a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift new file mode 100644 index 000000000..1ce1d524f --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift @@ -0,0 +1,89 @@ +// File created from FlowTemplate +// $ createRootCoordinator.sh Room/EditHistory EditHistory +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +@objc protocol EditHistoryCoordinatorBridgePresenterDelegate { + func editHistoryCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: EditHistoryCoordinatorBridgePresenter) +} + +/// EditHistoryCoordinatorBridgePresenter enables to start EditHistoryCoordinator from a view controller. +/// This bridge is used while waiting for global usage of coordinator pattern. +@objcMembers +final class EditHistoryCoordinatorBridgePresenter: NSObject { + + // MARK: - Properties + + // MARK: Private + + private let aggregations: MXAggregations + private let roomId: String + private let eventId: String + private var coordinator: EditHistoryCoordinator? + + // MARK: Public + + weak var delegate: EditHistoryCoordinatorBridgePresenterDelegate? + + // MARK: - Setup + + init(aggregations: MXAggregations, + roomId: String, + eventId: String) { + self.aggregations = aggregations + self.roomId = roomId + self.eventId = eventId + super.init() + } + + // MARK: - Public + + // NOTE: Default value feature is not compatible with Objective-C. + // func present(from viewController: UIViewController, animated: Bool) { + // self.present(from: viewController, animated: animated) + // } + + func present(from viewController: UIViewController, animated: Bool) { + let editHistoryCoordinator = EditHistoryCoordinator(aggregations: self.aggregations, roomId: self.roomId, eventId: self.eventId) + editHistoryCoordinator.delegate = self + viewController.present(editHistoryCoordinator.toPresentable(), animated: animated, completion: nil) + editHistoryCoordinator.start() + + self.coordinator = editHistoryCoordinator + } + + func dismiss(animated: Bool, completion: (() -> Void)?) { + guard let coordinator = self.coordinator else { + return + } + coordinator.toPresentable().dismiss(animated: animated) { + self.coordinator = nil + + if let completion = completion { + completion() + } + } + } +} + +// MARK: - EditHistoryCoordinatorDelegate +extension EditHistoryCoordinatorBridgePresenter: EditHistoryCoordinatorDelegate { + func editHistoryCoordinatorDidComplete(_ coordinator: EditHistoryCoordinatorType) { + self.delegate?.editHistoryCoordinatorBridgePresenterDelegateDidComplete(self) + } +} diff --git a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorType.swift b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorType.swift new file mode 100644 index 000000000..2f02bd705 --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorType.swift @@ -0,0 +1,28 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/EditHistory EditHistory +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +protocol EditHistoryCoordinatorDelegate: class { + func editHistoryCoordinatorDidComplete(_ coordinator: EditHistoryCoordinatorType) +} + +/// `EditHistoryCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow. +protocol EditHistoryCoordinatorType: Coordinator, Presentable { + var delegate: EditHistoryCoordinatorDelegate? { get } +} diff --git a/Riot/Modules/Room/EditHistory/EditHistoryMessage.swift b/Riot/Modules/Room/EditHistory/EditHistoryMessage.swift new file mode 100644 index 000000000..f33864960 --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryMessage.swift @@ -0,0 +1,22 @@ +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +struct EditHistoryMessage { + let date: Date + let message: NSAttributedString +} diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewAction.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewAction.swift new file mode 100644 index 000000000..d1fed7fc5 --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewAction.swift @@ -0,0 +1,25 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/EditHistory EditHistory +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +/// EditHistoryViewController view actions exposed to view model +enum EditHistoryViewAction { + case loadMore + case close +} diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewController.storyboard b/Riot/Modules/Room/EditHistory/EditHistoryViewController.storyboard new file mode 100644 index 000000000..c8f3b006a --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewController.storyboard @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift new file mode 100644 index 000000000..451991881 --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift @@ -0,0 +1,185 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/EditHistory EditHistory +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit + +final class EditHistoryViewController: UIViewController { + + // MARK: - Constants + + private enum Constants { + static let aConstant: Int = 666 + } + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var scrollView: UIScrollView! + + @IBOutlet private weak var messageLabel: UILabel! + @IBOutlet private weak var okButton: UIButton! + + // MARK: Private + + private var viewModel: EditHistoryViewModelType! + private var theme: Theme! + private var keyboardAvoider: KeyboardAvoider? + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + // MARK: - Setup + + class func instantiate(with viewModel: EditHistoryViewModelType) -> EditHistoryViewController { + let viewController = StoryboardScene.EditHistoryViewController.initialScene.instantiate() + viewController.viewModel = viewModel + viewController.theme = ThemeService.shared().theme + return viewController + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + self.title = "Template" + + self.setupViews() + self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.scrollView) + self.activityPresenter = ActivityIndicatorPresenter() + self.errorPresenter = MXKErrorAlertPresentation() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + + self.viewModel.viewDelegate = self + + self.viewModel.process(viewAction: .loadMore) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + self.keyboardAvoider?.startAvoiding() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + self.keyboardAvoider?.stopAvoiding() + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Private + + private func update(theme: Theme) { + self.theme = theme + + self.view.backgroundColor = theme.headerBackgroundColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + + + // TODO: + self.messageLabel.textColor = theme.textPrimaryColor + + self.okButton.backgroundColor = theme.backgroundColor + theme.applyStyle(onButton: self.okButton) + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + + private func setupViews() { + let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in + self?.cancelButtonAction() + } + + self.navigationItem.rightBarButtonItem = cancelBarButtonItem + + self.scrollView.keyboardDismissMode = .interactive + + self.messageLabel.text = "VectorL10n.editHistoryTitle" + self.messageLabel.isHidden = true + } + + private func render(viewState: EditHistoryViewState) { + switch viewState { + case .loading: + self.renderLoading() + case .loaded(let messages, let addedCount): + self.renderLoaded(messages: messages, addedCount: addedCount) + case .error(let error): + self.render(error: error) + } + } + + private func renderLoading() { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + } + + private func renderLoaded(messages: [EditHistoryMessage], addedCount: Int) { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + + let attributedText = NSMutableAttributedString() + for message in messages { + attributedText.append(message.message) + attributedText.append(NSAttributedString(string: "\n")) + } + + self.messageLabel.attributedText = attributedText + self.messageLabel.isHidden = false + } + + private func render(error: Error) { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil) + } + + + // MARK: - Actions + + @IBAction private func okButtonAction(_ sender: Any) { + self.viewModel.process(viewAction: .close) + } + + private func cancelButtonAction() { + self.viewModel.process(viewAction: .close) + } +} + + +// MARK: - EditHistoryViewModelViewDelegate +extension EditHistoryViewController: EditHistoryViewModelViewDelegate { + + func editHistoryViewModel(_ viewModel: EditHistoryViewModelType, didUpdateViewState viewSate: EditHistoryViewState) { + self.render(viewState: viewSate) + } +} diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift new file mode 100644 index 000000000..f4b1348a8 --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift @@ -0,0 +1,128 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/EditHistory EditHistory +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +final class EditHistoryViewModel: EditHistoryViewModelType { + + // MARK: - Properties + + // MARK: Private + + private let aggregations: MXAggregations + private let roomId: String + private let eventId: String + private let messageFormattingQueue: DispatchQueue + + private var nextBatch: String? + + // MARK: Public + + var messages: [EditHistoryMessage] = [] + var operation: MXHTTPOperation? + + weak var viewDelegate: EditHistoryViewModelViewDelegate? + weak var coordinatorDelegate: EditHistoryViewModelCoordinatorDelegate? + + + // MARK: - Setup + + init(aggregations: MXAggregations, + roomId: String, + eventId: String) { + self.aggregations = aggregations + self.roomId = roomId + self.eventId = eventId + self.messageFormattingQueue = DispatchQueue(label: "\(type(of: self)).messageFormattingQueue") + } + + deinit { + } + + // MARK: - Public + + func process(viewAction: EditHistoryViewAction) { + switch viewAction { + case .loadMore: + self.loadMoreHistory() + case .close: + self.coordinatorDelegate?.editHistoryViewModelDidClose(self) + } + } + + // MARK: - Private + + func loadMoreHistory() { + if self.operation != nil { + print("[EditHistoryViewModel] loadMoreHistory: operation already pending") + return + } + + self.update(viewState: .loading) + self.operation = self.aggregations.replaceEvents(forEvent: self.eventId, inRoom: self.roomId, from: self.nextBatch, limit: 10, success: { [weak self] (response) in + guard let sself = self else { + return + } + + sself.nextBatch = response.nextBatch + sself.operation = nil + + sself.process(editEvents: response.chunk) + + }, failure: { [weak self] error in + guard let sself = self else { + return + } + + sself.operation = nil + sself.update(viewState: .error(error)) + }) + } + + func process(editEvents: [MXEvent]) { + self.messageFormattingQueue.async { + + let newMessages = editEvents.reversed() + .compactMap { (editEvent) -> EditHistoryMessage? in + return self.process(editEvent: editEvent) + } + + if newMessages.count > 0 { + DispatchQueue.main.async { + self.messages = newMessages + self.messages + self.update(viewState: .loaded(messages: self.messages, addedCount: newMessages.count)) + } + } + } + } + + func process(editEvent: MXEvent) -> EditHistoryMessage? { + + guard let body: String = (editEvent.content?["m.new_content"] as? [String: Any])?["body"] as? String else { + print("[EditHistoryViewModel] processEditEvent: invalid edit event: \(editEvent.eventId ?? "")") + return nil + } + + // TODO: Using MXKEventFormatter + return EditHistoryMessage(date: Date(), message: NSAttributedString(string: body)) + } + + private func update(viewState: EditHistoryViewState) { + self.viewDelegate?.editHistoryViewModel(self, didUpdateViewState: viewState) + } +} diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewModelType.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewModelType.swift new file mode 100644 index 000000000..d0322c85f --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewModelType.swift @@ -0,0 +1,38 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/EditHistory EditHistory +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +protocol EditHistoryViewModelViewDelegate: class { + func editHistoryViewModel(_ viewModel: EditHistoryViewModelType, didUpdateViewState viewSate: EditHistoryViewState) +} + +protocol EditHistoryViewModelCoordinatorDelegate: class { + func editHistoryViewModelDidClose(_ viewModel: EditHistoryViewModelType) +} + +/// Protocol describing the view model used by `EditHistoryViewController` +protocol EditHistoryViewModelType { + + var messages: [EditHistoryMessage] { get set } + + var viewDelegate: EditHistoryViewModelViewDelegate? { get set } + var coordinatorDelegate: EditHistoryViewModelCoordinatorDelegate? { get set } + + func process(viewAction: EditHistoryViewAction) +} diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewState.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewState.swift new file mode 100644 index 000000000..62f75431b --- /dev/null +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewState.swift @@ -0,0 +1,26 @@ +// File created from ScreenTemplate +// $ createScreen.sh Room/EditHistory EditHistory +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +/// EditHistoryViewController view state +enum EditHistoryViewState { + case loading + case loaded(messages: [EditHistoryMessage], addedCount: Int) + case error(Error) +} From dc1f0b58b8eba81428bcf46e60cf12c3215c88ce Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 1 Jul 2019 10:34:02 +0200 Subject: [PATCH 2/6] Edits history: Fix missing navigation bar --- .../EditHistory/EditHistoryCoordinatorBridgePresenter.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift index 1ce1d524f..fb52c31c5 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift @@ -61,7 +61,11 @@ final class EditHistoryCoordinatorBridgePresenter: NSObject { func present(from viewController: UIViewController, animated: Bool) { let editHistoryCoordinator = EditHistoryCoordinator(aggregations: self.aggregations, roomId: self.roomId, eventId: self.eventId) editHistoryCoordinator.delegate = self - viewController.present(editHistoryCoordinator.toPresentable(), animated: animated, completion: nil) + + let navigationController = UINavigationController() + navigationController.addChild(editHistoryCoordinator.toPresentable()) + viewController.present(navigationController, animated: animated, completion: nil) + editHistoryCoordinator.start() self.coordinator = editHistoryCoordinator From 462ac5bb6e49d84924a5c416d9717b825ec6893a Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 1 Jul 2019 10:51:07 +0200 Subject: [PATCH 3/6] Edits history: Improve temporary UX a bit --- .../EditHistoryViewController.storyboard | 12 ++++---- .../EditHistoryViewController.swift | 29 +++++++++++++------ .../EditHistory/EditHistoryViewModel.swift | 14 +++++++-- .../EditHistory/EditHistoryViewState.swift | 1 + 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewController.storyboard b/Riot/Modules/Room/EditHistory/EditHistoryViewController.storyboard index c8f3b006a..7a2d5f148 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryViewController.storyboard +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewController.storyboard @@ -10,7 +10,7 @@ - + @@ -27,8 +27,8 @@ - @@ -79,8 +79,8 @@ + - diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift index 451991881..843bb31b4 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift @@ -33,7 +33,7 @@ final class EditHistoryViewController: UIViewController { @IBOutlet private weak var scrollView: UIScrollView! @IBOutlet private weak var messageLabel: UILabel! - @IBOutlet private weak var okButton: UIButton! + @IBOutlet private weak var loadMoreButton: UIButton! // MARK: Private @@ -105,8 +105,8 @@ final class EditHistoryViewController: UIViewController { // TODO: self.messageLabel.textColor = theme.textPrimaryColor - self.okButton.backgroundColor = theme.backgroundColor - theme.applyStyle(onButton: self.okButton) + self.loadMoreButton.backgroundColor = theme.backgroundColor + theme.applyStyle(onButton: self.loadMoreButton) } private func registerThemeServiceDidChangeThemeNotification() { @@ -118,11 +118,11 @@ final class EditHistoryViewController: UIViewController { } private func setupViews() { - let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in - self?.cancelButtonAction() + let closeBarButtonItem = MXKBarButtonItem(title: "Close", style: .plain) { [weak self] in + self?.closeButtonAction() } - self.navigationItem.rightBarButtonItem = cancelBarButtonItem + self.navigationItem.rightBarButtonItem = closeBarButtonItem self.scrollView.keyboardDismissMode = .interactive @@ -136,6 +136,8 @@ final class EditHistoryViewController: UIViewController { self.renderLoading() case .loaded(let messages, let addedCount): self.renderLoaded(messages: messages, addedCount: addedCount) + case .allLoaded: + self.renderAllLoaded() case .error(let error): self.render(error: error) } @@ -148,8 +150,13 @@ final class EditHistoryViewController: UIViewController { private func renderLoaded(messages: [EditHistoryMessage], addedCount: Int) { self.activityPresenter.removeCurrentActivityIndicator(animated: true) + let calendar = Calendar.current + let attributedText = NSMutableAttributedString() for message in messages { + let time=calendar.dateComponents([.hour, .minute], from: Date()) + attributedText.append(NSAttributedString(string: "\(time.hour!):\(time.minute!)")) + attributedText.append(NSAttributedString(string: " - ")) attributedText.append(message.message) attributedText.append(NSAttributedString(string: "\n")) } @@ -157,6 +164,10 @@ final class EditHistoryViewController: UIViewController { self.messageLabel.attributedText = attributedText self.messageLabel.isHidden = false } + + private func renderAllLoaded() { + self.loadMoreButton.isHidden = true + } private func render(error: Error) { self.activityPresenter.removeCurrentActivityIndicator(animated: true) @@ -166,11 +177,11 @@ final class EditHistoryViewController: UIViewController { // MARK: - Actions - @IBAction private func okButtonAction(_ sender: Any) { - self.viewModel.process(viewAction: .close) + @IBAction private func loadMoreButtonAction(_ sender: Any) { + self.viewModel.process(viewAction: .loadMore) } - private func cancelButtonAction() { + private func closeButtonAction() { self.viewModel.process(viewAction: .close) } } diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift index f4b1348a8..3a156733e 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift @@ -19,7 +19,13 @@ import Foundation final class EditHistoryViewModel: EditHistoryViewModelType { - + + // MARK: - Constants + + private enum Pagination { + static let count: UInt = 2 + } + // MARK: - Properties // MARK: Private @@ -74,7 +80,7 @@ final class EditHistoryViewModel: EditHistoryViewModelType { } self.update(viewState: .loading) - self.operation = self.aggregations.replaceEvents(forEvent: self.eventId, inRoom: self.roomId, from: self.nextBatch, limit: 10, success: { [weak self] (response) in + self.operation = self.aggregations.replaceEvents(forEvent: self.eventId, inRoom: self.roomId, from: self.nextBatch, limit: Pagination.count, success: { [weak self] (response) in guard let sself = self else { return } @@ -84,6 +90,10 @@ final class EditHistoryViewModel: EditHistoryViewModelType { sself.process(editEvents: response.chunk) + if sself.nextBatch == nil { + sself.update(viewState: .allLoaded) + } + }, failure: { [weak self] error in guard let sself = self else { return diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewState.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewState.swift index 62f75431b..112451335 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryViewState.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewState.swift @@ -22,5 +22,6 @@ import Foundation enum EditHistoryViewState { case loading case loaded(messages: [EditHistoryMessage], addedCount: Int) + case allLoaded case error(Error) } From b1becf78aaaad8c46cf60ad7b9791b3c61fcd379 Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 1 Jul 2019 12:34:20 +0200 Subject: [PATCH 4/6] Edits history: Use a dedicated event formatter --- .../EditHistory/EditHistoryCoordinator.swift | 6 +-- ...ditHistoryCoordinatorBridgePresenter.swift | 44 ++++++++++++++----- .../EditHistory/EditHistoryViewModel.swift | 29 +++++++----- Riot/SupportingFiles/Riot-Bridging-Header.h | 1 + 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/Riot/Modules/Room/EditHistory/EditHistoryCoordinator.swift b/Riot/Modules/Room/EditHistory/EditHistoryCoordinator.swift index 29dcb6500..760b5ccf6 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryCoordinator.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryCoordinator.swift @@ -38,10 +38,10 @@ final class EditHistoryCoordinator: EditHistoryCoordinatorType { // MARK: - Setup init(aggregations: MXAggregations, - roomId: String, - eventId: String) { + formatter: MXKEventFormatter, + event: MXEvent) { - let editHistoryViewModel = EditHistoryViewModel(aggregations: aggregations, roomId: roomId, eventId: eventId) + let editHistoryViewModel = EditHistoryViewModel(aggregations: aggregations, formatter: formatter, event: event) let editHistoryViewController = EditHistoryViewController.instantiate(with: editHistoryViewModel) self.editHistoryViewModel = editHistoryViewModel self.editHistoryViewController = editHistoryViewController diff --git a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift index fb52c31c5..818773e2b 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift @@ -31,9 +31,8 @@ final class EditHistoryCoordinatorBridgePresenter: NSObject { // MARK: Private - private let aggregations: MXAggregations - private let roomId: String - private let eventId: String + private let session: MXSession + private let event: MXEvent private var coordinator: EditHistoryCoordinator? // MARK: Public @@ -42,12 +41,10 @@ final class EditHistoryCoordinatorBridgePresenter: NSObject { // MARK: - Setup - init(aggregations: MXAggregations, - roomId: String, - eventId: String) { - self.aggregations = aggregations - self.roomId = roomId - self.eventId = eventId + init(session: MXSession, + event: MXEvent) { + self.session = session + self.event = event super.init() } @@ -59,7 +56,13 @@ final class EditHistoryCoordinatorBridgePresenter: NSObject { // } func present(from viewController: UIViewController, animated: Bool) { - let editHistoryCoordinator = EditHistoryCoordinator(aggregations: self.aggregations, roomId: self.roomId, eventId: self.eventId) + + guard let formatter = self.createEventFormatter(session: self.session) else { + //s das + return + } + + let editHistoryCoordinator = EditHistoryCoordinator(aggregations: self.session.aggregations, formatter: formatter, event: self.event) editHistoryCoordinator.delegate = self let navigationController = UINavigationController() @@ -83,6 +86,27 @@ final class EditHistoryCoordinatorBridgePresenter: NSObject { } } } + + // MARK: - Private + + func createEventFormatter(session: MXSession) -> EventFormatter? { + guard let formatter = EventFormatter(matrixSession: session) else { + print("[EditHistoryCoordinatorBridgePresenter] createEventFormatter: Cannot build formatter") + return nil + } + + // Use the same event formatter settings as RoomDataSource + formatter.treatMatrixUserIdAsLink = true + formatter.treatMatrixRoomIdAsLink = true + formatter.treatMatrixRoomAliasAsLink = true + formatter.treatMatrixGroupIdAsLink = true + formatter.eventTypesFilterForMessages = MXKAppSettings.standard()?.eventsFilterForMessages + + // But do not display "...(edited)" + // TODO + + return formatter + } } // MARK: - EditHistoryCoordinatorDelegate diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift index 3a156733e..3229a9218 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift @@ -31,8 +31,9 @@ final class EditHistoryViewModel: EditHistoryViewModelType { // MARK: Private private let aggregations: MXAggregations + private let formatter: MXKEventFormatter private let roomId: String - private let eventId: String + private let event: MXEvent private let messageFormattingQueue: DispatchQueue private var nextBatch: String? @@ -49,11 +50,12 @@ final class EditHistoryViewModel: EditHistoryViewModelType { // MARK: - Setup init(aggregations: MXAggregations, - roomId: String, - eventId: String) { + formatter: MXKEventFormatter, + event: MXEvent) { self.aggregations = aggregations - self.roomId = roomId - self.eventId = eventId + self.formatter = formatter + self.event = event + self.roomId = event.roomId self.messageFormattingQueue = DispatchQueue(label: "\(type(of: self)).messageFormattingQueue") } @@ -80,7 +82,7 @@ final class EditHistoryViewModel: EditHistoryViewModelType { } self.update(viewState: .loading) - self.operation = self.aggregations.replaceEvents(forEvent: self.eventId, inRoom: self.roomId, from: self.nextBatch, limit: Pagination.count, success: { [weak self] (response) in + self.operation = self.aggregations.replaceEvents(forEvent: self.event.eventId, inRoom: self.roomId, from: self.nextBatch, limit: Pagination.count, success: { [weak self] (response) in guard let sself = self else { return } @@ -122,14 +124,19 @@ final class EditHistoryViewModel: EditHistoryViewModelType { } func process(editEvent: MXEvent) -> EditHistoryMessage? { - - guard let body: String = (editEvent.content?["m.new_content"] as? [String: Any])?["body"] as? String else { - print("[EditHistoryViewModel] processEditEvent: invalid edit event: \(editEvent.eventId ?? "")") + // Create a temporary MXEvent that represents this edition + guard let editedEvent = self.event.editedEvent(fromReplacementEvent: editEvent) else { + print("[EditHistoryViewModel] processEditEvent: Cannot build edited event: \(editEvent.eventId ?? "")") return nil } - // TODO: Using MXKEventFormatter - return EditHistoryMessage(date: Date(), message: NSAttributedString(string: body)) + let formatterError = UnsafeMutablePointer.allocate(capacity: 1) + guard let message = self.formatter.attributedString(from: editedEvent, with: nil, error: formatterError) else { + print("[EditHistoryViewModel] processEditEvent: cannot format(error: \(formatterError)) edited event: \(editEvent.eventId ?? "")") + return nil + } + + return EditHistoryMessage(date: Date(), message: message) } private func update(viewState: EditHistoryViewState) { diff --git a/Riot/SupportingFiles/Riot-Bridging-Header.h b/Riot/SupportingFiles/Riot-Bridging-Header.h index 7467821eb..68348718c 100644 --- a/Riot/SupportingFiles/Riot-Bridging-Header.h +++ b/Riot/SupportingFiles/Riot-Bridging-Header.h @@ -12,3 +12,4 @@ #import "RecentsDataSource.h" #import "AvatarGenerator.h" #import "EncryptionInfoView.h" +#import "EventFormatter.h" From e2cbd51028b33db4282b954a476b2d104443be3d Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 1 Jul 2019 12:42:42 +0200 Subject: [PATCH 5/6] EventFormatter: add showEditionMention setting --- .../EditHistory/EditHistoryCoordinatorBridgePresenter.swift | 4 ++-- Riot/Utils/EventFormatter.h | 6 ++++++ Riot/Utils/EventFormatter.m | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift index 818773e2b..a566c959b 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift @@ -102,8 +102,8 @@ final class EditHistoryCoordinatorBridgePresenter: NSObject { formatter.treatMatrixGroupIdAsLink = true formatter.eventTypesFilterForMessages = MXKAppSettings.standard()?.eventsFilterForMessages - // But do not display "...(edited)" - // TODO + // But do not display "...(Edited)" + formatter.showEditionMention = false return formatter } diff --git a/Riot/Utils/EventFormatter.h b/Riot/Utils/EventFormatter.h index 67abcd419..172175079 100644 --- a/Riot/Utils/EventFormatter.h +++ b/Riot/Utils/EventFormatter.h @@ -36,6 +36,12 @@ FOUNDATION_EXPORT NSString *const EventFormatterEditedEventLinkAction; */ @interface EventFormatter : MXKEventFormatter +/** + Add a "(Edited)" mention to edited message. + Default is YES. + */ +@property (nonatomic) BOOL showEditionMention; + /** Text color used to display message edited mention. Default is `textSecondaryColor`. diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index 8b8eeba27..3ba09e318 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -182,7 +182,7 @@ static NSString *const kEventFormatterTimeFormat = @"HH:mm"; attributedString = attributedStringWithRerequestMessage; } } - else if (event.contentHasBeenEdited) + else if (self.showEditionMention && event.contentHasBeenEdited) { NSMutableAttributedString *attributedStringWithEditMention = [attributedString mutableCopy]; @@ -255,6 +255,7 @@ static NSString *const kEventFormatterTimeFormat = @"HH:mm"; self.encryptingTextColor = ThemeService.shared.theme.tintColor; self.sendingTextColor = ThemeService.shared.theme.textSecondaryColor; self.errorTextColor = ThemeService.shared.theme.warningColor; + self.showEditionMention = YES; self.editionMentionTextColor = ThemeService.shared.theme.textSecondaryColor; self.defaultTextFont = [UIFont systemFontOfSize:15]; From 0312c7f1e4a29c3bd33f72737135131f08995be0 Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 1 Jul 2019 14:39:39 +0200 Subject: [PATCH 6/6] Edits history: Manage date --- Riot/Modules/Room/EditHistory/EditHistoryViewController.swift | 4 ++-- Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift index 843bb31b4..59ae30e10 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewController.swift @@ -59,7 +59,7 @@ final class EditHistoryViewController: UIViewController { // Do any additional setup after loading the view. - self.title = "Template" + self.title = "Edits history" self.setupViews() self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.scrollView) @@ -154,7 +154,7 @@ final class EditHistoryViewController: UIViewController { let attributedText = NSMutableAttributedString() for message in messages { - let time=calendar.dateComponents([.hour, .minute], from: Date()) + let time=calendar.dateComponents([.hour, .minute], from: message.date) attributedText.append(NSAttributedString(string: "\(time.hour!):\(time.minute!)")) attributedText.append(NSAttributedString(string: " - ")) attributedText.append(message.message) diff --git a/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift b/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift index 3229a9218..2a9f553bf 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryViewModel.swift @@ -136,7 +136,9 @@ final class EditHistoryViewModel: EditHistoryViewModelType { return nil } - return EditHistoryMessage(date: Date(), message: message) + let date = Date(timeIntervalSince1970: TimeInterval(editEvent.originServerTs) / 1000) + + return EditHistoryMessage(date: date, message: message) } private func update(viewState: EditHistoryViewState) {