Files
GitHawk/Classes/Issues/IssueTextActionsView.swift
2018-08-11 14:51:11 -04:00

198 lines
6.4 KiB
Swift

//
// IssueTextActionsView.swift
// Freetime
//
// Created by Ryan Nystrom on 7/31/17.
// Copyright © 2017 Ryan Nystrom. All rights reserved.
//
import UIKit
final class IssueTextActionsCell: SelectableCell {
let imageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
imageView.tintColor = Styles.Colors.Gray.dark.color
imageView.contentMode = .center
contentView.addSubview(imageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = contentView.bounds
}
func configure(operation: IssueTextActionOperation) {
imageView.image = operation.icon
imageView.accessibilityLabel = operation.name
}
override var accessibilityLabel: String? {
get {
return AccessibilityHelper.generatedLabel(forCell: self)
}
set { }
}
}
protocol IssueTextActionsViewDelegate: class {
func didSelect(actionsView: IssueTextActionsView, operation: IssueTextActionOperation)
}
protocol IssueTextActionsViewSendDelegate: class {
func didSend(for actionsView: IssueTextActionsView)
}
struct IssueTextActionOperation {
enum Operation {
case line(String)
case wrap(String, String)
case execute(() -> Void)
case multi([Operation])
case uploadImage
}
let icon: UIImage?
let operation: Operation
let name: String
}
final class IssueTextActionsView: UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
weak var delegate: IssueTextActionsViewDelegate?
weak var sendDelegate: IssueTextActionsViewSendDelegate?
private let operations: [IssueTextActionOperation]
private let identifier = "cell"
private let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumInteritemSpacing = Styles.Sizes.rowSpacing
let c = UICollectionView(frame: .zero, collectionViewLayout: layout)
c.backgroundColor = .clear
c.alwaysBounceVertical = false
c.alwaysBounceHorizontal = true
c.showsVerticalScrollIndicator = false
c.showsHorizontalScrollIndicator = false
return c
}()
private let gradientWidth = Styles.Sizes.gutter
private let sendButtonGradientLayer = CAGradientLayer()
private let sendButton = UIButton()
public var sendButtonEnabled: Bool {
get { return sendButton.isEnabled }
set {
sendButton.isEnabled = newValue
sendButton.alpha = newValue ? 1 : 0.25
}
}
init(operations: [IssueTextActionOperation], showSendButton: Bool) {
self.operations = operations
super.init(frame: .zero)
translatesAutoresizingMaskIntoConstraints = false
collectionView.clipsToBounds = true
collectionView.register(IssueTextActionsCell.self, forCellWithReuseIdentifier: identifier)
collectionView.dataSource = self
collectionView.delegate = self
addSubview(collectionView)
if showSendButton {
collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: gradientWidth)
sendButtonGradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
sendButtonGradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
sendButtonGradientLayer.colors = [UIColor(white: 1, alpha: 0).cgColor, UIColor.white.cgColor]
layer.addSublayer(sendButtonGradientLayer)
let blue = Styles.Colors.Blue.medium.color
sendButton.tintColor = blue
sendButton.imageView?.tintColor = blue
sendButton.setImage(UIImage(named: "send")?.withRenderingMode(.alwaysTemplate), for: .normal)
sendButton.addTarget(self, action: #selector(onSend), for: .touchUpInside)
addSubview(sendButton)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
if sendButton.superview != nil {
let height = bounds.height
let imageWidth = sendButton.image(for: .normal)?.size.width ?? 0
let buttonWidth = imageWidth + 2*Styles.Sizes.gutter
sendButton.frame = CGRect(
x: bounds.width - buttonWidth,
y: 0,
width: buttonWidth,
height: height
)
sendButtonGradientLayer.frame = CGRect(
x: sendButton.frame.minX - gradientWidth,
y: 0,
width: gradientWidth,
height: height
)
// put collection view beneath the gradient layer
collectionView.frame = CGRect(x: 0, y: 0, width: sendButton.frame.minX, height: height)
} else {
collectionView.frame = bounds
}
}
@objc private func onSend() {
sendDelegate?.didSend(for: self)
}
// MARK: UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return operations.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as? IssueTextActionsCell
else { fatalError("Wrong cell type") }
cell.configure(operation: operations[indexPath.item])
return cell
}
// MARK: UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: trueUnlessReduceMotionEnabled)
delegate?.didSelect(actionsView: self, operation: operations[indexPath.item])
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = collectionView.bounds.height
return CGSize(
width: (operations[indexPath.item].icon?.size.width ?? 0) + Styles.Sizes.rowSpacing*2,
height: height
)
}
}