mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-30 21:26:57 +02:00
RoomContextualMenuViewController: Handle updated ReactionsMenuView and new animations instructions.
This commit is contained in:
@@ -31,7 +31,7 @@ import Foundation
|
||||
|
||||
// MARK: Public
|
||||
|
||||
@objc weak var viewModelDelegate: ReactionsMenuViewModelCoordinatorDelegate?
|
||||
@objc weak var coordinatorDelegate: ReactionsMenuViewModelCoordinatorDelegate?
|
||||
weak var viewDelegate: ReactionsMenuViewModelViewDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
@@ -21,19 +21,20 @@
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Szx-Dr-Ndt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="793"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Vdy-rp-3g9" customClass="ReactionsMenuView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="100" width="414" height="100"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Vdy-rp-3g9">
|
||||
<rect key="frame" x="10" y="150" width="394" height="50"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="100" id="D3i-aE-kdL"/>
|
||||
<constraint firstAttribute="height" constant="50" id="D3i-aE-kdL"/>
|
||||
<constraint firstAttribute="width" relation="lessThanOrEqual" priority="999" constant="400" id="Kdn-SI-BvA"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Vdy-rp-3g9" firstAttribute="bottom" secondItem="Szx-Dr-Ndt" secondAttribute="top" constant="200" id="0GH-Qk-vKA"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Vdy-rp-3g9" secondAttribute="trailing" id="9Gu-dr-IPv"/>
|
||||
<constraint firstItem="Vdy-rp-3g9" firstAttribute="leading" secondItem="Szx-Dr-Ndt" secondAttribute="leading" id="h78-sP-xDx"/>
|
||||
<constraint firstItem="Vdy-rp-3g9" firstAttribute="width" secondItem="Szx-Dr-Ndt" secondAttribute="width" priority="750" id="Io5-6N-mvK"/>
|
||||
<constraint firstItem="Vdy-rp-3g9" firstAttribute="centerX" secondItem="Szx-Dr-Ndt" secondAttribute="centerX" id="epY-Ub-0d5"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0GC-JU-rI3" customClass="RoomContextualMenuToolbarView" customModule="Riot" customModuleProvider="target">
|
||||
@@ -49,8 +50,10 @@
|
||||
<constraint firstAttribute="trailing" secondItem="Szx-Dr-Ndt" secondAttribute="trailing" id="2eB-6O-P3h"/>
|
||||
<constraint firstItem="Szx-Dr-Ndt" firstAttribute="leading" secondItem="X0o-r8-auN" secondAttribute="leading" id="4qK-G6-nr9"/>
|
||||
<constraint firstItem="Szx-Dr-Ndt" firstAttribute="top" secondItem="X0o-r8-auN" secondAttribute="top" id="GVa-P9-DcG"/>
|
||||
<constraint firstItem="Vdy-rp-3g9" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="225-y0-Elg" secondAttribute="leading" constant="10" id="R2Z-jH-SRN"/>
|
||||
<constraint firstItem="0GC-JU-rI3" firstAttribute="leading" secondItem="X0o-r8-auN" secondAttribute="leading" id="TZJ-nm-Ppz"/>
|
||||
<constraint firstItem="0GC-JU-rI3" firstAttribute="top" secondItem="Szx-Dr-Ndt" secondAttribute="bottom" id="Wyl-wh-kh4"/>
|
||||
<constraint firstItem="225-y0-Elg" firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Vdy-rp-3g9" secondAttribute="trailing" constant="10" id="j9U-2p-huj"/>
|
||||
<constraint firstAttribute="trailing" secondItem="0GC-JU-rI3" secondAttribute="trailing" id="lzM-FD-x89"/>
|
||||
<constraint firstItem="225-y0-Elg" firstAttribute="bottom" secondItem="0GC-JU-rI3" secondAttribute="bottom" id="s4i-80-0iu"/>
|
||||
</constraints>
|
||||
@@ -61,7 +64,7 @@
|
||||
<outlet property="menuToolbarView" destination="0GC-JU-rI3" id="j0z-I8-Pcr"/>
|
||||
<outlet property="menuToolbarViewBottomConstraint" destination="s4i-80-0iu" id="E5w-5m-m5O"/>
|
||||
<outlet property="menuToolbarViewHeightConstraint" destination="ynL-KP-iB4" id="Zeb-b0-Yil"/>
|
||||
<outlet property="reactionsMenuView" destination="Vdy-rp-3g9" id="jJT-mz-vg6"/>
|
||||
<outlet property="reactionsMenuContainerView" destination="Vdy-rp-3g9" id="hRj-C0-5VR"/>
|
||||
<outlet property="reactionsMenuViewBottomConstraint" destination="0GH-Qk-vKA" id="8lg-XL-JgW"/>
|
||||
<outlet property="reactionsMenuViewHeightConstraint" destination="D3i-aE-kdL" id="CCr-hW-2dv"/>
|
||||
</connections>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user