Files
suixinkan_uikit/suixinkan/UI/CloudDrive/CloudDriveTransferViewController.swift

235 lines
8.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// CloudDriveTransferViewController.swift
// suixinkan
//
import SnapKit
import UIKit
/// Android `CloudStorageTransitScreen`
final class CloudDriveTransferViewController: BaseViewController {
private enum Tab: Int {
case upload
case download
}
private let manager: CloudTransferManager
private let segmentedControl = UISegmentedControl(items: ["上传", "下载"])
private let tableView = UITableView(frame: .zero, style: .plain)
private var selectedTab: Tab = .upload
///
init(manager: CloudTransferManager = .shared) {
self.manager = manager
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setupNavigationBar() {
title = "传输管理"
}
override func setupUI() {
view.backgroundColor = AppColor.pageBackground
segmentedControl.selectedSegmentIndex = selectedTab.rawValue
tableView.backgroundColor = AppColor.pageBackground
tableView.separatorStyle = .none
tableView.dataSource = self
tableView.delegate = self
tableView.register(CloudTransferCell.self, forCellReuseIdentifier: CloudTransferCell.reuseIdentifier)
view.addSubview(segmentedControl)
view.addSubview(tableView)
}
override func setupConstraints() {
segmentedControl.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide).offset(AppSpacing.sm)
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
make.height.equalTo(36)
}
tableView.snp.makeConstraints { make in
make.top.equalTo(segmentedControl.snp.bottom).offset(AppSpacing.sm)
make.leading.trailing.bottom.equalToSuperview()
}
}
override func bindActions() {
segmentedControl.addTarget(self, action: #selector(tabChanged), for: .valueChanged)
manager.onTasksChange = { [weak self] in
Task { @MainActor in self?.tableView.reloadData() }
}
}
private var visibleTasks: [CloudTransferTask] {
selectedTab == .upload ? manager.uploadTasks : manager.downloadTasks
}
@objc private func tabChanged() {
selectedTab = Tab(rawValue: segmentedControl.selectedSegmentIndex) ?? .upload
tableView.reloadData()
}
}
extension CloudDriveTransferViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
visibleTasks.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
112
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CloudTransferCell.reuseIdentifier, for: indexPath) as! CloudTransferCell
let task = visibleTasks[indexPath.row]
cell.apply(task: task)
cell.onPrimaryAction = { [weak self] in
guard let self else { return }
if task.kind == .upload {
task.status == .uploading ? self.manager.pauseUpload(id: task.id) : self.manager.resumeUpload(id: task.id)
} else {
task.status == .downloading ? self.manager.pauseDownload(id: task.id) : self.manager.resumeDownload(id: task.id)
}
}
cell.onCancel = { [weak self] in
guard let self else { return }
task.kind == .upload ? self.manager.cancelUpload(id: task.id) : self.manager.cancelDownload(id: task.id)
}
return cell
}
}
/// Cell
private final class CloudTransferCell: UITableViewCell {
static let reuseIdentifier = "CloudTransferCell"
var onPrimaryAction: (() -> Void)?
var onCancel: (() -> Void)?
private let cardView = UIView()
private let iconView = UIImageView()
private let titleLabel = UILabel()
private let statusLabel = UILabel()
private let primaryButton = UIButton(type: .system)
private let cancelButton = UIButton(type: .system)
private let progressView = UIProgressView(progressViewStyle: .default)
private let percentLabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
setupConstraints()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
onPrimaryAction = nil
onCancel = nil
}
func apply(task: CloudTransferTask) {
iconView.image = CloudDriveAsset.image(
named: task.fileType == 1 ? "icon_cloud_storage_file_type_video" : "icon_cloud_storage_file_type_photo",
fallbackSystemName: task.fileType == 1 ? "video.fill" : "photo.fill"
)
titleLabel.text = task.fileName
statusLabel.text = "\(task.status.title) \(CloudDriveFormatter.fileSize(task.fileSize))"
progressView.progress = Float(task.progress) / 100
percentLabel.text = "\(task.progress)%"
let isRunning = task.status == .uploading || task.status == .downloading
primaryButton.setImage(UIImage(systemName: isRunning ? "pause.fill" : "play.fill"), for: .normal)
primaryButton.isHidden = task.status == .completed
}
private func setupUI() {
backgroundColor = .clear
selectionStyle = .none
cardView.backgroundColor = .white
cardView.layer.cornerRadius = AppRadius.sm
cardView.clipsToBounds = true
iconView.tintColor = AppColor.primary
iconView.contentMode = .scaleAspectFit
titleLabel.font = .app(.body)
titleLabel.textColor = AppColor.textPrimary
titleLabel.lineBreakMode = .byTruncatingMiddle
statusLabel.font = .app(.caption)
statusLabel.textColor = AppColor.textTertiary
progressView.progressTintColor = AppColor.primary
percentLabel.font = .app(.caption)
percentLabel.textColor = AppColor.textSecondary
percentLabel.textAlignment = .right
primaryButton.tintColor = AppColor.primary
cancelButton.tintColor = AppColor.textSecondary
cancelButton.setImage(UIImage(systemName: "xmark"), for: .normal)
primaryButton.addTarget(self, action: #selector(primaryTapped), for: .touchUpInside)
cancelButton.addTarget(self, action: #selector(cancelTapped), for: .touchUpInside)
contentView.addSubview(cardView)
cardView.addSubview(iconView)
cardView.addSubview(titleLabel)
cardView.addSubview(statusLabel)
cardView.addSubview(primaryButton)
cardView.addSubview(cancelButton)
cardView.addSubview(progressView)
cardView.addSubview(percentLabel)
}
private func setupConstraints() {
cardView.snp.makeConstraints { make in
make.top.bottom.equalToSuperview().inset(AppSpacing.xs)
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
}
iconView.snp.makeConstraints { make in
make.leading.top.equalToSuperview().offset(AppSpacing.sm)
make.width.height.equalTo(48)
}
cancelButton.snp.makeConstraints { make in
make.trailing.top.equalToSuperview().inset(AppSpacing.xs)
make.width.height.equalTo(36)
}
primaryButton.snp.makeConstraints { make in
make.trailing.equalTo(cancelButton.snp.leading)
make.centerY.equalTo(cancelButton)
make.width.height.equalTo(36)
}
titleLabel.snp.makeConstraints { make in
make.leading.equalTo(iconView.snp.trailing).offset(AppSpacing.sm)
make.top.equalTo(iconView)
make.trailing.equalTo(primaryButton.snp.leading).offset(-AppSpacing.xs)
}
statusLabel.snp.makeConstraints { make in
make.leading.trailing.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(AppSpacing.xxs)
}
progressView.snp.makeConstraints { make in
make.leading.equalTo(iconView)
make.trailing.equalToSuperview().inset(AppSpacing.sm)
make.top.equalTo(iconView.snp.bottom).offset(AppSpacing.sm)
}
percentLabel.snp.makeConstraints { make in
make.top.equalTo(progressView.snp.bottom).offset(AppSpacing.xxs)
make.trailing.equalTo(progressView)
}
}
@objc private func primaryTapped() {
onPrimaryAction?()
}
@objc private func cancelTapped() {
onCancel?()
}
}