diff --git a/Signal/src/ViewControllers/MenuActionsViewController.swift b/Signal/src/ViewControllers/MenuActionsViewController.swift index d18f28aa1..0e20c2f92 100644 --- a/Signal/src/ViewControllers/MenuActionsViewController.swift +++ b/Signal/src/ViewControllers/MenuActionsViewController.swift @@ -71,10 +71,6 @@ class MenuActionsViewController: UIViewController, MenuActionSheetDelegate { let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapBackground)) self.view.addGestureRecognizer(tapGesture) - - let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(didSwipeBackground)) - swipeGesture.direction = .down - self.view.addGestureRecognizer(swipeGesture) } override func viewDidAppear(_ animated: Bool) { @@ -249,11 +245,6 @@ class MenuActionsViewController: UIViewController, MenuActionSheetDelegate { animateDismiss(action: nil) } - @objc - func didSwipeBackground(gesture: UISwipeGestureRecognizer) { - animateDismiss(action: nil) - } - // MARK: MenuActionSheetDelegate func actionSheet(_ actionSheet: MenuActionSheetView, didSelectAction action: MenuAction) { @@ -269,6 +260,7 @@ class MenuActionSheetView: UIView, MenuActionViewDelegate { private let actionStackView: UIStackView private var actions: [MenuAction] + private var actionViews: [MenuActionView] weak var delegate: MenuActionSheetDelegate? override var bounds: CGRect { @@ -288,29 +280,57 @@ class MenuActionSheetView: UIView, MenuActionViewDelegate { actionStackView.spacing = CGHairlineWidth() actions = [] + actionViews = [] super.init(frame: frame) backgroundColor = UIColor.ows_light10 addSubview(actionStackView) - actionStackView.ows_autoPinToSuperviewEdges() + actionStackView.autoPinEdgesToSuperviewEdges() self.clipsToBounds = true - // Prevent panning from percolating to the superview, which would - // cause us to dismiss - let panGestureSink = UIPanGestureRecognizer(target: nil, action: nil) - self.addGestureRecognizer(panGestureSink) + let touchGesture = UILongPressGestureRecognizer(target: self, action: #selector(didTouch(gesture:))) + touchGesture.minimumPressDuration = 0.0 + touchGesture.allowableMovement = CGFloat.greatestFiniteMagnitude + self.addGestureRecognizer(touchGesture) } required init?(coder aDecoder: NSCoder) { fatalError("not implemented") } + @objc + public func didTouch(gesture: UIGestureRecognizer) { + switch gesture.state { + case .possible: + break + case .began: + let location = gesture.location(in: self) + highlightActionView(location: location, fromView: self) + case .changed: + let location = gesture.location(in: self) + highlightActionView(location: location, fromView: self) + case .ended: + Logger.debug("\(logTag) in \(#function) ended") + let location = gesture.location(in: self) + selectActionView(location: location, fromView: self) + case .cancelled: + Logger.debug("\(logTag) in \(#function) canceled") + unhighlightAllActionViews() + case .failed: + Logger.debug("\(logTag) in \(#function) failed") + unhighlightAllActionViews() + } + } + public func addAction(_ action: MenuAction) { + actions.append(action) + let actionView = MenuActionView(action: action) actionView.delegate = self - actions.append(action) + actionViews.append(actionView) + self.actionStackView.addArrangedSubview(actionView) } @@ -329,6 +349,41 @@ class MenuActionSheetView: UIView, MenuActionViewDelegate { mask.path = path.cgPath self.layer.mask = mask } + + private func unhighlightAllActionViews() { + for actionView in actionViews { + actionView.isHighlighted = false + } + } + + private func actionView(touchedBy touchPoint: CGPoint, fromView: UIView) -> MenuActionView? { + for actionView in actionViews { + let convertedPoint = actionView.convert(touchPoint, from: fromView) + if actionView.point(inside: convertedPoint, with: nil) { + return actionView + } + } + return nil + } + + private func highlightActionView(location: CGPoint, fromView: UIView) { + guard let touchedView = actionView(touchedBy: location, fromView: fromView) else { + unhighlightAllActionViews() + return + } + touchedView.isHighlighted = true + self.actionViews.filter { $0 != touchedView }.forEach { $0.isHighlighted = false } + } + + private func selectActionView(location: CGPoint, fromView: UIView) { + guard let selectedView: MenuActionView = actionView(touchedBy: location, fromView: fromView) else { + unhighlightAllActionViews() + return + } + selectedView.isHighlighted = true + self.actionViews.filter { $0 != selectedView }.forEach { $0.isHighlighted = false } + delegate?.actionSheet(self, didSelectAction: selectedView.action) + } } protocol MenuActionViewDelegate: class { @@ -337,7 +392,7 @@ protocol MenuActionViewDelegate: class { class MenuActionView: UIButton { public weak var delegate: MenuActionViewDelegate? - private let action: MenuAction + public let action: MenuAction required init(action: MenuAction) { self.action = action @@ -378,14 +433,15 @@ class MenuActionView: UIButton { contentRow.isUserInteractionEnabled = false self.addSubview(contentRow) - contentRow.ows_autoPinToSuperviewMargins() + contentRow.autoPinEdgesToSuperviewMargins() contentRow.autoSetDimension(.height, toSize: 56, relation: .greaterThanOrEqual) - self.addTarget(self, action: #selector(didPress(sender:)), for: .touchUpInside) + self.isUserInteractionEnabled = false } override var isHighlighted: Bool { didSet { + Logger.debug("\(logTag) in \(#function) \(oldValue) -> \(isHighlighted)") self.backgroundColor = isHighlighted ? UIColor.ows_light10 : UIColor.white } }