From af92b980658c8b70600a3a51fc6c0cbb7e030ba0 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 25 Jun 2019 12:06:54 +0200 Subject: [PATCH 1/8] Update ReactionsMenuButton UI --- .../ReactionsMenu/ReactionsMenuButton.swift | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuButton.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuButton.swift index ae12573ecf..6da7eb19bf 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuButton.swift +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuButton.swift @@ -18,7 +18,14 @@ import UIKit class ReactionsMenuButton: UIButton, Themable { - // MARK: Private + // MARK: - Constants + + private enum Constants { + static let borderWidthSelected: CGFloat = 1/UIScreen.main.scale + static let borderColorAlpha: CGFloat = 0.15 + } + + // MARK: - Properties private var theme: Theme! @@ -38,8 +45,8 @@ class ReactionsMenuButton: UIButton, Themable { override func layoutSubviews() { super.layoutSubviews() - self.layer.cornerRadius = self.frame.size.height / 2 - self.layer.borderWidth = self.isSelected ? 1 : 0 + self.layer.cornerRadius = self.frame.size.height / 3 + self.layer.borderWidth = self.isSelected ? Constants.borderWidthSelected : 0 } // MARK: - Private @@ -59,16 +66,15 @@ class ReactionsMenuButton: UIButton, Themable { func update(theme: Theme) { self.theme = theme - - // TODO: Color for black theme + self.setTitleColor(self.theme.textPrimaryColor, for: .normal) self.setTitleColor(self.theme.textPrimaryColor, for: .selected) - self.layer.borderColor = self.theme.tintColor.cgColor + self.layer.borderColor = self.theme.tintColor.withAlphaComponent(Constants.borderColorAlpha).cgColor } private func updateView() { - backgroundColor = isSelected ? self.theme.tintBackgroundColor : self.theme.headerBackgroundColor + backgroundColor = isSelected ? self.theme.tintBackgroundColor : UIColor.clear } override open var isSelected: Bool { From 833ba360ee664a7e8731705df7d2d5c3777c2938 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 25 Jun 2019 13:23:07 +0200 Subject: [PATCH 2/8] Update ReactionsMenuViewModel to handle a list of reactions. --- ...n.swift => ReactionMenuItemViewData.swift} | 14 +- .../ReactionsMenuViewAction.swift | 3 +- .../ReactionsMenuViewModel.swift | 171 +++++------------- .../ReactionsMenuViewModelType.swift | 16 +- .../ReactionsMenuViewState.swift | 22 +++ 5 files changed, 77 insertions(+), 149 deletions(-) rename Riot/Modules/Room/ContextualMenu/ReactionsMenu/{ReactionsMenuReaction.swift => ReactionMenuItemViewData.swift} (80%) create mode 100644 Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewState.swift diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuReaction.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionMenuItemViewData.swift similarity index 80% rename from Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuReaction.swift rename to Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionMenuItemViewData.swift index 93de3403db..df9f4ed27c 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuReaction.swift +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionMenuItemViewData.swift @@ -1,12 +1,12 @@ /* 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. @@ -16,9 +16,7 @@ import Foundation -enum ReactionsMenuReaction: String { - case agree = "👍" - case disagree = "👎" - case like = "🙂" - case dislike = "😔" +struct ReactionMenuItemViewData { + let emoji: String + let isSelected: Bool } diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewAction.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewAction.swift index b98ac829ae..3608a91876 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewAction.swift +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewAction.swift @@ -18,5 +18,6 @@ import UIKit /// Action chosen by the user enum ReactionsMenuViewAction { - case toggleReaction(ReactionsMenuReaction) + case loadData + case tap(reaction: String) } diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift index 846ce20491..c2ec998301 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift @@ -14,158 +14,71 @@ limitations under the License. */ -import UIKit +import Foundation @objc final class ReactionsMenuViewModel: NSObject, ReactionsMenuViewModelType { - + // MARK: - Properties - + + private let reactions = ["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"] + private var currentViewDatas: [ReactionMenuItemViewData] = [] + // MARK: Private - private let aggregations: MXAggregations - private let roomId: String + + private let aggregatedReactions: MXAggregatedReactions? + private let reactionsViewData: [ReactionMenuItemViewData] = [] private let eventId: String - + // MARK: Public - - private(set) var isAgreeButtonSelected: Bool = false - private(set) var isDisagreeButtonSelected: Bool = false - private(set) var isLikeButtonSelected: Bool = false - private(set) var isDislikeButtonSelected: Bool = false - - weak var viewDelegate: ReactionsMenuViewModelDelegate? - @objc weak var coordinatorDelegate: ReactionsMenuViewModelCoordinatorDelegate? - + + @objc weak var viewModelDelegate: ReactionsMenuViewModelCoordinatorDelegate? + weak var viewDelegate: ReactionsMenuViewModelViewDelegate? + // MARK: - Setup - - @objc init(aggregations: MXAggregations, roomId: String, eventId: String) { - self.aggregations = aggregations - self.roomId = roomId + + @objc init(aggregatedReactions: MXAggregatedReactions?, + eventId: String) { + self.aggregatedReactions = aggregatedReactions self.eventId = eventId - - super.init() - - self.loadData() - self.listenToDataUpdate() } - + // MARK: - Public - + func process(viewAction: ReactionsMenuViewAction) { - var reaction: ReactionsMenuReaction? - var newState: Bool? - switch viewAction { - case .toggleReaction(let menuReaction): - reaction = menuReaction - - switch menuReaction { - case .agree: - newState = !self.isAgreeButtonSelected - case .disagree: - newState = !self.isDisagreeButtonSelected - case .like: - newState = !self.isLikeButtonSelected - case .dislike: - newState = !self.isDislikeButtonSelected + case .loadData: + self.loadData() + case .tap(let reaction): + if let viewData = self.currentViewDatas.first(where: { $0.emoji == reaction }) { + if viewData.isSelected { + self.coordinatorDelegate?.reactionsMenuViewModel(self, didRemoveReaction: reaction, forEventId: self.eventId) + } else { + self.coordinatorDelegate?.reactionsMenuViewModel(self, didAddReaction: reaction, forEventId: self.eventId) + } } } - - guard let theReaction = reaction, let theNewState = newState else { - return - } - - self.react(withReaction: theReaction, selected: theNewState) } - + // MARK: - Private - - private func resetData() { - self.isAgreeButtonSelected = false - self.isDisagreeButtonSelected = false - self.isLikeButtonSelected = false - self.isDislikeButtonSelected = false - } - + private func loadData() { - guard let reactionCounts = self.aggregations.aggregatedReactions(onEvent: self.eventId, inRoom: self.roomId)?.withNonZeroCount()?.reactions else { - return - } - - self.resetData() + let reactionCounts = self.aggregatedReactions?.withNonZeroCount()?.reactions ?? [] + + var quickReactionsWithUserReactedFlag: [String: Bool] = Dictionary(uniqueKeysWithValues: self.reactions.map { ($0, false) }) + reactionCounts.forEach { (reactionCount) in - if reactionCount.myUserHasReacted { - if let reaction = ReactionsMenuReaction(rawValue: reactionCount.reaction) { - switch reaction { - case .agree: - self.isAgreeButtonSelected = true - case .disagree: - self.isDisagreeButtonSelected = true - case .like: - self.isLikeButtonSelected = true - case .dislike: - self.isDislikeButtonSelected = true - } - } + if let hasUserReacted = quickReactionsWithUserReactedFlag[reactionCount.reaction], hasUserReacted == false { + quickReactionsWithUserReactedFlag[reactionCount.reaction] = reactionCount.myUserHasReacted } } - - self.viewDelegate?.reactionsMenuViewModelDidUpdate(self) - } - - private func listenToDataUpdate() { - self.aggregations.listenToReactionCountUpdate(inRoom: self.roomId) { [weak self] (changes) in - - guard let sself = self else { - return - } - - if changes[sself.eventId] != nil { - sself.loadData() - } - } - } - - private func react(withReaction reaction: ReactionsMenuReaction, selected: Bool) { - // If required, unreact first - if selected { - self.ensure3StateButtons(withReaction: reaction) + let reactionMenuItemViewDatas: [ReactionMenuItemViewData] = self.reactions.map { reaction -> ReactionMenuItemViewData in + let isSelected = quickReactionsWithUserReactedFlag[reaction] ?? false + return ReactionMenuItemViewData(emoji: reaction, isSelected: isSelected) } - let reactionString = reaction.rawValue + self.currentViewDatas = reactionMenuItemViewDatas - if selected { - self.coordinatorDelegate?.reactionsMenuViewModel(self, didAddReaction: reactionString, forEventId: self.eventId) - } else { - self.coordinatorDelegate?.reactionsMenuViewModel(self, didRemoveReaction: reactionString, forEventId: self.eventId) - } - } - - // We can like, dislike, be indifferent but we cannot like & dislike at the same time - private func ensure3StateButtons(withReaction reaction: ReactionsMenuReaction) { - var unreaction: ReactionsMenuReaction? - - switch reaction { - case .agree: - if isDisagreeButtonSelected { - unreaction = .disagree - } - case .disagree: - if isAgreeButtonSelected { - unreaction = .agree - } - case .like: - if isDislikeButtonSelected { - unreaction = .dislike - } - case .dislike: - if isLikeButtonSelected { - unreaction = .like - } - } - - if let unreaction = unreaction { - self.react(withReaction: unreaction, selected: false) - } + self.viewDelegate?.reactionsMenuViewModel(self, didUpdateViewState: ReactionsMenuViewState.loaded(reactionsViewData: reactionMenuItemViewDatas)) } } diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModelType.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModelType.swift index 111c01d03f..0e162f6c1f 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModelType.swift +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModelType.swift @@ -16,8 +16,8 @@ import Foundation -protocol ReactionsMenuViewModelDelegate: class { - func reactionsMenuViewModelDidUpdate(_ viewModel: ReactionsMenuViewModelType) +protocol ReactionsMenuViewModelViewDelegate: class { + func reactionsMenuViewModel(_ viewModel: ReactionsMenuViewModel, didUpdateViewState viewState: ReactionsMenuViewState) } @objc protocol ReactionsMenuViewModelCoordinatorDelegate: class { @@ -25,16 +25,10 @@ protocol ReactionsMenuViewModelDelegate: class { func reactionsMenuViewModel(_ viewModel: ReactionsMenuViewModel, didRemoveReaction reaction: String, forEventId eventId: String) } - protocol ReactionsMenuViewModelType { - - var isAgreeButtonSelected: Bool { get } - var isDisagreeButtonSelected: Bool { get } - var isLikeButtonSelected: Bool { get } - var isDislikeButtonSelected: Bool { get } - - var viewDelegate: ReactionsMenuViewModelDelegate? { get set } + var coordinatorDelegate: ReactionsMenuViewModelCoordinatorDelegate? { get set } - + var viewDelegate: ReactionsMenuViewModelViewDelegate? { get set } + func process(viewAction: ReactionsMenuViewAction) } diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewState.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewState.swift new file mode 100644 index 0000000000..e74a77ef7b --- /dev/null +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewState.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 + +/// ReactionsMenuView view state +enum ReactionsMenuViewState { + case loaded(reactionsViewData: [ReactionMenuItemViewData]) +} From 96c771bbfeee09805a317868439daa7f1bd50c44 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 25 Jun 2019 13:24:03 +0200 Subject: [PATCH 3/8] Update ReactionsMenuView layout. --- .../ReactionsMenu/ReactionsMenuView.swift | 146 +++++++------- .../ReactionsMenu/ReactionsMenuView.xib | 180 +++++++++--------- 2 files changed, 174 insertions(+), 152 deletions(-) diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift index d4f54bd39e..ce4d91cf74 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.swift @@ -17,93 +17,111 @@ import UIKit import Reusable -final class ReactionsMenuView: UIView, NibOwnerLoadable { - +final class ReactionsMenuView: UIView, Themable, NibLoadable { + + // MARK: - Constants + + private enum Constants { + static let selectedReactionAnimationScale: CGFloat = 1.2 + } + // MARK: - Properties - + // MARK: Outlets - @IBOutlet weak var agreeButton: UIButton! - @IBOutlet weak var disagreeButton: UIButton! - @IBOutlet weak var likeButton: UIButton! - @IBOutlet weak var dislikeButton: UIButton! + @IBOutlet private weak var reactionsBackgroundView: UIView! + @IBOutlet private weak var reactionsStackView: UIStackView! + // MARK: Private - + + private var reactionViewDatas: [ReactionMenuItemViewData] = [] + private var reactionButtons: [ReactionsMenuButton] = [] + private var tappedReactionButton: ReactionsMenuButton? + // MARK: Public - + var viewModel: ReactionsMenuViewModelType? { didSet { - self.updateView() self.viewModel?.viewDelegate = self + self.viewModel?.process(viewAction: .loadData) } } - - // MARK: - Setup - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - self.loadNibContent() - self.commonInit() + + var reactionHasBeenTapped: Bool { + return self.tappedReactionButton != nil } - - override init(frame: CGRect) { - super.init(frame: frame) - self.loadNibContent() - self.commonInit() + + // MARK: - Life cycle + + override func awakeFromNib() { + super.awakeFromNib() + + self.reactionsBackgroundView.layer.masksToBounds = true + self.update(theme: ThemeService.shared().theme) } - - // MARK: - Actions - - @IBAction private func agreeButtonAction(_ sender: Any) { - self.viewModel?.process(viewAction: .toggleReaction(.agree)) + + override func layoutSubviews() { + super.layoutSubviews() + + self.reactionsBackgroundView.layer.cornerRadius = self.reactionsBackgroundView.frame.size.height/2 } - - @IBAction private func disagreeButtonAction(_ sender: Any) { - self.viewModel?.process(viewAction: .toggleReaction(.disagree)) + + // MARK: - Public + + func update(theme: Theme) { + self.reactionsBackgroundView.backgroundColor = theme.headerBackgroundColor } - - @IBAction private func likeButtonAction(_ sender: Any) { - self.viewModel?.process(viewAction: .toggleReaction(.like)) + + func selectionAnimationInstructionPart1() { + guard let tappedButton = self.tappedReactionButton else { + return + } + let scale = Constants.selectedReactionAnimationScale + tappedButton.superview?.bringSubviewToFront(tappedButton) + tappedButton.transform = CGAffineTransform(scaleX: scale, y: scale) } - - @IBAction private func dislikeButtonAction(_ sender: Any) { - self.viewModel?.process(viewAction: .toggleReaction(.dislike)) + + func selectionAnimationInstructionPart2() { + guard let tappedButton = self.tappedReactionButton else { + return + } + tappedButton.transform = CGAffineTransform.identity + tappedButton.isSelected.toggle() } // MARK: - Private - - private func commonInit() { - - agreeButton.setTitle(VectorL10n.roomEventActionReactionAgree(ReactionsMenuReaction.agree.rawValue), for: .normal) - agreeButton.setTitle(VectorL10n.roomEventActionReactionAgree(ReactionsMenuReaction.agree.rawValue), for: .highlighted) - disagreeButton.setTitle(VectorL10n.roomEventActionReactionDisagree(ReactionsMenuReaction.disagree.rawValue), for: .normal) - disagreeButton.setTitle(VectorL10n.roomEventActionReactionDisagree(ReactionsMenuReaction.disagree.rawValue), for: .highlighted) - likeButton.setTitle(VectorL10n.roomEventActionReactionLike(ReactionsMenuReaction.like.rawValue), for: .normal) - likeButton.setTitle(VectorL10n.roomEventActionReactionLike(ReactionsMenuReaction.like.rawValue), for: .highlighted) - dislikeButton.setTitle(VectorL10n.roomEventActionReactionDislike(ReactionsMenuReaction.dislike.rawValue), for: .normal) - dislikeButton.setTitle(VectorL10n.roomEventActionReactionDislike(ReactionsMenuReaction.dislike.rawValue), for: .highlighted) - - customizeViewRendering() - } - - private func customizeViewRendering() { - self.backgroundColor = UIColor.clear + + private func fill(reactionsMenuViewDatas: [ReactionMenuItemViewData]) { + self.reactionViewDatas = reactionsMenuViewDatas + + self.reactionsStackView.vc_removeAllSubviews() + + for reactionViewData in self.reactionViewDatas { + let reactionsMenuButton = ReactionsMenuButton() + reactionsMenuButton.setTitle(reactionViewData.emoji, for: .normal) + reactionsMenuButton.isSelected = reactionViewData.isSelected + reactionsMenuButton.addTarget(self, action: #selector(reactionButtonAction), for: .touchUpInside) + self.reactionsStackView.addArrangedSubview(reactionsMenuButton) + self.reactionButtons.append(reactionsMenuButton) + } } - - private func updateView() { - guard let viewModel = self.viewModel else { + + @objc private func reactionButtonAction(_ sender: ReactionsMenuButton) { + guard let tappedReaction = sender.titleLabel?.text else { return } - - agreeButton.isSelected = viewModel.isAgreeButtonSelected - disagreeButton.isSelected = viewModel.isDisagreeButtonSelected - likeButton.isSelected = viewModel.isLikeButtonSelected - dislikeButton.isSelected = viewModel.isDislikeButtonSelected + self.tappedReactionButton = sender + self.viewModel?.process(viewAction: .tap(reaction: tappedReaction)) } } -extension ReactionsMenuView: ReactionsMenuViewModelDelegate { - func reactionsMenuViewModelDidUpdate(_ viewModel: ReactionsMenuViewModelType) { - self.updateView() +// MARK: - ReactionsMenuViewModelViewDelegate +extension ReactionsMenuView: ReactionsMenuViewModelViewDelegate { + + func reactionsMenuViewModel(_ viewModel: ReactionsMenuViewModel, didUpdateViewState viewState: ReactionsMenuViewState) { + switch viewState { + case .loaded(reactionsViewData: let reactionsViewData): + self.fill(reactionsMenuViewDatas: reactionsViewData) + } } } diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.xib b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.xib index f8ca5acd4e..f2920d92b3 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.xib +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuView.xib @@ -1,113 +1,117 @@ - + - - - - - - - - - + - - + + - - - - + + + + + + + + + + + - - - - - - + + + + - - - - - - - - + - - - - - - - - + + + + - - + + + + + From 77d27d5fce7665d02455bd9e4357e284d5eb70b1 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 25 Jun 2019 13:48:16 +0200 Subject: [PATCH 4/8] RoomContextualMenuViewController: Handle updated ReactionsMenuView and new animations instructions. --- .../ReactionsMenuViewModel.swift | 2 +- ...oomContextualMenuViewController.storyboard | 17 ++- .../RoomContextualMenuViewController.swift | 124 +++++++++++++++--- 3 files changed, 115 insertions(+), 28 deletions(-) diff --git a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift index c2ec998301..c35678cdb6 100644 --- a/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift +++ b/Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift @@ -31,7 +31,7 @@ import Foundation // MARK: Public - @objc weak var viewModelDelegate: ReactionsMenuViewModelCoordinatorDelegate? + @objc weak var coordinatorDelegate: ReactionsMenuViewModelCoordinatorDelegate? weak var viewDelegate: ReactionsMenuViewModelViewDelegate? // MARK: - Setup diff --git a/Riot/Modules/Room/ContextualMenu/RoomContextualMenuViewController.storyboard b/Riot/Modules/Room/ContextualMenu/RoomContextualMenuViewController.storyboard index 711ebfcfb4..f473449964 100644 --- a/Riot/Modules/Room/ContextualMenu/RoomContextualMenuViewController.storyboard +++ b/Riot/Modules/Room/ContextualMenu/RoomContextualMenuViewController.storyboard @@ -21,19 +21,20 @@ - - - + + + - + + - - + + @@ -49,8 +50,10 @@ + + @@ -61,7 +64,7 @@ - + diff --git a/Riot/Modules/Room/ContextualMenu/RoomContextualMenuViewController.swift b/Riot/Modules/Room/ContextualMenu/RoomContextualMenuViewController.swift index d4d9284006..72594e2480 100644 --- a/Riot/Modules/Room/ContextualMenu/RoomContextualMenuViewController.swift +++ b/Riot/Modules/Room/ContextualMenu/RoomContextualMenuViewController.swift @@ -18,12 +18,18 @@ import UIKit @objc protocol RoomContextualMenuViewControllerDelegate: class { func roomContextualMenuViewControllerDidTapBackgroundOverlay(_ viewController: RoomContextualMenuViewController) - func roomContextualMenuViewControllerDidReaction(_ viewController: RoomContextualMenuViewController) } @objcMembers final class RoomContextualMenuViewController: UIViewController, Themable { + // MARK: - Constants + + private enum Constants { + static let reactionsMenuViewVerticalMargin: CGFloat = 10.0 + static let reactionsMenuViewHiddenScale: CGFloat = 0.97 + } + // MARK: - Properties // MARK: Outlets @@ -34,15 +40,20 @@ final class RoomContextualMenuViewController: UIViewController, Themable { @IBOutlet private weak var menuToolbarViewHeightConstraint: NSLayoutConstraint! @IBOutlet private weak var menuToolbarViewBottomConstraint: NSLayoutConstraint! - @IBOutlet private weak var reactionsMenuView: ReactionsMenuView! + @IBOutlet private weak var reactionsMenuContainerView: UIView! @IBOutlet private weak var reactionsMenuViewHeightConstraint: NSLayoutConstraint! @IBOutlet private weak var reactionsMenuViewBottomConstraint: NSLayoutConstraint! // MARK: Private private var theme: Theme! - private var errorPresenter: MXKErrorPresentation! - private var contextualMenuItems: [RoomContextualMenuItem] = [] + private var contextualMenuItems: [RoomContextualMenuItem] = [] + private var reactionsMenuViewModel: ReactionsMenuViewModel? + + private weak var reactionsMenuView: ReactionsMenuView? + + private var reactionsMenuViewBottomStartConstraintConstant: CGFloat? + private var reactionsMenuViewBottomEndConstraintConstant: CGFloat? private var hiddenToolbarViewBottomConstant: CGFloat { let bottomSafeAreaHeight: CGFloat @@ -58,30 +69,40 @@ final class RoomContextualMenuViewController: UIViewController, Themable { // MARK: Public + var contentToReactFrame: CGRect? + var shouldPerformTappedReactionAnimation: Bool { + return self.reactionsMenuView?.reactionHasBeenTapped ?? false + } + weak var delegate: RoomContextualMenuViewControllerDelegate? // MARK: - Setup - class func instantiate(with contextualMenuItems: [RoomContextualMenuItem]) -> RoomContextualMenuViewController { + class func instantiate(with contextualMenuItems: [RoomContextualMenuItem], + reactionsMenuViewModel: ReactionsMenuViewModel?) -> RoomContextualMenuViewController { let viewController = StoryboardScene.RoomContextualMenuViewController.initialScene.instantiate() viewController.theme = ThemeService.shared().theme viewController.contextualMenuItems = contextualMenuItems + viewController.reactionsMenuViewModel = reactionsMenuViewModel return viewController } + // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. - self.reactionsMenuView.isHidden = true + self.reactionsMenuContainerView.isHidden = true + + if let reactionsMenuViewModel = self.reactionsMenuViewModel { + self.setupReactionsMenu(with: reactionsMenuViewModel) + } self.backgroundOverlayView.isUserInteractionEnabled = true self.menuToolbarView.fill(contextualMenuItems: self.contextualMenuItems) self.setupBackgroundOverlayGestureRecognizers() - - self.errorPresenter = MXKErrorAlertPresentation() self.registerThemeServiceDidChangeThemeNotification() self.update(theme: self.theme) @@ -91,31 +112,87 @@ final class RoomContextualMenuViewController: UIViewController, Themable { func showMenuToolbar() { self.menuToolbarViewBottomConstraint.constant = 0 + self.menuToolbarView.alpha = 1 } func hideMenuToolbar() { self.menuToolbarViewBottomConstraint.constant = self.hiddenToolbarViewBottomConstant + self.menuToolbarView.alpha = 0 } - - func showReactionsMenu(withViewModel viewModel: ReactionsMenuViewModel, aroundFrame frame: CGRect) { - self.reactionsMenuView.viewModel = viewModel - self.reactionsMenuView.isHidden = false - + + func prepareReactionsMenuAnimations() { + guard let frame = self.contentToReactFrame else { + return + } + let menuHeight = self.reactionsMenuViewHeightConstraint.constant - + let verticalMargin = Constants.reactionsMenuViewVerticalMargin + + let reactionsMenuViewBottomStartConstraintConstant: CGFloat? + let reactionsMenuViewBottomEndConstraintConstant: CGFloat? + // Try to display the menu at the top of the message first // Then, try at the bottom // Else, keep the position defined in the storyboard - if frame.origin.y >= self.reactionsMenuViewHeightConstraint.constant { - self.reactionsMenuViewBottomConstraint.constant = frame.origin.y + if frame.origin.y - verticalMargin >= menuHeight { + let menuViewBottomY = frame.origin.y - verticalMargin + reactionsMenuViewBottomStartConstraintConstant = menuViewBottomY + menuHeight/2 + reactionsMenuViewBottomEndConstraintConstant = menuViewBottomY } else { - let frameBottomY = frame.origin.y + frame.size.height + let frameBottomY = frame.origin.y + frame.size.height + verticalMargin let visibleViewHeight = self.view.frame.size.height - self.menuToolbarView.frame.size.height - + if frameBottomY + menuHeight < visibleViewHeight { - self.reactionsMenuViewBottomConstraint.constant = frameBottomY + menuHeight + let menuViewBottomY = frameBottomY + menuHeight + + reactionsMenuViewBottomEndConstraintConstant = menuViewBottomY + reactionsMenuViewBottomStartConstraintConstant = menuViewBottomY - menuHeight/2 + } else { + reactionsMenuViewBottomEndConstraintConstant = nil + reactionsMenuViewBottomStartConstraintConstant = nil } } + + self.reactionsMenuViewBottomStartConstraintConstant = reactionsMenuViewBottomStartConstraintConstant + self.reactionsMenuViewBottomEndConstraintConstant = reactionsMenuViewBottomEndConstraintConstant + + self.reactionsMenuContainerView.isHidden = false + } + + func showReactionsMenu() { + guard let reactionsMenuView = self.reactionsMenuView else { + return + } + + if let reactionsMenuViewBottomEndConstraintConstant = self.reactionsMenuViewBottomEndConstraintConstant { + self.reactionsMenuViewBottomConstraint.constant = reactionsMenuViewBottomEndConstraintConstant + } + + reactionsMenuView.alpha = 1 + reactionsMenuContainerView.transform = CGAffineTransform.identity + } + + func hideReactionsMenu() { + guard let reactionsMenuView = self.reactionsMenuView else { + return + } + + if let reactionsMenuViewBottomStartConstraintConstant = self.reactionsMenuViewBottomStartConstraintConstant { + self.reactionsMenuViewBottomConstraint.constant = reactionsMenuViewBottomStartConstraintConstant + } + + reactionsMenuView.alpha = 0 + + let transformScale = Constants.reactionsMenuViewHiddenScale + self.reactionsMenuContainerView.transform = CGAffineTransform(scaleX: transformScale, y: transformScale) + } + + func selectedReactionAnimationsIntructionsPart1() { + self.reactionsMenuView?.selectionAnimationInstructionPart1() + } + + func selectedReactionAnimationsIntructionsPart2() { + self.reactionsMenuView?.selectionAnimationInstructionPart2() } func update(theme: Theme) { @@ -124,6 +201,13 @@ final class RoomContextualMenuViewController: UIViewController, Themable { // MARK: - Private + private func setupReactionsMenu(with viewModel: ReactionsMenuViewModel) { + let reactionsMenuView = ReactionsMenuView.loadFromNib() + self.reactionsMenuContainerView.vc_addSubViewMatchingParent(reactionsMenuView) + reactionsMenuView.viewModel = viewModel + self.reactionsMenuView = reactionsMenuView + } + private func setupBackgroundOverlayGestureRecognizers() { let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handle(gestureRecognizer:))) @@ -155,6 +239,6 @@ extension RoomContextualMenuViewController: UIGestureRecognizerDelegate { // Avoid triggering background overlay gesture recognizers when touching reactions menu func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { - return touch.vc_isInside(view: self.reactionsMenuView) == false + return touch.vc_isInside(view: self.reactionsMenuContainerView) == false } } From dab7d224ebda30e33cc139fe2775fd60a119f1c2 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 25 Jun 2019 13:56:44 +0200 Subject: [PATCH 5/8] RoomContextualMenuPresenter: Handle new reactions menu animations, reduce context menu show/hide animation duration. --- .../RoomContextualMenuPresenter.swift | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/Riot/Modules/Room/ContextualMenu/RoomContextualMenuPresenter.swift b/Riot/Modules/Room/ContextualMenu/RoomContextualMenuPresenter.swift index 5e0fbbc7e2..58e9e2bd48 100644 --- a/Riot/Modules/Room/ContextualMenu/RoomContextualMenuPresenter.swift +++ b/Riot/Modules/Room/ContextualMenu/RoomContextualMenuPresenter.swift @@ -22,7 +22,7 @@ final class RoomContextualMenuPresenter: NSObject { // MARK: - Constants private enum Constants { - static let animationDuration: TimeInterval = 0.3 + static let animationDuration: TimeInterval = 0.2 } // MARK: - Properties @@ -38,28 +38,32 @@ final class RoomContextualMenuPresenter: NSObject { } // MARK: - Public - + func present(roomContextualMenuViewController: RoomContextualMenuViewController, from viewController: UIViewController, on view: UIView, + contentToReactFrame: CGRect, // Not nullable for compatibility with Obj-C animated: Bool, completion: (() -> Void)?) { guard self.roomContextualMenuViewController == nil else { return } - roomContextualMenuViewController.view.alpha = 0 - viewController.vc_addChildViewController(viewController: roomContextualMenuViewController, onView: view) self.roomContextualMenuViewController = roomContextualMenuViewController + roomContextualMenuViewController.contentToReactFrame = contentToReactFrame + roomContextualMenuViewController.hideMenuToolbar() + roomContextualMenuViewController.prepareReactionsMenuAnimations() + roomContextualMenuViewController.hideReactionsMenu() + roomContextualMenuViewController.view.layoutIfNeeded() let animationInstructions: (() -> Void) = { roomContextualMenuViewController.showMenuToolbar() - roomContextualMenuViewController.view.alpha = 1 + roomContextualMenuViewController.showReactionsMenu() roomContextualMenuViewController.view.layoutIfNeeded() } @@ -77,37 +81,43 @@ final class RoomContextualMenuPresenter: NSObject { func hideContextualMenu(animated: Bool, completion: (() -> Void)?) { guard let roomContextualMenuViewController = self.roomContextualMenuViewController else { + completion?() return } let animationInstructions: (() -> Void) = { roomContextualMenuViewController.hideMenuToolbar() - roomContextualMenuViewController.view.alpha = 0 + roomContextualMenuViewController.hideReactionsMenu() roomContextualMenuViewController.view.layoutIfNeeded() } let animationCompletionInstructions: (() -> Void) = { roomContextualMenuViewController.vc_removeFromParent() - - // TODO: To remove once the retain cycle caused by reactionsMenuViewModel is fixed - self.roomContextualMenuViewController = nil - completion?() } if animated { - UIView.animate(withDuration: Constants.animationDuration, animations: { - animationInstructions() - }, completion: { completed in - animationCompletionInstructions() - }) + if roomContextualMenuViewController.shouldPerformTappedReactionAnimation { + UIView.animate(withDuration: 0.15, animations: { + roomContextualMenuViewController.selectedReactionAnimationsIntructionsPart1() + }, completion: { _ in + UIView.animate(withDuration: Constants.animationDuration, animations: { + roomContextualMenuViewController.selectedReactionAnimationsIntructionsPart2() + animationInstructions() + }, completion: { completed in + animationCompletionInstructions() + }) + }) + } else { + UIView.animate(withDuration: Constants.animationDuration, animations: { + animationInstructions() + }, completion: { completed in + animationCompletionInstructions() + }) + } } else { animationInstructions() animationCompletionInstructions() } } - - func showReactionsMenu(reactionsMenuViewModel: ReactionsMenuViewModel, aroundFrame frame: CGRect) { - self.roomContextualMenuViewController?.showReactionsMenu(withViewModel: reactionsMenuViewModel, aroundFrame: frame) - } } From cd57ed1f9b38dfa186226409868205c407aadf74 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 25 Jun 2019 14:00:12 +0200 Subject: [PATCH 6/8] RoomViewController: Handle updated RoomContextualMenuViewController. --- Riot/Modules/Room/RoomViewController.m | 76 +++++++++++++------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index e6c7b2b95d..fab2cd0559 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -5158,21 +5158,13 @@ - (void)showContextualMenuForEvent:(MXEvent*)event cell:(id)ce return; } - [self selectEventWithId:event.eventId]; + NSString *selectedEventId = event.eventId; - NSArray* contextualMenuItems = [self contextualMenuItemsForEvent:event andCell:cell]; - - RoomContextualMenuViewController *roomContextualMenuViewController = [RoomContextualMenuViewController instantiateWith:contextualMenuItems]; - roomContextualMenuViewController.delegate = self; + [self selectEventWithId:selectedEventId]; - [self enableOverlayContainerUserInteractions:YES]; - - [self.roomContextualMenuPresenter presentWithRoomContextualMenuViewController:roomContextualMenuViewController - from:self - on:self.overlayContainerView - animated:YES - completion:^{ - }]; + NSArray* contextualMenuItems = [self contextualMenuItemsForEvent:event andCell:cell]; + ReactionsMenuViewModel *reactionsMenuViewModel; + CGRect bubbleComponentFrameInOverlayView = CGRectNull; if (RiotSettings.shared.messageReaction && [cell isKindOfClass:MXKRoomBubbleTableViewCell.class] && [self.roomDataSource canReactToEventWithId:event.eventId]) { @@ -5181,14 +5173,14 @@ - (void)showContextualMenuForEvent:(MXEvent*)event cell:(id)ce NSArray *bubbleComponents = bubbleCellData.bubbleComponents; NSInteger foundComponentIndex = [bubbleComponents indexOfObjectPassingTest:^BOOL(MXKRoomBubbleComponent * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - if (obj.event.eventId == event.eventId) + if (obj.event.eventId == selectedEventId) { *stop = YES; return YES; } return NO; }]; - + CGRect bubbleComponentFrame; if (bubbleComponents.count > 0) @@ -5201,16 +5193,28 @@ - (void)showContextualMenuForEvent:(MXEvent*)event cell:(id)ce bubbleComponentFrame = roomBubbleTableViewCell.frame; } - CGRect bubbleComponentFrameInOverlayView = [self.bubblesTableView convertRect:bubbleComponentFrame toView:self.overlayContainerView]; + bubbleComponentFrameInOverlayView = [self.bubblesTableView convertRect:bubbleComponentFrame toView:self.overlayContainerView]; NSString *roomId = self.roomDataSource.roomId; MXAggregations *aggregations = self.mainSession.aggregations; + MXAggregatedReactions *aggregatedReactions = [aggregations aggregatedReactionsOnEvent:selectedEventId inRoom:roomId]; - ReactionsMenuViewModel *reactionsMenuViewModel = [[ReactionsMenuViewModel alloc] initWithAggregations:aggregations roomId:roomId eventId:event.eventId]; + reactionsMenuViewModel = [[ReactionsMenuViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:selectedEventId]; reactionsMenuViewModel.coordinatorDelegate = self; - - [self.roomContextualMenuPresenter showReactionsMenuWithReactionsMenuViewModel:reactionsMenuViewModel aroundFrame:bubbleComponentFrameInOverlayView]; } + + RoomContextualMenuViewController *roomContextualMenuViewController = [RoomContextualMenuViewController instantiateWith:contextualMenuItems reactionsMenuViewModel:reactionsMenuViewModel]; + roomContextualMenuViewController.delegate = self; + + [self enableOverlayContainerUserInteractions:YES]; + + [self.roomContextualMenuPresenter presentWithRoomContextualMenuViewController:roomContextualMenuViewController + from:self + on:self.overlayContainerView + contentToReactFrame:bubbleComponentFrameInOverlayView + animated:YES + completion:^{ + }]; } - (void)hideContextualMenuAnimated:(BOOL)animated @@ -5259,41 +5263,39 @@ - (void)roomContextualMenuViewControllerDidTapBackgroundOverlay:(RoomContextualM [self hideContextualMenuAnimated:YES]; } -- (void)roomContextualMenuViewControllerDidReaction:(RoomContextualMenuViewController *)viewController -{ - [self hideContextualMenuAnimated:YES]; -} - #pragma mark - ReactionsMenuViewModelCoordinatorDelegate - (void)reactionsMenuViewModel:(ReactionsMenuViewModel *)viewModel didAddReaction:(NSString *)reaction forEventId:(NSString *)eventId { MXWeakify(self); - [self.roomDataSource addReaction:reaction forEventId:eventId success:^{ + [self hideContextualMenuAnimated:YES completion:^{ - } failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); - - [self.errorPresenter presentErrorFromViewController:self forError:error animated:YES handler:nil]; + [self.roomDataSource addReaction:reaction forEventId:eventId success:^{ + + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + + [self.errorPresenter presentErrorFromViewController:self forError:error animated:YES handler:nil]; + }]; }]; - - [self hideContextualMenuAnimated:YES]; } - (void)reactionsMenuViewModel:(ReactionsMenuViewModel *)viewModel didRemoveReaction:(NSString *)reaction forEventId:(NSString *)eventId { MXWeakify(self); - [self.roomDataSource removeReaction:reaction forEventId:eventId success:^{ + [self hideContextualMenuAnimated:YES completion:^{ - } failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); + [self.roomDataSource removeReaction:reaction forEventId:eventId success:^{ + + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + + [self.errorPresenter presentErrorFromViewController:self forError:error animated:YES handler:nil]; + }]; - [self.errorPresenter presentErrorFromViewController:self forError:error animated:YES handler:nil]; }]; - - [self hideContextualMenuAnimated:YES]; } @end From 8c304d521eda8c480ea057294c88dd146c703304 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 25 Jun 2019 14:00:20 +0200 Subject: [PATCH 7/8] Update pbxproj --- Riot.xcodeproj/project.pbxproj | 44 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 6f8412cefb..21d874c542 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -76,13 +76,8 @@ 32891D75226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32891D73226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift */; }; 32891D76226728EF00C82226 /* DeviceVerificationDataLoadingViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32891D74226728EE00C82226 /* DeviceVerificationDataLoadingViewController.storyboard */; }; 32B1FEDB21A46F2C00637127 /* TermsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32B1FEDA21A46F2C00637127 /* TermsView.xib */; }; - 32B94DF8228EC26400716A26 /* ReactionsMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B94DF1228EC26400716A26 /* ReactionsMenuView.swift */; }; 32B94DF9228EC26400716A26 /* ReactionsMenuViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B94DF2228EC26400716A26 /* ReactionsMenuViewAction.swift */; }; 32B94DFA228EC26400716A26 /* ReactionsMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B94DF3228EC26400716A26 /* ReactionsMenuButton.swift */; }; - 32B94DFB228EC26400716A26 /* ReactionsMenuViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B94DF4228EC26400716A26 /* ReactionsMenuViewModelType.swift */; }; - 32B94DFC228EC26400716A26 /* ReactionsMenuViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B94DF5228EC26400716A26 /* ReactionsMenuViewModel.swift */; }; - 32B94DFD228EC26400716A26 /* ReactionsMenuReaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B94DF6228EC26400716A26 /* ReactionsMenuReaction.swift */; }; - 32B94DFE228EC26400716A26 /* ReactionsMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32B94DF7228EC26400716A26 /* ReactionsMenuView.xib */; }; 32BF994F21FA29A400698084 /* SettingsKeyBackupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BF994E21FA29A400698084 /* SettingsKeyBackupViewModel.swift */; }; 32BF995121FA29DC00698084 /* SettingsKeyBackupViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BF995021FA29DC00698084 /* SettingsKeyBackupViewModelType.swift */; }; 32BF995321FA2A1300698084 /* SettingsKeyBackupViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BF995221FA2A1300698084 /* SettingsKeyBackupViewState.swift */; }; @@ -460,6 +455,12 @@ B1CA3A2921EF692B000D1D89 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CA3A2821EF692B000D1D89 /* UIView.swift */; }; B1CE9EFD22148703000FAE6A /* SignOutAlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CE9EFC22148703000FAE6A /* SignOutAlertPresenter.swift */; }; B1CE9F062216FB09000FAE6A /* EncryptionKeysExportPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CE9F052216FB09000FAE6A /* EncryptionKeysExportPresenter.swift */; }; + B1D1BDA622BBAFB500831367 /* ReactionsMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D1BDA522BBAFB500831367 /* ReactionsMenuView.swift */; }; + B1D1BDA822BBAFC900831367 /* ReactionsMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B1D1BDA722BBAFC900831367 /* ReactionsMenuView.xib */; }; + B1D211E222BD193C00D939BD /* ReactionsMenuViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D211E122BD193C00D939BD /* ReactionsMenuViewModel.swift */; }; + B1D211E422C18E3800D939BD /* ReactionsMenuViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D211E322C18E3800D939BD /* ReactionsMenuViewModelType.swift */; }; + B1D211E622C194A200D939BD /* ReactionsMenuViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D211E522C194A200D939BD /* ReactionsMenuViewState.swift */; }; + B1D211E822C195B400D939BD /* ReactionMenuItemViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D211E722C195B400D939BD /* ReactionMenuItemViewData.swift */; }; B1D250D82118AA0A000F4E93 /* RoomPredecessorBubbleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = B1D250D72118AA0A000F4E93 /* RoomPredecessorBubbleCell.m */; }; B1D4752721EE4E630067973F /* KeyboardAvoider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D4752521EE4E620067973F /* KeyboardAvoider.swift */; }; B1D4752821EE4E630067973F /* KeyboardNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D4752621EE4E620067973F /* KeyboardNotification.swift */; }; @@ -607,13 +608,8 @@ 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 = ""; }; 32B1FEDA21A46F2C00637127 /* TermsView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TermsView.xib; sourceTree = ""; }; - 32B94DF1228EC26400716A26 /* ReactionsMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactionsMenuView.swift; 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 = ""; }; - 32B94DF4228EC26400716A26 /* ReactionsMenuViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactionsMenuViewModelType.swift; sourceTree = ""; }; - 32B94DF5228EC26400716A26 /* ReactionsMenuViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactionsMenuViewModel.swift; sourceTree = ""; }; - 32B94DF6228EC26400716A26 /* ReactionsMenuReaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactionsMenuReaction.swift; sourceTree = ""; }; - 32B94DF7228EC26400716A26 /* ReactionsMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReactionsMenuView.xib; sourceTree = ""; }; 32BDC9A1211C2C870064AF51 /* zh_Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh_Hant; path = zh_Hant.lproj/InfoPlist.strings; sourceTree = ""; }; 32BDC9A2211C2C870064AF51 /* zh_Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh_Hant; path = zh_Hant.lproj/Localizable.strings; sourceTree = ""; }; 32BDC9A3211C2C870064AF51 /* zh_Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh_Hant; path = zh_Hant.lproj/Vector.strings; sourceTree = ""; }; @@ -1197,6 +1193,12 @@ B1CA3A2821EF692B000D1D89 /* UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; B1CE9EFC22148703000FAE6A /* SignOutAlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignOutAlertPresenter.swift; sourceTree = ""; }; B1CE9F052216FB09000FAE6A /* EncryptionKeysExportPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EncryptionKeysExportPresenter.swift; sourceTree = ""; }; + B1D1BDA522BBAFB500831367 /* ReactionsMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsMenuView.swift; sourceTree = ""; }; + B1D1BDA722BBAFC900831367 /* ReactionsMenuView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReactionsMenuView.xib; sourceTree = ""; }; + B1D211E122BD193C00D939BD /* ReactionsMenuViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsMenuViewModel.swift; sourceTree = ""; }; + B1D211E322C18E3800D939BD /* ReactionsMenuViewModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsMenuViewModelType.swift; sourceTree = ""; }; + B1D211E522C194A200D939BD /* ReactionsMenuViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsMenuViewState.swift; sourceTree = ""; }; + B1D211E722C195B400D939BD /* ReactionMenuItemViewData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionMenuItemViewData.swift; sourceTree = ""; }; B1D250D62118AA0A000F4E93 /* RoomPredecessorBubbleCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoomPredecessorBubbleCell.h; sourceTree = ""; }; B1D250D72118AA0A000F4E93 /* RoomPredecessorBubbleCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomPredecessorBubbleCell.m; sourceTree = ""; }; B1D4752521EE4E620067973F /* KeyboardAvoider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardAvoider.swift; sourceTree = ""; }; @@ -1510,13 +1512,14 @@ 32B94DF0228EC26400716A26 /* ReactionsMenu */ = { isa = PBXGroup; children = ( - 32B94DF1228EC26400716A26 /* ReactionsMenuView.swift */, + B1D211E322C18E3800D939BD /* ReactionsMenuViewModelType.swift */, + B1D211E122BD193C00D939BD /* ReactionsMenuViewModel.swift */, + B1D211E722C195B400D939BD /* ReactionMenuItemViewData.swift */, + B1D1BDA522BBAFB500831367 /* ReactionsMenuView.swift */, + B1D1BDA722BBAFC900831367 /* ReactionsMenuView.xib */, + B1D211E522C194A200D939BD /* ReactionsMenuViewState.swift */, 32B94DF2228EC26400716A26 /* ReactionsMenuViewAction.swift */, 32B94DF3228EC26400716A26 /* ReactionsMenuButton.swift */, - 32B94DF4228EC26400716A26 /* ReactionsMenuViewModelType.swift */, - 32B94DF5228EC26400716A26 /* ReactionsMenuViewModel.swift */, - 32B94DF6228EC26400716A26 /* ReactionsMenuReaction.swift */, - 32B94DF7228EC26400716A26 /* ReactionsMenuView.xib */, ); path = ReactionsMenu; sourceTree = ""; @@ -3578,7 +3581,6 @@ B1107ECA2200B09F0038014B /* KeyBackupRecoverSuccessViewController.storyboard in Resources */, B1B5579C20EF575B00210D55 /* ForgotPasswordInputsView.xib in Resources */, F083BE011E7009ED00A9B29C /* third_party_licenses.html in Resources */, - 32B94DFE228EC26400716A26 /* ReactionsMenuView.xib in Resources */, B1098BFC21ECFE65000DDA48 /* PasswordStrengthView.xib in Resources */, B1B5573720EE6C4D00210D55 /* GroupParticipantsViewController.xib in Resources */, B110872421F098F0003554A5 /* ActivityIndicatorView.xib in Resources */, @@ -3601,6 +3603,7 @@ 3232AB1422564D9100AD6A5C /* swiftgen-config.yml in Resources */, 324A204F225FC571004FE8B0 /* DeviceVerificationIncomingViewController.storyboard in Resources */, 3232AB4B2256558300AD6A5C /* TemplateScreenViewController.storyboard in Resources */, + B1D1BDA822BBAFC900831367 /* ReactionsMenuView.xib in Resources */, 32B1FEDB21A46F2C00637127 /* TermsView.xib in Resources */, B1B5578E20EF568D00210D55 /* GroupInviteTableViewCell.xib in Resources */, B1B5582020EF625800210D55 /* SimpleRoomTitleView.xib in Resources */, @@ -3906,6 +3909,7 @@ B1B558C320EF768F00210D55 /* RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.m in Sources */, B110872521F098F0003554A5 /* ActivityIndicatorPresenter.swift in Sources */, 32242F1521E8FBA900725742 /* DarkTheme.swift in Sources */, + B1D211E222BD193C00D939BD /* ReactionsMenuViewModel.swift in Sources */, B140B4A621F89E7600E3F5FE /* KeyBackupSetupCoordinatorBridgePresenter.swift in Sources */, B1B5577420EE702900210D55 /* WidgetViewController.m in Sources */, B139C21B21FE5B9200BB68EC /* KeyBackupRecoverFromPassphraseViewModel.swift in Sources */, @@ -3942,7 +3946,6 @@ B1B5594520EF7BD000210D55 /* TableViewCellWithCollectionView.m in Sources */, 32891D75226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift in Sources */, 32891D712264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift in Sources */, - 32B94DFB228EC26400716A26 /* ReactionsMenuViewModelType.swift in Sources */, F083BDEF1E7009ED00A9B29C /* UINavigationController+Riot.m in Sources */, B1B5581F20EF625800210D55 /* SimpleRoomTitleView.m in Sources */, B1C562E2228C7C8D0037F12A /* RoomContextualMenuViewController.swift in Sources */, @@ -3959,6 +3962,7 @@ 3232ABA7225730E100AD6A5C /* DeviceVerificationStartCoordinator.swift in Sources */, B1D4752721EE4E630067973F /* KeyboardAvoider.swift in Sources */, B1D4752821EE4E630067973F /* KeyboardNotification.swift in Sources */, + B1D1BDA622BBAFB500831367 /* ReactionsMenuView.swift in Sources */, B1B5573C20EE6C4D00210D55 /* MasterTabBarController.m in Sources */, 32F6B96E2270623100BBA352 /* DeviceVerificationDataLoadingViewModelType.swift in Sources */, B1B5592C20EF7A5D00210D55 /* TableViewCellWithButton.m in Sources */, @@ -3998,14 +4002,12 @@ 3232ABAB225730E100AD6A5C /* DeviceVerificationCoordinator.swift in Sources */, B1B5583E20EF6E7F00210D55 /* GroupRoomTableViewCell.m in Sources */, B14F143522144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewController.swift in Sources */, - 32B94DF8228EC26400716A26 /* ReactionsMenuView.swift in Sources */, B1B5574F20EE6C4D00210D55 /* RoomsViewController.m in Sources */, B1B5572520EE6C4D00210D55 /* RoomMessagesSearchViewController.m in Sources */, B139C22121FE5D9D00BB68EC /* KeyBackupRecoverFromPassphraseViewState.swift in Sources */, B1B5579120EF568D00210D55 /* GroupInviteTableViewCell.m in Sources */, B1B5579A20EF575B00210D55 /* ForgotPasswordInputsView.m in Sources */, B1B12B2922942315002CB419 /* UITouch.swift in Sources */, - 32B94DFD228EC26400716A26 /* ReactionsMenuReaction.swift in Sources */, B1B558CC20EF768F00210D55 /* RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.m in Sources */, B1B5571D20EE6C4D00210D55 /* HomeViewController.m in Sources */, 3232ABA6225730E100AD6A5C /* DeviceVerificationStartViewController.swift in Sources */, @@ -4063,6 +4065,7 @@ B140B4A221F87F7100E3F5FE /* OperationQueue.swift in Sources */, B1B5575120EE6C4D00210D55 /* AuthenticationViewController.m in Sources */, B1B5571820EE6C4D00210D55 /* CountryPickerViewController.m in Sources */, + B1D211E622C194A200D939BD /* ReactionsMenuViewState.swift in Sources */, B17982FF2119FED2001FD722 /* GDPRConsentViewController.swift in Sources */, B1098BE121ECE09F000DDA48 /* Images.swift in Sources */, 3232ABA4225730E100AD6A5C /* DeviceVerificationStartViewAction.swift in Sources */, @@ -4120,6 +4123,7 @@ B1B5599420EFC5E400210D55 /* DecryptionFailureTracker.m in Sources */, F083BDF01E7009ED00A9B29C /* UIViewController+RiotSearch.m in Sources */, F083BDF91E7009ED00A9B29C /* RoomEmailInvitation.m in Sources */, + B1D211E422C18E3800D939BD /* ReactionsMenuViewModelType.swift in Sources */, 324A2055225FC571004FE8B0 /* DeviceVerificationIncomingViewModelType.swift in Sources */, B1B5572C20EE6C4D00210D55 /* RoomParticipantsViewController.m in Sources */, B1B558EE20EF768F00210D55 /* RoomOutgoingAttachmentBubbleCell.m in Sources */, @@ -4127,12 +4131,12 @@ 32BF994F21FA29A400698084 /* SettingsKeyBackupViewModel.swift in Sources */, B1B5574920EE6C4D00210D55 /* RiotSplitViewController.m in Sources */, B1B5574E20EE6C4D00210D55 /* DirectoryServerPickerViewController.m in Sources */, + B1D211E822C195B400D939BD /* ReactionMenuItemViewData.swift in Sources */, B1DB4F0B223131600065DBFA /* String.swift in Sources */, 3232AB522256558300AD6A5C /* TemplateScreenViewModel.swift in Sources */, B1B5575B20EE6C4D00210D55 /* HomeFilesSearchViewController.m in Sources */, B139C22521FF01C100BB68EC /* KeyBackupRecoverFromPassphraseCoordinator.swift in Sources */, B1098BFD21ECFE65000DDA48 /* PasswordStrengthManager.swift in Sources */, - 32B94DFC228EC26400716A26 /* ReactionsMenuViewModel.swift in Sources */, B1B558F520EF768F00210D55 /* RoomOutgoingTextMsgWithPaginationTitleBubbleCell.m in Sources */, 3232AB482256558300AD6A5C /* FlowTemplateCoordinatorType.swift in Sources */, B1B558F820EF768F00210D55 /* RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */, From bdae76225c27dda8cd7cd3db97ae74fce77a37bb Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 25 Jun 2019 14:04:54 +0200 Subject: [PATCH 8/8] Update changes --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index 7f6826381e..f291f041ca 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -13,6 +13,7 @@ Improvements: * Message Editing: Editing in the timeline (#2404). * Read receipts: They are now counted at the MatrixKit level. * Migrate to Swift 5.0. + * Reactions: Update quick reactions (#2459). Bug fix: * Device Verification: Fix user display name and device id colors in dark theme