mirror of
https://github.com/zhigang1992/GitHawk.git
synced 2026-03-29 22:39:31 +08:00
198 lines
6.4 KiB
Swift
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
|
|
)
|
|
}
|
|
|
|
}
|