From 6d1a3eb56ff5cd6ee69091b7c2d4e2585f8bcdef Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Wed, 9 May 2018 17:22:17 -0300 Subject: [PATCH 01/17] Map broadcasting on the Subscription object --- .../Models/Mapping/SubscriptionModelMapping.swift | 11 +++-------- Rocket.Chat/Models/Subscription/Subscription.swift | 1 + 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Rocket.Chat/Models/Mapping/SubscriptionModelMapping.swift b/Rocket.Chat/Models/Mapping/SubscriptionModelMapping.swift index 9a7b7138ab..d51fef2f4d 100644 --- a/Rocket.Chat/Models/Mapping/SubscriptionModelMapping.swift +++ b/Rocket.Chat/Models/Mapping/SubscriptionModelMapping.swift @@ -45,18 +45,13 @@ extension Subscription: ModelMappeable { func mapRoom(_ values: JSON) { self.roomDescription = values["description"].stringValue self.roomTopic = values["topic"].stringValue + self.roomReadOnly = values["ro"].boolValue + self.roomBroadcast = values["broadcast"].boolValue + self.roomOwnerId = values["u"]["_id"].stringValue self.roomMuted.removeAll() if let roomMuted = values["muted"].array?.compactMap({ $0.string }) { self.roomMuted.append(objectsIn: roomMuted) } - - if let readOnly = values["ro"].bool { - self.roomReadOnly = readOnly - } - - if let ownerId = values["u"]["_id"].string { - self.roomOwnerId = ownerId - } } } diff --git a/Rocket.Chat/Models/Subscription/Subscription.swift b/Rocket.Chat/Models/Subscription/Subscription.swift index 8ddeb97d50..328e7357b5 100644 --- a/Rocket.Chat/Models/Subscription/Subscription.swift +++ b/Rocket.Chat/Models/Subscription/Subscription.swift @@ -46,6 +46,7 @@ final class Subscription: BaseModel { @objc dynamic var roomTopic: String? @objc dynamic var roomDescription: String? @objc dynamic var roomReadOnly = false + @objc dynamic var roomBroadcast = false let roomMuted = RealmSwift.List() From ea8312b2e541c51f7e95e29c559285a26cd8c207 Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Wed, 9 May 2018 17:26:47 -0300 Subject: [PATCH 02/17] Write some tests for the false & empty values --- .../Models/SubscriptionSpec.swift | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/Rocket.ChatTests/Models/SubscriptionSpec.swift b/Rocket.ChatTests/Models/SubscriptionSpec.swift index 789273466a..0abee8090a 100644 --- a/Rocket.ChatTests/Models/SubscriptionSpec.swift +++ b/Rocket.ChatTests/Models/SubscriptionSpec.swift @@ -107,6 +107,7 @@ class SubscriptionSpec: XCTestCase { "muted": [ "username" ], "jitsiTimeout": [ "$date": 1480377601 ], "ro": true, + "broadcast": true, "description": "room-description" ]) @@ -117,9 +118,64 @@ class SubscriptionSpec: XCTestCase { XCTAssertEqual(subscription.roomTopic, "room-topic") XCTAssertEqual(subscription.roomDescription, "room-description") XCTAssertEqual(subscription.roomReadOnly, true) + XCTAssertEqual(subscription.roomBroadcast, true) XCTAssertEqual(subscription.roomOwnerId, "user-id") } + func testMapRoomReadOnlyFalse() { + let object = JSON([ + "_id": "room-id", + "t": "c", + "name": "room-name", + "ro": false + ]) + + let subscription = Subscription() + subscription.mapRoom(object) + + XCTAssertEqual(subscription.roomReadOnly, false) + } + + func testMapRoomReadOnlyEmpty() { + let object = JSON([ + "_id": "room-id", + "t": "c", + "name": "room-name" + ]) + + let subscription = Subscription() + subscription.mapRoom(object) + + XCTAssertEqual(subscription.roomReadOnly, false) + } + + func testMapRoomBroadcastFalse() { + let object = JSON([ + "_id": "room-id", + "t": "c", + "name": "room-name", + "broadcast": false + ]) + + let subscription = Subscription() + subscription.mapRoom(object) + + XCTAssertEqual(subscription.roomBroadcast, false) + } + + func testMapRoomBroadcastEmpty() { + let object = JSON([ + "_id": "room-id", + "t": "c", + "name": "room-name" + ]) + + let subscription = Subscription() + subscription.mapRoom(object) + + XCTAssertEqual(subscription.roomBroadcast, false) + } + func testSubscriptionDisplayNameHonorFullnameSettings() { let settings = AuthSettings() settings.useUserRealName = false From 92515ba12fc05c803267ea1736b898ca78e80d83 Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Wed, 9 May 2018 17:54:02 -0300 Subject: [PATCH 03/17] Add "Reply" button to each message on Broadcasting --- Rocket.Chat.xcodeproj/project.pbxproj | 8 ++++ ...hViewControllerAuthenticationHandler.swift | 18 ++++---- .../Chat/ChatMessageActionButtonsView.swift | 25 +++++++++++ .../Chat/ChatMessageActionButtonsView.xib | 44 +++++++++++++++++++ .../Views/Cells/Chat/ChatMessageCell.swift | 23 +++++++++- 5 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.swift create mode 100644 Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib diff --git a/Rocket.Chat.xcodeproj/project.pbxproj b/Rocket.Chat.xcodeproj/project.pbxproj index 92b2584274..6d275deaf0 100644 --- a/Rocket.Chat.xcodeproj/project.pbxproj +++ b/Rocket.Chat.xcodeproj/project.pbxproj @@ -250,6 +250,8 @@ 41C275DF1D848005003C88CF /* AvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41C275DE1D848005003C88CF /* AvatarView.swift */; }; 41C275E11D84815C003C88CF /* AvatarView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 41C275E01D84815C003C88CF /* AvatarView.xib */; }; 41C45AEF1DFAD42800D9969C /* ChatDataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41C45AEE1DFAD42800D9969C /* ChatDataController.swift */; }; + 41C955FA20A3931C00FC8314 /* ChatMessageActionButtonsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 41F3705320A3917D00C5449E /* ChatMessageActionButtonsView.xib */; }; + 41C955FC20A3937A00FC8314 /* ChatMessageActionButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41C955FB20A3937A00FC8314 /* ChatMessageActionButtonsView.swift */; }; 41CABFF81F5047D600E0B289 /* ChatLoaderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 41CABFF71F5047D600E0B289 /* ChatLoaderCell.xib */; }; 41CABFFA1F5047E200E0B289 /* ChatLoaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41CABFF91F5047E200E0B289 /* ChatLoaderCell.swift */; }; 41CABFFC1F50515100E0B289 /* ArrayExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41CABFFB1F50515100E0B289 /* ArrayExtensions.swift */; }; @@ -927,6 +929,7 @@ 41C275DE1D848005003C88CF /* AvatarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarView.swift; sourceTree = ""; }; 41C275E01D84815C003C88CF /* AvatarView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AvatarView.xib; sourceTree = ""; }; 41C45AEE1DFAD42800D9969C /* ChatDataController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatDataController.swift; sourceTree = ""; }; + 41C955FB20A3937A00FC8314 /* ChatMessageActionButtonsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatMessageActionButtonsView.swift; sourceTree = ""; }; 41CABFF71F5047D600E0B289 /* ChatLoaderCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChatLoaderCell.xib; sourceTree = ""; }; 41CABFF91F5047E200E0B289 /* ChatLoaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatLoaderCell.swift; sourceTree = ""; }; 41CABFFB1F50515100E0B289 /* ArrayExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExtensions.swift; sourceTree = ""; }; @@ -976,6 +979,7 @@ 41EE15811E05BF9600754D45 /* ChatControllerSocketConnectionHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatControllerSocketConnectionHandler.swift; sourceTree = ""; }; 41F167E81DAC4D4300775CCA /* ChatTitleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatTitleView.swift; sourceTree = ""; }; 41F167EA1DAC4D5500775CCA /* ChatTitleView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChatTitleView.xib; sourceTree = ""; }; + 41F3705320A3917D00C5449E /* ChatMessageActionButtonsView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ChatMessageActionButtonsView.xib; sourceTree = ""; }; 41F3C0FF1DB577ED000E0C76 /* MessageURL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageURL.swift; sourceTree = ""; }; 41F8487D1FA38B0A00C9AE84 /* PreferencesViewModelSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesViewModelSpec.swift; sourceTree = ""; }; 41FE55521F6038D60071E97A /* DatabaseManagerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseManagerSpec.swift; sourceTree = ""; }; @@ -1756,6 +1760,8 @@ 80AE2543203E61CF00DC2867 /* ChatMessageUnreadSeparator.xib */, 412A95D41FD94ED000954AA6 /* ChatMessageVideoView.swift */, 412A95D51FD94ED000954AA6 /* ChatMessageVideoView.xib */, + 41C955FB20A3937A00FC8314 /* ChatMessageActionButtonsView.swift */, + 41F3705320A3917D00C5449E /* ChatMessageActionButtonsView.xib */, ); path = Chat; sourceTree = ""; @@ -3224,6 +3230,7 @@ 41C275E11D84815C003C88CF /* AvatarView.xib in Resources */, 14F8A261202E64B200175FDC /* BnW-76@3x.png in Resources */, 809B53121FE2F2F900833DD2 /* ReactionView.xib in Resources */, + 41C955FA20A3931C00FC8314 /* ChatMessageActionButtonsView.xib in Resources */, 14F8A270202E653E00175FDC /* Grey-76@2x.png in Resources */, 14F8A295202E65C700175FDC /* Blue-76@3x.png in Resources */, 80A2F39420057B48005D2DCA /* EmojiAutocompleteCell.xib in Resources */, @@ -3746,6 +3753,7 @@ 80113DF81F98330C0048F2C2 /* OAuthViewController.swift in Sources */, 80E9DBD6209CA8FE00A48CA9 /* Closeable.swift in Sources */, 9987B5962093E4BA007D277C /* FilesListViewController.swift in Sources */, + 41C955FC20A3937A00FC8314 /* ChatMessageActionButtonsView.swift in Sources */, 806DB94820695BCF004ED8ED /* AuthViewControllerConnectionHandler.swift in Sources */, 339B692B2050449700F97392 /* KeyboardFrameView.swift in Sources */, 0B9AB2C320444ED600ABEA05 /* LanguageViewModel.swift in Sources */, diff --git a/Rocket.Chat/Controllers/Auth/AuthViewControllerAuthenticationHandler.swift b/Rocket.Chat/Controllers/Auth/AuthViewControllerAuthenticationHandler.swift index fd4a471433..7ddcf16738 100644 --- a/Rocket.Chat/Controllers/Auth/AuthViewControllerAuthenticationHandler.swift +++ b/Rocket.Chat/Controllers/Auth/AuthViewControllerAuthenticationHandler.swift @@ -11,15 +11,17 @@ import Foundation extension AuthViewController { internal func handleAuthenticationResponse(_ response: LoginResponse) { if case let .resource(resource) = response, let error = resource.error { - stopLoading() + DispatchQueue.main.async { [weak self] in + self?.stopLoading() - switch error.lowercased() { - case "totp-required": - return performSegue(withIdentifier: "TwoFactor", sender: nil) - case "unauthorized": - return Alert(key: "error.login_unauthorized").present() - default: - return Alert(key: "error.login").present() + switch error.lowercased() { + case "totp-required": + self?.performSegue(withIdentifier: "TwoFactor", sender: nil) + case "unauthorized": + Alert(key: "error.login_unauthorized").present() + default: + Alert(key: "error.login").present() + } } } diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.swift new file mode 100644 index 0000000000..883377c9dd --- /dev/null +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.swift @@ -0,0 +1,25 @@ +// +// ChatMessageActionButtonsView.swift +// Rocket.Chat +// +// Created by Rafael Kellermann Streit on 09/05/18. +// Copyright © 2018 Rocket.Chat. All rights reserved. +// + +import UIKit + +class ChatMessageActionButtonsView: UIView { + + static let defaultHeight = CGFloat(55) + + @IBOutlet weak var buttonReply: UIButton! { + didSet { + let buttonColor = UIColor.RCBlue() + buttonReply.tintColor = buttonColor + buttonReply.layer.borderColor = buttonColor.cgColor + buttonReply.layer.borderWidth = 1 + buttonReply.layer.cornerRadius = 4 + } + } + +} diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib new file mode 100644 index 0000000000..e38a1bf482 --- /dev/null +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift index 29ca66894f..2a87657676 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift @@ -151,6 +151,21 @@ final class ChatMessageCell: UICollectionViewCell { } } + func insertButtonActions() -> CGFloat { + var addedHeight = CGFloat(0) + + if message.subscription.roomBroadcast { + if let view = ChatMessageActionButtonsView.instantiateFromNib() { +// view.delegate = delegate + + mediaViews.addArrangedSubview(view) + addedHeight += ChatMessageActionButtonsView.defaultHeight + } + } + + return addedHeight + } + func insertURLs() -> CGFloat { var addedHeight = CGFloat(0) message.urls.forEach { url in @@ -168,7 +183,9 @@ final class ChatMessageCell: UICollectionViewCell { //swiftlint:disable cyclomatic_complexity func insertAttachments() { - var mediaViewHeight = insertURLs() + var mediaViewHeight = CGFloat(0) + mediaViewHeight += insertButtonActions() + mediaViewHeight += insertURLs() message.attachments.forEach { attachment in let type = attachment.type @@ -315,6 +332,10 @@ extension ChatMessageCell { total += (attributedString?.heightForView(withWidth: fullWidth - 55) ?? 0) } + if message.subscription.roomBroadcast { + total += ChatMessageActionButtonsView.defaultHeight + } + for url in message.urls { guard url.isValid() else { continue } total += ChatMessageURLView.defaultHeight From 32b54a6e36f0ca69519b51ed025529c3446dbc3f Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Wed, 9 May 2018 19:14:47 -0300 Subject: [PATCH 04/17] Call the delegate on pressing the button --- .../ChatControllerMessageCellProtocol.swift | 4 ++++ .../Controllers/Chat/ChatViewController.swift | 4 ++-- .../Chat/ChatMessageActionButtonsView.swift | 20 +++++++++++++++++-- .../Chat/ChatMessageActionButtonsView.xib | 3 +++ .../Views/Cells/Chat/ChatMessageCell.swift | 6 ++++-- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift b/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift index 15518f050a..233c4cf7d9 100644 --- a/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift +++ b/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift @@ -95,6 +95,10 @@ extension ChatViewController: ChatMessageCellProtocol, UserActionSheetPresenter present(controller, animated: true, completion: nil) } + func openReplyMessage(message: Message) { + + } + func openImageFromCell(attachment: Attachment, thumbnail: FLAnimatedImageView) { textView.resignFirstResponder() diff --git a/Rocket.Chat/Controllers/Chat/ChatViewController.swift b/Rocket.Chat/Controllers/Chat/ChatViewController.swift index c4e0e0650f..95def629a6 100644 --- a/Rocket.Chat/Controllers/Chat/ChatViewController.swift +++ b/Rocket.Chat/Controllers/Chat/ChatViewController.swift @@ -10,8 +10,8 @@ import RealmSwift import SlackTextViewController import SimpleImageViewer -private typealias NibCellIndentifier = (nibName: String, cellIdentifier: String) -private let kEmptyCellIdentifier = "kEmptyCellIdentifier" +typealias NibCellIndentifier = (nibName: String, cellIdentifier: String) +let kEmptyCellIdentifier = "kEmptyCellIdentifier" // swiftlint:disable file_length type_body_length final class ChatViewController: SLKTextViewController { diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.swift index 883377c9dd..3873ec3dca 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.swift @@ -8,9 +8,16 @@ import UIKit -class ChatMessageActionButtonsView: UIView { +protocol ChatMessageActionButtonsViewProtocol: class { + func openReplyMessage(message: Message) +} + +final class ChatMessageActionButtonsView: UIView { - static let defaultHeight = CGFloat(55) + static let defaultHeight = CGFloat(55) + + weak var delegate: ChatMessageActionButtonsViewProtocol? + var message: Message? @IBOutlet weak var buttonReply: UIButton! { didSet { @@ -19,6 +26,15 @@ class ChatMessageActionButtonsView: UIView { buttonReply.layer.borderColor = buttonColor.cgColor buttonReply.layer.borderWidth = 1 buttonReply.layer.cornerRadius = 4 + buttonReply.setTitle(localized("chat.message.actions.reply"), for: .normal) + } + } + + // MARK: IBAction + + @IBAction func buttonReplyDidPressed(sender: Any) { + if let message = message { + delegate?.openReplyMessage(message: message) } } diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib index e38a1bf482..b16629070a 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib @@ -24,6 +24,9 @@ + + + diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift index 2a87657676..70bb4ce843 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift @@ -8,8 +8,9 @@ import UIKit -protocol ChatMessageCellProtocol: ChatMessageURLViewProtocol, ChatMessageVideoViewProtocol, ChatMessageImageViewProtocol, ChatMessageTextViewProtocol { +protocol ChatMessageCellProtocol: ChatMessageURLViewProtocol, ChatMessageVideoViewProtocol, ChatMessageImageViewProtocol, ChatMessageTextViewProtocol, ChatMessageActionButtonsViewProtocol { func openURL(url: URL) + func handleLongPressMessageCell(_ message: Message, view: UIView, recognizer: UIGestureRecognizer) func handleUsernameTapMessageCell(_ message: Message, view: UIView, recognizer: UIGestureRecognizer) func handleLongPress(reactionListView: ReactionListView, reactionView: ReactionView) @@ -156,7 +157,8 @@ final class ChatMessageCell: UICollectionViewCell { if message.subscription.roomBroadcast { if let view = ChatMessageActionButtonsView.instantiateFromNib() { -// view.delegate = delegate + view.message = message + view.delegate = delegate mediaViews.addArrangedSubview(view) addedHeight += ChatMessageActionButtonsView.defaultHeight From 108b6f3386b900bbe3ae092885da222edc3fafcf Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Thu, 10 May 2018 08:52:40 -0300 Subject: [PATCH 05/17] Let the user open the DM with the reply --- .../Chat/ChatControllerMessageCellProtocol.swift | 3 ++- Rocket.Chat/Managers/AppManager.swift | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift b/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift index 233c4cf7d9..1f4043900d 100644 --- a/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift +++ b/Rocket.Chat/Controllers/Chat/ChatControllerMessageCellProtocol.swift @@ -96,7 +96,8 @@ extension ChatViewController: ChatMessageCellProtocol, UserActionSheetPresenter } func openReplyMessage(message: Message) { - + guard let username = message.user?.username else { return } + AppManager.openDirectMessage(username: username, replyMessageIdentifier: message.identifier, completion: nil) } func openImageFromCell(attachment: Attachment, thumbnail: FLAnimatedImageView) { diff --git a/Rocket.Chat/Managers/AppManager.swift b/Rocket.Chat/Managers/AppManager.swift index bd7e778a7f..6f9df38835 100644 --- a/Rocket.Chat/Managers/AppManager.swift +++ b/Rocket.Chat/Managers/AppManager.swift @@ -125,13 +125,19 @@ extension AppManager { // MARK: Open Rooms extension AppManager { - static func openDirectMessage(username: String, completion: (() -> Void)? = nil) { + static func openDirectMessage(username: String, replyMessageIdentifier: String? = nil, completion: (() -> Void)? = nil) { func openDirectMessage() -> Bool { guard let directMessageRoom = Subscription.find(name: username, subscriptionType: [.directMessage]) else { return false } let controller = ChatViewController.shared controller?.subscription = directMessageRoom + if let identifier = replyMessageIdentifier { + if let message = Realm.current?.object(ofType: Message.self, forPrimaryKey: identifier) { + controller?.reply(to: message) + } + } + completion?() return true From 82d9733c57dde5e860948278f1b02374fd4bcc67 Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Thu, 10 May 2018 09:08:25 -0300 Subject: [PATCH 06/17] Only show reply button when required --- .../Extensions/Models/MessageExtensions.swift | 18 ++++++++++++++++++ .../AuthManager/AuthManagerCurrentUser.swift | 1 + .../Views/Cells/Chat/ChatMessageCell.swift | 6 +++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Rocket.Chat/Extensions/Models/MessageExtensions.swift b/Rocket.Chat/Extensions/Models/MessageExtensions.swift index bf0106533b..ea74306562 100644 --- a/Rocket.Chat/Extensions/Models/MessageExtensions.swift +++ b/Rocket.Chat/Extensions/Models/MessageExtensions.swift @@ -9,6 +9,22 @@ import UIKit extension Message { + + func isBroadcastReplyAvailable() -> Bool { + guard + !temporary, + !failed, + !markedForDeletion, + !isSystemMessage(), + let currentUser = AuthManager.currentUser(), + currentUser.identifier != user?.identifier + else { + return false + } + + return subscription.roomBroadcast + } + func isSystemMessage() -> Bool { return !( type == .text || @@ -112,9 +128,11 @@ extension Message { return text } + } // MARK: Accessibility + extension Message { override var accessibilityLabel: String? { get { diff --git a/Rocket.Chat/Managers/Model/AuthManager/AuthManagerCurrentUser.swift b/Rocket.Chat/Managers/Model/AuthManager/AuthManagerCurrentUser.swift index ccb30f37c2..ea46fc6fb3 100644 --- a/Rocket.Chat/Managers/Model/AuthManager/AuthManagerCurrentUser.swift +++ b/Rocket.Chat/Managers/Model/AuthManager/AuthManagerCurrentUser.swift @@ -9,6 +9,7 @@ import Foundation extension AuthManager { + /** - returns: Current user object, if exists. */ diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift b/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift index 70bb4ce843..3c186ecd99 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageCell.swift @@ -155,7 +155,7 @@ final class ChatMessageCell: UICollectionViewCell { func insertButtonActions() -> CGFloat { var addedHeight = CGFloat(0) - if message.subscription.roomBroadcast { + if message.isBroadcastReplyAvailable() { if let view = ChatMessageActionButtonsView.instantiateFromNib() { view.message = message view.delegate = delegate @@ -186,7 +186,6 @@ final class ChatMessageCell: UICollectionViewCell { //swiftlint:disable cyclomatic_complexity func insertAttachments() { var mediaViewHeight = CGFloat(0) - mediaViewHeight += insertButtonActions() mediaViewHeight += insertURLs() message.attachments.forEach { attachment in @@ -242,6 +241,7 @@ final class ChatMessageCell: UICollectionViewCell { } } + mediaViewHeight += insertButtonActions() mediaViewsHeightConstraint.constant = CGFloat(mediaViewHeight) } @@ -334,7 +334,7 @@ extension ChatMessageCell { total += (attributedString?.heightForView(withWidth: fullWidth - 55) ?? 0) } - if message.subscription.roomBroadcast { + if message.isBroadcastReplyAvailable() { total += ChatMessageActionButtonsView.defaultHeight } From c331e047356db1b5f2b3e8019994929f8fa21228 Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Thu, 10 May 2018 09:19:17 -0300 Subject: [PATCH 07/17] Write some tests and improve performance check for message broadcast --- .../Extensions/Models/MessageExtensions.swift | 3 +- Rocket.ChatTests/Models/MessageSpec.swift | 73 +++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/Rocket.Chat/Extensions/Models/MessageExtensions.swift b/Rocket.Chat/Extensions/Models/MessageExtensions.swift index ea74306562..bbc023e7f8 100644 --- a/Rocket.Chat/Extensions/Models/MessageExtensions.swift +++ b/Rocket.Chat/Extensions/Models/MessageExtensions.swift @@ -15,6 +15,7 @@ extension Message { !temporary, !failed, !markedForDeletion, + subscription.roomBroadcast, !isSystemMessage(), let currentUser = AuthManager.currentUser(), currentUser.identifier != user?.identifier @@ -22,7 +23,7 @@ extension Message { return false } - return subscription.roomBroadcast + return true } func isSystemMessage() -> Bool { diff --git a/Rocket.ChatTests/Models/MessageSpec.swift b/Rocket.ChatTests/Models/MessageSpec.swift index f42843e773..2133d3e43b 100644 --- a/Rocket.ChatTests/Models/MessageSpec.swift +++ b/Rocket.ChatTests/Models/MessageSpec.swift @@ -203,6 +203,79 @@ extension MessageSpec { } +// MARK: Broadcast + +extension MessageSpec { + + func testMessageBroadcastTrue() { + let subscription = Subscription() + subscription.identifier = "1" + subscription.roomBroadcast = true + + let user = User() + user.identifier = "1" + + let message = Message() + message.subscription = subscription + message.text = "foobar" + message.user = user + + XCTAssertTrue(message.isBroadcastReplyAvailable()) + } + + func testMessageSystemBroadcastFalse() { + let subscription = Subscription() + subscription.identifier = "1" + subscription.roomBroadcast = true + + let message = Message() + message.subscription = subscription + message.internalType = MessageType.roomArchived.rawValue + + XCTAssertFalse(message.isBroadcastReplyAvailable()) + } + + func testMessageTemporaryBroadcastFalse() { + let subscription = Subscription() + subscription.identifier = "1" + subscription.roomBroadcast = true + + let message = Message() + message.subscription = subscription + message.text = "foobar" + message.temporary = true + + XCTAssertFalse(message.isBroadcastReplyAvailable()) + } + + func testMessageFailedBroadcastFalse() { + let subscription = Subscription() + subscription.identifier = "1" + subscription.roomBroadcast = true + + let message = Message() + message.subscription = subscription + message.text = "foobar" + message.failed = true + + XCTAssertFalse(message.isBroadcastReplyAvailable()) + } + + func testMessageCurrentUserBroadcastFalse() { + let subscription = Subscription() + subscription.identifier = "1" + subscription.roomBroadcast = true + + let message = Message() + message.subscription = subscription + message.text = "foobar" + message.failed = true + + XCTAssertFalse(message.isBroadcastReplyAvailable()) + } + +} + // MARK: Equatable extension MessageSpec { From 61084378bb0ac291201b41a97609add493bd1049 Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Thu, 10 May 2018 10:04:36 -0300 Subject: [PATCH 08/17] Write some tests for broadcasting --- .../Extensions/Models/MessageExtensions.swift | 11 +++++-- .../AuthManager/AuthManagerCurrentUser.swift | 6 ++-- Rocket.ChatTests/Models/MessageSpec.swift | 29 +++++++++++++++---- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Rocket.Chat/Extensions/Models/MessageExtensions.swift b/Rocket.Chat/Extensions/Models/MessageExtensions.swift index bbc023e7f8..3ddfade8c8 100644 --- a/Rocket.Chat/Extensions/Models/MessageExtensions.swift +++ b/Rocket.Chat/Extensions/Models/MessageExtensions.swift @@ -7,17 +7,24 @@ // import UIKit +import RealmSwift extension Message { - func isBroadcastReplyAvailable() -> Bool { + /** + This method will return if the reply button + in a broadcast room needs to be displayed or + not for the message. If the subscription is not + a broadcast type, it'll return false. + */ + func isBroadcastReplyAvailable(realm: Realm? = nil) -> Bool { guard !temporary, !failed, !markedForDeletion, subscription.roomBroadcast, !isSystemMessage(), - let currentUser = AuthManager.currentUser(), + let currentUser = AuthManager.currentUser(realm: realm), currentUser.identifier != user?.identifier else { return false diff --git a/Rocket.Chat/Managers/Model/AuthManager/AuthManagerCurrentUser.swift b/Rocket.Chat/Managers/Model/AuthManager/AuthManagerCurrentUser.swift index ea46fc6fb3..adf56f81bf 100644 --- a/Rocket.Chat/Managers/Model/AuthManager/AuthManagerCurrentUser.swift +++ b/Rocket.Chat/Managers/Model/AuthManager/AuthManagerCurrentUser.swift @@ -7,13 +7,13 @@ // import Foundation +import RealmSwift extension AuthManager { - /** - returns: Current user object, if exists. */ - static func currentUser() -> User? { - return isAuthenticated()?.user + static func currentUser(realm: Realm? = Realm.current) -> User? { + return isAuthenticated(realm: realm)?.user } } diff --git a/Rocket.ChatTests/Models/MessageSpec.swift b/Rocket.ChatTests/Models/MessageSpec.swift index 2133d3e43b..f7fa6224d3 100644 --- a/Rocket.ChatTests/Models/MessageSpec.swift +++ b/Rocket.ChatTests/Models/MessageSpec.swift @@ -205,22 +205,39 @@ extension MessageSpec { // MARK: Broadcast -extension MessageSpec { +extension MessageSpec: RealmTestCase { func testMessageBroadcastTrue() { - let subscription = Subscription() - subscription.identifier = "1" - subscription.roomBroadcast = true + let realm = testRealm() + + let auth = Auth() + auth.serverURL = "https://foo.com/" + auth.token = "123" + auth.tokenExpires = Date() + auth.lastAccess = Date() + auth.userId = "1" let user = User() user.identifier = "1" + let userOther = User() + userOther.identifier = "2" + + Realm.executeOnMainThread(realm: realm, { realm in + realm.add(auth) + realm.add(user) + }) + + let subscription = Subscription() + subscription.identifier = "1" + subscription.roomBroadcast = true + let message = Message() message.subscription = subscription message.text = "foobar" - message.user = user + message.user = userOther - XCTAssertTrue(message.isBroadcastReplyAvailable()) + XCTAssertTrue(message.isBroadcastReplyAvailable(realm: realm)) } func testMessageSystemBroadcastFalse() { From 57554db8afb71b915bc3e7d421ce9f60df60aa85 Mon Sep 17 00:00:00 2001 From: Rafael Kellermann Streit Date: Thu, 10 May 2018 10:09:25 -0300 Subject: [PATCH 09/17] Fixed a bug & increase top spacing of the button --- Rocket.Chat/Extensions/Models/MessageExtensions.swift | 2 +- Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Rocket.Chat/Extensions/Models/MessageExtensions.swift b/Rocket.Chat/Extensions/Models/MessageExtensions.swift index 3ddfade8c8..dab17e9434 100644 --- a/Rocket.Chat/Extensions/Models/MessageExtensions.swift +++ b/Rocket.Chat/Extensions/Models/MessageExtensions.swift @@ -17,7 +17,7 @@ extension Message { not for the message. If the subscription is not a broadcast type, it'll return false. */ - func isBroadcastReplyAvailable(realm: Realm? = nil) -> Bool { + func isBroadcastReplyAvailable(realm: Realm? = Realm.current) -> Bool { guard !temporary, !failed, diff --git a/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib index b16629070a..ca68e8a6ca 100644 --- a/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib +++ b/Rocket.Chat/Views/Cells/Chat/ChatMessageActionButtonsView.xib @@ -17,7 +17,7 @@