Skip to content
This repository was archived by the owner on Sep 20, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 50 additions & 11 deletions Classes/Issues/Comments/IssueCommentSectionController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import IGListKit
import TUSafariActivity
import Squawk
import GitHubAPI
import ContextMenu

protocol IssueCommentSectionControllerDelegate: class {
func didSelectReply(
Expand All @@ -27,7 +28,8 @@ final class IssueCommentSectionController:
IssueCommentReactionCellDelegate,
EditCommentViewControllerDelegate,
MarkdownStyledTextViewDelegate,
IssueCommentDoubleTapDelegate {
IssueCommentDoubleTapDelegate,
ContextMenuDelegate {

private weak var issueCommentDelegate: IssueCommentSectionControllerDelegate?

Expand All @@ -37,7 +39,6 @@ final class IssueCommentSectionController:
private let model: IssueDetailsModel
private var hasBeenDeleted = false
private let autocomplete: IssueCommentAutocomplete
private var menuVisible = false

private lazy var webviewCache: WebviewCellHeightCache = {
return WebviewCellHeightCache(sectionController: self)
Expand Down Expand Up @@ -183,7 +184,7 @@ final class IssueCommentSectionController:

@discardableResult
private func uncollapse() -> Bool {
guard collapsed, !menuVisible else { return false }
guard collapsed else { return false }
collapsed = false
clearCollapseCells()
collectionContext?.invalidateLayout(for: self, completion: nil)
Expand Down Expand Up @@ -468,14 +469,6 @@ final class IssueCommentSectionController:

// MARK: IssueCommentReactionCellDelegate

func willShowMenu(cell: IssueCommentReactionCell) {
menuVisible = true
}

func didHideMenu(cell: IssueCommentReactionCell) {
menuVisible = false
}

func didAdd(cell: IssueCommentReactionCell, reaction: ReactionContent) {
// don't add a reaction if already reacted
guard let reactions = reactionMutation ?? self.object?.reactions,
Expand Down Expand Up @@ -518,6 +511,26 @@ final class IssueCommentSectionController:
viewController?.present(alert, animated: trueUnlessReduceMotionEnabled)
}

func didTapAddReaction(cell: IssueCommentReactionCell, sender: UIView) {
guard let viewController = self.viewController else { return }
ContextMenu.shared.show(
sourceViewController: viewController,
viewController: ReactionsMenuViewController(),
options: ContextMenu.Options(
durations: ContextMenu.AnimationDurations(present: 0.2),
containerStyle: ContextMenu.ContainerStyle(
xPadding: -4,
yPadding: 8,
backgroundColor: Styles.Colors.menuBackgroundColor.color
),
menuStyle: .minimal,
hapticsStyle: .medium
),
sourceView: sender,
delegate: self
)
}

// MARK: MarkdownStyledTextViewDelegate

func didTap(cell: MarkdownStyledTextView, attribute: DetectedMarkdownAttribute) {
Expand All @@ -535,4 +548,30 @@ final class IssueCommentSectionController:
viewController.dismiss(animated: trueUnlessReduceMotionEnabled)
}

// MARK: ContextMenuDelegate

func contextMenuWillDismiss(viewController: UIViewController, animated: Bool) {}

func contextMenuDidDismiss(viewController: UIViewController, animated: Bool) {
guard let reactionViewController = viewController as? ReactionsMenuViewController,
let reaction = reactionViewController.selectedReaction,
let reactions = reactionMutation ?? self.object?.reactions
else { return }

var index = -1
for (i, model) in viewModels.reversed().enumerated() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you're doing here. Can't parse it from the code 😕

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting it in a separate function (+ tests) would not be a bad idea I think 😇

if model is IssueCommentReactionViewModel {
index = viewModels.count - 1 - i
break
}
}

guard index >= 0 else { return }
react(
cell: collectionContext?.cellForItem(at: index, sectionController: self) as? IssueCommentReactionCell,
content: reaction,
isAdd: !reactions.viewerDidReact(reaction: reaction)
)
}

}
47 changes: 4 additions & 43 deletions Classes/Issues/Comments/Reactions/IssueCommentReactionCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import SnapKit
import IGListKit

protocol IssueCommentReactionCellDelegate: class {
func willShowMenu(cell: IssueCommentReactionCell)
func didHideMenu(cell: IssueCommentReactionCell)
func didAdd(cell: IssueCommentReactionCell, reaction: ReactionContent)
func didRemove(cell: IssueCommentReactionCell, reaction: ReactionContent)
func didTapMore(cell: IssueCommentReactionCell, sender: UIView)
func didTapAddReaction(cell: IssueCommentReactionCell, sender: UIView)
}

final class IssueCommentReactionCell: IssueCommentBaseCell,
Expand Down Expand Up @@ -49,7 +48,7 @@ UICollectionViewDelegateFlowLayout {
addButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10)
addButton.setTitleColor(Styles.Colors.Gray.light.color, for: .normal)
addButton.setImage(UIImage(named: "smiley-small")?.withRenderingMode(.alwaysTemplate), for: .normal)
addButton.addTarget(self, action: #selector(IssueCommentReactionCell.onAddButton), for: .touchUpInside)
addButton.addTarget(self, action: #selector(IssueCommentReactionCell.onAddButton(sender:)), for: .touchUpInside)
addButton.accessibilityLabel = NSLocalizedString("Add reaction", comment: "")
addButton.setContentCompressionResistancePriority(.required, for: .horizontal)
contentView.addSubview(addButton)
Expand Down Expand Up @@ -84,20 +83,6 @@ UICollectionViewDelegateFlowLayout {
make.top.bottom.right.equalToSuperview()
make.right.equalTo(moreButton.snp.left).offset(-Styles.Sizes.columnSpacing)
}

let nc = NotificationCenter.default
nc.addObserver(
self,
selector: #selector(onMenuControllerWillShow(notification:)),
name: .UIMenuControllerWillShowMenu,
object: nil
)
nc.addObserver(
self,
selector: #selector(onMenuControllerDidHide(notification:)),
name: .UIMenuControllerDidHideMenu,
object: nil
)
}

required init?(coder aDecoder: NSCoder) {
Expand All @@ -123,22 +108,8 @@ UICollectionViewDelegateFlowLayout {
return collectionView.cellForItem(at: path) as? IssueReactionCell
}

@objc private func onAddButton() {
addButton.becomeFirstResponder()

let actions = [
(ReactionContent.thumbsUp.emoji, #selector(IssueCommentReactionCell.onThumbsUp)),
(ReactionContent.thumbsDown.emoji, #selector(IssueCommentReactionCell.onThumbsDown)),
(ReactionContent.laugh.emoji, #selector(IssueCommentReactionCell.onLaugh)),
(ReactionContent.hooray.emoji, #selector(IssueCommentReactionCell.onHooray)),
(ReactionContent.confused.emoji, #selector(IssueCommentReactionCell.onConfused)),
(ReactionContent.heart.emoji, #selector(IssueCommentReactionCell.onHeart))
]

let menu = UIMenuController.shared
menu.menuItems = actions.map { UIMenuItem(title: $0.0, action: $0.1) }
menu.setTargetRect(addButton.imageView?.frame ?? .zero, in: addButton)
menu.setMenuVisible(true, animated: trueUnlessReduceMotionEnabled)
@objc private func onAddButton(sender: UIView) {
delegate?.didTapAddReaction(cell: self, sender: sender)
}

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
Expand Down Expand Up @@ -208,16 +179,6 @@ UICollectionViewDelegateFlowLayout {
delegate?.didTapMore(cell: self, sender: sender)
}

// MARK: Notifications

@objc func onMenuControllerWillShow(notification: Notification) {
delegate?.willShowMenu(cell: self)
}

@objc func onMenuControllerDidHide(notification: Notification) {
delegate?.didHideMenu(cell: self)
}

// MARK: ListBindable

func bindViewModel(_ viewModel: Any) {
Expand Down
107 changes: 107 additions & 0 deletions Classes/Issues/Comments/Reactions/ReactionsMenuViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//
// ReactionsMenuViewController.swift
// Freetime
//
// Created by Ryan Nystrom on 8/12/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//

import UIKit

final class EmojiCell: UICollectionViewCell {
let label = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)
label.textAlignment = .center
label.backgroundColor = .clear
label.font = UIFont.systemFont(ofSize: Styles.Text.body.size + 4)
contentView.addSubview(label)

selectedBackgroundView = UIView()
selectedBackgroundView?.backgroundColor = Styles.Colors.Gray.medium.color
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func layoutSubviews() {
super.layoutSubviews()
label.frame = contentView.bounds
}

}

final class ReactionsMenuViewController: UICollectionViewController,
UICollectionViewDelegateFlowLayout {

private let reuseIdentifier = "cell"
private let size: CGFloat = 50
private let reactions: [ReactionContent] = [
.thumbsUp,
.hooray,
.thumbsDown,
.heart,
.laugh,
.confused
]

var selectedReaction: ReactionContent? {
guard let item = collectionView?.indexPathsForSelectedItems?.first?.item else { return nil }
return reactions[item]
}

init() {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
super.init(collectionViewLayout: layout)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = Styles.Colors.menuBackgroundColor.color
collectionView?.register(EmojiCell.self, forCellWithReuseIdentifier: reuseIdentifier)
collectionView?.reloadData()
collectionView?.layoutIfNeeded()
preferredContentSize = CGSize(
width: size * CGFloat(reactions.count),
height: size
)
}

// MARK: UICollectionViewDataSource

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return reactions.count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
if let cell = cell as? EmojiCell {
cell.label.text = reactions[indexPath.item].emoji
}
return cell
}

// MARK: UICollectionViewDelegate

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
dismiss(animated: true)
}

// MARK: UICollectionViewDelegateFlowLayout

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(
width: size,
height: size
)
}

}
Loading