190 lines
7.8 KiB
Swift
190 lines
7.8 KiB
Swift
//
|
||
// CloudDriveFileCell.swift
|
||
// suixinkan
|
||
//
|
||
|
||
import Kingfisher
|
||
import SnapKit
|
||
import UIKit
|
||
|
||
/// 云盘文件 Cell,支持 Android 宫格与列表两种样式。
|
||
final class CloudDriveFileCell: UICollectionViewCell {
|
||
static let reuseIdentifier = "CloudDriveFileCell"
|
||
|
||
var onDetails: (() -> Void)?
|
||
|
||
private let thumbnailView = UIImageView()
|
||
private let folderIconView = UIImageView(image: CloudDriveAsset.image(named: "icon_cloud_storage_folder_type", fallbackSystemName: "folder.fill"))
|
||
private let playIconView = UIImageView(image: CloudDriveAsset.image(named: "icon_cloud_storage_file_play", fallbackSystemName: "play.circle.fill"))
|
||
private let extensionLabel = CloudDrivePaddingLabel()
|
||
private let nameLabel = UILabel()
|
||
private let detailLabel = UILabel()
|
||
private let moreButton = UIButton(type: .system)
|
||
|
||
private var gridConstraints: [Constraint] = []
|
||
private var listConstraints: [Constraint] = []
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
setupUI()
|
||
setupConstraints()
|
||
}
|
||
|
||
@available(*, unavailable)
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
override func prepareForReuse() {
|
||
super.prepareForReuse()
|
||
thumbnailView.kf.cancelDownloadTask()
|
||
thumbnailView.image = nil
|
||
folderIconView.isHidden = true
|
||
playIconView.isHidden = true
|
||
extensionLabel.isHidden = true
|
||
onDetails = nil
|
||
}
|
||
|
||
/// 应用云盘文件数据。
|
||
func apply(file: CloudFile, mode: CloudDriveDisplayMode) {
|
||
nameLabel.text = file.name
|
||
detailLabel.text = mode == .grid ? CloudDriveFormatter.typeName(file.type) : CloudDriveFormatter.fileDescription(file)
|
||
configureThumbnail(file)
|
||
gridConstraints.forEach { mode == .grid ? $0.activate() : $0.deactivate() }
|
||
listConstraints.forEach { mode == .list ? $0.activate() : $0.deactivate() }
|
||
contentView.layer.cornerRadius = mode == .grid ? AppRadius.lg : 0
|
||
contentView.layer.borderWidth = mode == .grid ? 1 : 0
|
||
contentView.backgroundColor = mode == .grid ? .white : .clear
|
||
thumbnailView.layer.cornerRadius = mode == .grid ? AppRadius.lg : 0
|
||
nameLabel.textAlignment = mode == .grid ? .left : .left
|
||
}
|
||
|
||
private func setupUI() {
|
||
contentView.clipsToBounds = true
|
||
contentView.layer.borderColor = UIColor(hex: 0xF4F4F4).cgColor
|
||
|
||
thumbnailView.contentMode = .scaleAspectFill
|
||
thumbnailView.clipsToBounds = true
|
||
thumbnailView.backgroundColor = AppColor.warningBackground
|
||
|
||
folderIconView.tintColor = AppColor.warning
|
||
folderIconView.contentMode = .scaleAspectFit
|
||
|
||
playIconView.tintColor = .white
|
||
playIconView.contentMode = .scaleAspectFit
|
||
playIconView.isHidden = true
|
||
|
||
extensionLabel.font = .app(.caption)
|
||
extensionLabel.textColor = .white
|
||
extensionLabel.backgroundColor = UIColor.black.withAlphaComponent(0.5)
|
||
extensionLabel.layer.cornerRadius = AppRadius.xs
|
||
extensionLabel.clipsToBounds = true
|
||
extensionLabel.isHidden = true
|
||
|
||
nameLabel.font = .app(.body)
|
||
nameLabel.textColor = AppColor.textPrimary
|
||
nameLabel.numberOfLines = 1
|
||
|
||
detailLabel.font = .app(.caption)
|
||
detailLabel.textColor = UIColor(hex: 0x4B5563)
|
||
detailLabel.numberOfLines = 1
|
||
|
||
moreButton.setImage(CloudDriveAsset.image(named: "icon_cloud_storage_file_details", fallbackSystemName: "ellipsis"), for: .normal)
|
||
moreButton.tintColor = AppColor.textSecondary
|
||
moreButton.addTarget(self, action: #selector(moreTapped), for: .touchUpInside)
|
||
|
||
contentView.addSubview(thumbnailView)
|
||
contentView.addSubview(folderIconView)
|
||
contentView.addSubview(playIconView)
|
||
contentView.addSubview(extensionLabel)
|
||
contentView.addSubview(nameLabel)
|
||
contentView.addSubview(detailLabel)
|
||
contentView.addSubview(moreButton)
|
||
}
|
||
|
||
private func setupConstraints() {
|
||
thumbnailView.snp.makeConstraints { make in
|
||
gridConstraints.append(make.top.leading.trailing.equalToSuperview().constraint)
|
||
gridConstraints.append(make.height.equalTo(thumbnailView.snp.width).multipliedBy(0.56).constraint)
|
||
listConstraints.append(make.leading.centerY.equalToSuperview().constraint)
|
||
listConstraints.append(make.width.height.equalTo(48).constraint)
|
||
}
|
||
folderIconView.snp.makeConstraints { make in
|
||
make.center.equalTo(thumbnailView)
|
||
make.width.height.equalTo(42)
|
||
}
|
||
playIconView.snp.makeConstraints { make in
|
||
make.center.equalTo(thumbnailView)
|
||
make.width.height.equalTo(28)
|
||
}
|
||
extensionLabel.snp.makeConstraints { make in
|
||
make.top.leading.equalTo(thumbnailView).offset(AppSpacing.xs)
|
||
}
|
||
nameLabel.snp.makeConstraints { make in
|
||
gridConstraints.append(make.top.equalTo(thumbnailView.snp.bottom).offset(AppSpacing.xs).constraint)
|
||
gridConstraints.append(make.leading.equalToSuperview().offset(AppSpacing.sm).constraint)
|
||
listConstraints.append(make.top.equalToSuperview().offset(AppSpacing.sm).constraint)
|
||
listConstraints.append(make.leading.equalTo(thumbnailView.snp.trailing).offset(AppSpacing.sm).constraint)
|
||
make.trailing.equalTo(moreButton.snp.leading).offset(-AppSpacing.xs)
|
||
}
|
||
detailLabel.snp.makeConstraints { make in
|
||
make.top.equalTo(nameLabel.snp.bottom).offset(AppSpacing.xxs)
|
||
make.leading.equalTo(nameLabel)
|
||
make.trailing.equalTo(nameLabel)
|
||
}
|
||
moreButton.snp.makeConstraints { make in
|
||
make.trailing.equalToSuperview().inset(AppSpacing.xs)
|
||
make.centerY.equalTo(nameLabel.snp.bottom).offset(4)
|
||
make.width.height.equalTo(32)
|
||
}
|
||
listConstraints.forEach { $0.deactivate() }
|
||
}
|
||
|
||
private func configureThumbnail(_ file: CloudFile) {
|
||
if file.isFolder {
|
||
thumbnailView.image = nil
|
||
thumbnailView.backgroundColor = AppColor.warningBackground
|
||
folderIconView.isHidden = false
|
||
extensionLabel.isHidden = true
|
||
return
|
||
}
|
||
folderIconView.isHidden = true
|
||
thumbnailView.backgroundColor = AppColor.inputBackground
|
||
let preview = file.isVideo ? file.coverUrl : file.fileUrl
|
||
if let url = URL(string: preview), !preview.isEmpty {
|
||
let placeholder = CloudDriveAsset.image(
|
||
named: file.isVideo ? "icon_cloud_storage_file_type_video" : "icon_cloud_storage_file_type_photo",
|
||
fallbackSystemName: file.isVideo ? "video" : "photo"
|
||
)
|
||
thumbnailView.kf.setImage(with: url, placeholder: placeholder)
|
||
} else {
|
||
thumbnailView.image = CloudDriveAsset.image(
|
||
named: file.isVideo ? "icon_cloud_storage_file_type_video" : "icon_cloud_storage_file_type_photo",
|
||
fallbackSystemName: file.isVideo ? "video" : "photo"
|
||
)
|
||
thumbnailView.tintColor = AppColor.textTertiary
|
||
}
|
||
playIconView.isHidden = !file.isVideo
|
||
extensionLabel.text = CloudDriveFormatter.fileExtension(file.fileUrl.isEmpty ? file.name : file.fileUrl)
|
||
extensionLabel.isHidden = false
|
||
}
|
||
|
||
@objc private func moreTapped() {
|
||
onDetails?()
|
||
}
|
||
}
|
||
|
||
/// 带内边距的标签。
|
||
private final class CloudDrivePaddingLabel: UILabel {
|
||
var insets = UIEdgeInsets(top: 3, left: 5, bottom: 3, right: 5)
|
||
|
||
override var intrinsicContentSize: CGSize {
|
||
let size = super.intrinsicContentSize
|
||
return CGSize(width: size.width + insets.left + insets.right, height: size.height + insets.top + insets.bottom)
|
||
}
|
||
|
||
override func drawText(in rect: CGRect) {
|
||
super.drawText(in: rect.inset(by: insets))
|
||
}
|
||
}
|