重构排队设置与变更日志交互,补充 Overlay 与资源,并将多页面主操作按钮统一到 UIButton Configuration,同步更新相关单元测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
518 lines
22 KiB
Swift
518 lines
22 KiB
Swift
//
|
|
// TravelAlbumDetailViewController.swift
|
|
// suixinkan
|
|
//
|
|
|
|
import Kingfisher
|
|
import SnapKit
|
|
import UIKit
|
|
|
|
/// 相册详情管理页,对齐 Android `TravelAlbumDetailScreen`。
|
|
final class TravelAlbumDetailViewController: BaseViewController {
|
|
private let viewModel: TravelAlbumDetailViewModel
|
|
private let api: any TravelAlbumServing
|
|
|
|
private let scrollContainer = UIView()
|
|
private let infoCard = TravelAlbumInfoCard()
|
|
private let manageCard = UIView()
|
|
private let tabStack = UIStackView()
|
|
private let allTabButton = UIButton(type: .system)
|
|
private let purchasedTabButton = UIButton(type: .system)
|
|
private let sortButton = UIButton(type: .system)
|
|
private let selectButton = UIButton(type: .system)
|
|
private var collectionView: UICollectionView!
|
|
private var dataSource: UICollectionViewDiffableDataSource<Int, TravelAlbumMaterial>!
|
|
private let bottomBar = UIView()
|
|
private let bottomActionStack = UIStackView()
|
|
private let deleteSelectedButton = UIButton(type: .system)
|
|
private let uploadButton = UIButton(type: .system)
|
|
private var isDeleteSelectedButtonVisible = false
|
|
|
|
init(albumId: Int, api: (any TravelAlbumServing)? = nil) {
|
|
viewModel = TravelAlbumDetailViewModel(albumId: albumId)
|
|
self.api = api ?? NetworkServices.shared.travelAlbumAPI
|
|
super.init(nibName: nil, bundle: nil)
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func setupNavigationBar() {
|
|
title = "相册管理"
|
|
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
|
image: UIImage(systemName: "ellipsis"),
|
|
menu: UIMenu(children: [
|
|
UIAction(title: "删除相册", image: UIImage(systemName: "trash"), attributes: .destructive) { [weak self] _ in
|
|
self?.confirmDeleteAlbum()
|
|
},
|
|
])
|
|
)
|
|
}
|
|
|
|
override func setupUI() {
|
|
view.backgroundColor = AppColor.pageBackground
|
|
|
|
manageCard.backgroundColor = .white
|
|
manageCard.layer.cornerRadius = 12
|
|
manageCard.layer.shadowColor = UIColor.black.withAlphaComponent(0.08).cgColor
|
|
manageCard.layer.shadowOpacity = 1
|
|
manageCard.layer.shadowRadius = 6
|
|
manageCard.layer.shadowOffset = CGSize(width: 0, height: 2)
|
|
|
|
tabStack.axis = .horizontal
|
|
tabStack.spacing = 8
|
|
configurePillButton(allTabButton)
|
|
configurePillButton(purchasedTabButton)
|
|
configureIconButton(sortButton, image: UIImage(systemName: "line.3.horizontal.decrease.circle.fill"))
|
|
configureIconButton(selectButton, image: UIImage(systemName: "circle"))
|
|
|
|
collectionView = UICollectionView(frame: .zero, collectionViewLayout: makeLayout())
|
|
collectionView.backgroundColor = .white
|
|
collectionView.delegate = self
|
|
collectionView.register(TravelAlbumMaterialCell.self, forCellWithReuseIdentifier: TravelAlbumMaterialCell.reuseIdentifier)
|
|
dataSource = UICollectionViewDiffableDataSource<Int, TravelAlbumMaterial>(collectionView: collectionView) {
|
|
[weak self] collectionView, indexPath, material in
|
|
let cell = collectionView.dequeueReusableCell(
|
|
withReuseIdentifier: TravelAlbumMaterialCell.reuseIdentifier,
|
|
for: indexPath
|
|
) as! TravelAlbumMaterialCell
|
|
cell.apply(
|
|
material: material,
|
|
selectionMode: self?.viewModel.isSelectionMode == true,
|
|
selected: self?.viewModel.selectedMaterialIds.contains(material.id) == true
|
|
)
|
|
return cell
|
|
}
|
|
|
|
bottomBar.backgroundColor = AppColor.pageBackground
|
|
bottomActionStack.axis = .vertical
|
|
bottomActionStack.spacing = 8
|
|
configureBottomButton(deleteSelectedButton, title: "删除选中(0)", color: UIColor(hex: 0xE53935))
|
|
configureBottomButton(uploadButton, title: "上传照片", color: AppColor.primary)
|
|
deleteSelectedButton.isHidden = true
|
|
deleteSelectedButton.alpha = 0
|
|
|
|
view.addSubview(scrollContainer)
|
|
scrollContainer.addSubview(infoCard)
|
|
scrollContainer.addSubview(manageCard)
|
|
manageCard.addSubview(tabStack)
|
|
tabStack.addArrangedSubview(allTabButton)
|
|
tabStack.addArrangedSubview(purchasedTabButton)
|
|
manageCard.addSubview(sortButton)
|
|
manageCard.addSubview(selectButton)
|
|
manageCard.addSubview(collectionView)
|
|
view.addSubview(bottomBar)
|
|
bottomBar.addSubview(bottomActionStack)
|
|
bottomActionStack.addArrangedSubview(deleteSelectedButton)
|
|
bottomActionStack.addArrangedSubview(uploadButton)
|
|
}
|
|
|
|
override func setupConstraints() {
|
|
bottomBar.snp.makeConstraints { make in
|
|
make.leading.trailing.bottom.equalToSuperview()
|
|
}
|
|
bottomActionStack.snp.makeConstraints { make in
|
|
make.top.equalToSuperview().offset(12)
|
|
make.leading.trailing.equalToSuperview().inset(20)
|
|
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-12)
|
|
}
|
|
deleteSelectedButton.snp.makeConstraints { make in
|
|
make.height.equalTo(48).priority(.high)
|
|
}
|
|
uploadButton.snp.makeConstraints { make in
|
|
make.height.equalTo(48).priority(.high)
|
|
}
|
|
scrollContainer.snp.makeConstraints { make in
|
|
make.top.equalTo(view.safeAreaLayoutGuide).offset(12)
|
|
make.leading.trailing.equalToSuperview().inset(16)
|
|
make.bottom.equalTo(bottomBar.snp.top).offset(-8)
|
|
}
|
|
infoCard.snp.makeConstraints { make in
|
|
make.top.leading.trailing.equalToSuperview()
|
|
make.height.greaterThanOrEqualTo(76)
|
|
}
|
|
manageCard.snp.makeConstraints { make in
|
|
make.top.equalTo(infoCard.snp.bottom).offset(12)
|
|
make.leading.trailing.bottom.equalToSuperview()
|
|
}
|
|
tabStack.snp.makeConstraints { make in
|
|
make.top.leading.equalToSuperview().offset(12)
|
|
make.height.equalTo(32)
|
|
}
|
|
sortButton.snp.makeConstraints { make in
|
|
make.centerY.equalTo(tabStack)
|
|
make.trailing.equalTo(selectButton.snp.leading).offset(-8)
|
|
make.size.equalTo(32)
|
|
}
|
|
selectButton.snp.makeConstraints { make in
|
|
make.centerY.equalTo(tabStack)
|
|
make.trailing.equalToSuperview().offset(-12)
|
|
make.size.equalTo(32)
|
|
}
|
|
collectionView.snp.makeConstraints { make in
|
|
make.top.equalTo(tabStack.snp.bottom).offset(12)
|
|
make.leading.trailing.bottom.equalToSuperview().inset(12)
|
|
}
|
|
}
|
|
|
|
override func bindActions() {
|
|
infoCard.onCall = { [weak self] phone in self?.call(phone) }
|
|
allTabButton.addTarget(self, action: #selector(allTabTapped), for: .touchUpInside)
|
|
purchasedTabButton.addTarget(self, action: #selector(purchasedTabTapped), for: .touchUpInside)
|
|
sortButton.addTarget(self, action: #selector(sortTapped), for: .touchUpInside)
|
|
selectButton.addTarget(self, action: #selector(selectTapped), for: .touchUpInside)
|
|
deleteSelectedButton.addTarget(self, action: #selector(deleteSelectedTapped), for: .touchUpInside)
|
|
uploadButton.addTarget(self, action: #selector(uploadTapped), for: .touchUpInside)
|
|
viewModel.onStateChange = { [weak self] in
|
|
Task { @MainActor in self?.applyViewModel() }
|
|
}
|
|
viewModel.onShowMessage = { [weak self] message in
|
|
Task { @MainActor in self?.showToast(message) }
|
|
}
|
|
viewModel.onDeletedAlbum = { [weak self] _ in
|
|
Task { @MainActor in
|
|
guard let self else { return }
|
|
TravelAlbumOTGPhotoStore().clearAlbum(albumId: self.viewModel.albumId)
|
|
self.navigationController?.popViewController(animated: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
Task { await viewModel.refreshAll(api: api) }
|
|
}
|
|
|
|
@MainActor
|
|
private func applyViewModel() {
|
|
if let album = viewModel.album {
|
|
infoCard.apply(album: album)
|
|
}
|
|
configureTabButton(allTabButton, title: "全部照片\(viewModel.allPhotoCount)", selected: viewModel.selectedTab == .all)
|
|
configureTabButton(purchasedTabButton, title: "已购照片", selected: viewModel.selectedTab == .purchased)
|
|
selectButton.isHidden = viewModel.selectedTab != .all
|
|
selectButton.setImage(UIImage(systemName: viewModel.isSelectionMode ? "checkmark.circle.fill" : "circle"), for: .normal)
|
|
selectButton.tintColor = viewModel.isSelectionMode ? AppColor.primary : AppColor.textTertiary
|
|
deleteSelectedButton.setTitle("删除选中(\(viewModel.selectedMaterialIds.count))", for: .normal)
|
|
setDeleteSelectedButtonVisible(viewModel.isSelectionMode && !viewModel.selectedMaterialIds.isEmpty)
|
|
|
|
var snapshot = NSDiffableDataSourceSnapshot<Int, TravelAlbumMaterial>()
|
|
snapshot.appendSections([0])
|
|
snapshot.appendItems(viewModel.materials)
|
|
if !snapshot.itemIdentifiers.isEmpty {
|
|
snapshot.reconfigureItems(snapshot.itemIdentifiers)
|
|
}
|
|
dataSource.apply(snapshot, animatingDifferences: true)
|
|
|
|
if viewModel.isLoading && viewModel.album == nil {
|
|
showLoading()
|
|
} else {
|
|
hideLoading()
|
|
}
|
|
}
|
|
|
|
private func configurePillButton(_ button: UIButton) {
|
|
button.titleLabel?.font = .systemFont(ofSize: 13, weight: .medium)
|
|
button.layer.cornerRadius = 16
|
|
button.setConfigurationContentInsets(
|
|
NSDirectionalEdgeInsets(top: 7, leading: 14, bottom: 7, trailing: 14)
|
|
)
|
|
}
|
|
|
|
private func configureTabButton(_ button: UIButton, title: String, selected: Bool) {
|
|
button.setTitle(title, for: .normal)
|
|
button.backgroundColor = selected ? AppColor.primary : UIColor(hex: 0xEAF4FF)
|
|
button.setTitleColor(selected ? .white : AppColor.primary, for: .normal)
|
|
}
|
|
|
|
private func configureIconButton(_ button: UIButton, image: UIImage?) {
|
|
button.setImage(image, for: .normal)
|
|
button.backgroundColor = UIColor(hex: 0xEAF4FF)
|
|
button.tintColor = AppColor.primary
|
|
button.layer.cornerRadius = 16
|
|
}
|
|
|
|
private func configureBottomButton(_ button: UIButton, title: String, color: UIColor) {
|
|
button.setTitle(title, for: .normal)
|
|
button.setTitleColor(.white, for: .normal)
|
|
button.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
|
button.backgroundColor = color
|
|
button.layer.cornerRadius = 10
|
|
}
|
|
|
|
private func setDeleteSelectedButtonVisible(_ visible: Bool) {
|
|
guard visible != isDeleteSelectedButtonVisible else { return }
|
|
isDeleteSelectedButtonVisible = visible
|
|
|
|
let changes = {
|
|
self.deleteSelectedButton.isHidden = !visible
|
|
self.deleteSelectedButton.alpha = visible ? 1 : 0
|
|
self.view.layoutIfNeeded()
|
|
}
|
|
guard view.window != nil else {
|
|
changes()
|
|
return
|
|
}
|
|
|
|
view.layoutIfNeeded()
|
|
UIView.animate(
|
|
withDuration: 0.25,
|
|
delay: 0,
|
|
options: [.curveEaseInOut, .beginFromCurrentState],
|
|
animations: changes
|
|
)
|
|
}
|
|
|
|
private func makeLayout() -> UICollectionViewCompositionalLayout {
|
|
UICollectionViewCompositionalLayout { _, environment in
|
|
let spacing: CGFloat = 8
|
|
let width = (environment.container.effectiveContentSize.width - spacing * 2) / 3
|
|
let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(width), heightDimension: .absolute(width + 38))
|
|
let item = NSCollectionLayoutItem(layoutSize: itemSize)
|
|
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(width + 38))
|
|
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: 3)
|
|
group.interItemSpacing = .fixed(spacing)
|
|
let section = NSCollectionLayoutSection(group: group)
|
|
section.interGroupSpacing = 12
|
|
return section
|
|
}
|
|
}
|
|
|
|
private func call(_ phone: String) {
|
|
guard !phone.isEmpty, let url = URL(string: "tel:\(phone)") else { return }
|
|
UIApplication.shared.open(url)
|
|
}
|
|
|
|
private func confirmDeleteAlbum() {
|
|
let alert = UIAlertController(title: "删除相册", message: "确定删除该相册吗?已有购买素材的相册无法删除。", preferredStyle: .alert)
|
|
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
|
|
alert.addAction(UIAlertAction(title: "删除", style: .destructive) { [weak self] _ in
|
|
guard let self else { return }
|
|
Task { await self.viewModel.deleteAlbum(api: self.api) }
|
|
})
|
|
present(alert, animated: true)
|
|
}
|
|
|
|
@objc private func allTabTapped() {
|
|
Task { await viewModel.selectTab(.all, api: api) }
|
|
}
|
|
|
|
@objc private func purchasedTabTapped() {
|
|
Task { await viewModel.selectTab(.purchased, api: api) }
|
|
}
|
|
|
|
@objc private func sortTapped() {
|
|
let alert = UIAlertController(title: "排序", message: nil, preferredStyle: .actionSheet)
|
|
TravelAlbumDetailViewModel.SortOption.allCases.forEach { option in
|
|
alert.addAction(UIAlertAction(title: option.title, style: .default) { [weak self] _ in
|
|
guard let self else { return }
|
|
Task { await self.viewModel.setSortOption(option, api: self.api) }
|
|
})
|
|
}
|
|
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
|
|
present(alert, animated: true)
|
|
}
|
|
|
|
@objc private func selectTapped() {
|
|
viewModel.toggleSelectionMode()
|
|
}
|
|
|
|
@objc private func deleteSelectedTapped() {
|
|
let count = viewModel.selectedMaterialIds.count
|
|
let alert = UIAlertController(title: "删除素材", message: "确定删除选中的 \(count) 张素材吗?", preferredStyle: .alert)
|
|
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
|
|
alert.addAction(UIAlertAction(title: "删除", style: .destructive) { [weak self] _ in
|
|
guard let self else { return }
|
|
Task { await self.viewModel.deleteSelectedMaterials(api: self.api) }
|
|
})
|
|
present(alert, animated: true)
|
|
}
|
|
|
|
@objc private func uploadTapped() {
|
|
let album = viewModel.album
|
|
let controller = WiredCameraTransferViewController(
|
|
viewModel: WiredCameraTransferViewModel(
|
|
albumId: album?.id ?? viewModel.albumId,
|
|
albumTitle: album?.name ?? "",
|
|
headerPhone: album?.displayPhone ?? ""
|
|
)
|
|
)
|
|
navigationController?.pushViewController(controller, animated: true)
|
|
}
|
|
}
|
|
|
|
extension TravelAlbumDetailViewController: UICollectionViewDelegate {
|
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
|
guard let material = dataSource.itemIdentifier(for: indexPath) else { return }
|
|
viewModel.toggleMaterialSelection(material)
|
|
}
|
|
|
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
|
let visible = collectionView.indexPathsForVisibleItems.map(\.item).max() ?? 0
|
|
Task { await viewModel.loadMoreIfNeeded(lastVisibleIndex: visible, api: api) }
|
|
}
|
|
}
|
|
|
|
/// 旅拍相册详情信息卡。
|
|
private final class TravelAlbumInfoCard: UIView {
|
|
var onCall: ((String) -> Void)?
|
|
private var phone = ""
|
|
|
|
private let iconView = UIImageView(image: UIImage(systemName: "checklist"))
|
|
private let phoneLabel = UILabel()
|
|
private let timeLabel = UILabel()
|
|
private let callButton = UIButton(type: .system)
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
backgroundColor = .white
|
|
layer.cornerRadius = 12
|
|
layer.shadowColor = UIColor.black.withAlphaComponent(0.08).cgColor
|
|
layer.shadowOpacity = 1
|
|
layer.shadowRadius = 6
|
|
layer.shadowOffset = CGSize(width: 0, height: 2)
|
|
|
|
let iconBox = UIView()
|
|
iconBox.backgroundColor = AppColor.primary
|
|
iconBox.layer.cornerRadius = 10
|
|
iconView.tintColor = .white
|
|
iconView.contentMode = .scaleAspectFit
|
|
phoneLabel.font = .systemFont(ofSize: 14, weight: .medium)
|
|
phoneLabel.textColor = AppColor.textPrimary
|
|
timeLabel.font = .systemFont(ofSize: 12)
|
|
timeLabel.textColor = AppColor.textTertiary
|
|
callButton.setImage(UIImage(systemName: "phone.fill"), for: .normal)
|
|
callButton.tintColor = AppColor.primary
|
|
callButton.backgroundColor = UIColor(hex: 0xEAF4FF)
|
|
callButton.layer.cornerRadius = 20
|
|
|
|
addSubview(iconBox)
|
|
iconBox.addSubview(iconView)
|
|
addSubview(phoneLabel)
|
|
addSubview(timeLabel)
|
|
addSubview(callButton)
|
|
iconBox.snp.makeConstraints { make in
|
|
make.leading.top.bottom.equalToSuperview().inset(14)
|
|
make.size.equalTo(48)
|
|
}
|
|
iconView.snp.makeConstraints { make in
|
|
make.center.equalToSuperview()
|
|
make.size.equalTo(28)
|
|
}
|
|
phoneLabel.snp.makeConstraints { make in
|
|
make.top.equalToSuperview().offset(16)
|
|
make.leading.equalTo(iconBox.snp.trailing).offset(12)
|
|
make.trailing.equalTo(callButton.snp.leading).offset(-12)
|
|
}
|
|
timeLabel.snp.makeConstraints { make in
|
|
make.top.equalTo(phoneLabel.snp.bottom).offset(6)
|
|
make.leading.trailing.equalTo(phoneLabel)
|
|
make.bottom.equalToSuperview().offset(-16)
|
|
}
|
|
callButton.snp.makeConstraints { make in
|
|
make.trailing.equalToSuperview().offset(-14)
|
|
make.centerY.equalToSuperview()
|
|
make.size.equalTo(40)
|
|
}
|
|
callButton.addTarget(self, action: #selector(callTapped), for: .touchUpInside)
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
func apply(album: TravelAlbum) {
|
|
phone = album.displayPhone
|
|
phoneLabel.text = "手机号 \(TravelAlbumDisplayFormatter.maskPhone(album.displayPhone))"
|
|
timeLabel.text = "创建时间 \(album.createdAt)"
|
|
}
|
|
|
|
@objc private func callTapped() {
|
|
onCall?(phone)
|
|
}
|
|
}
|
|
|
|
/// 旅拍相册素材网格 cell。
|
|
private final class TravelAlbumMaterialCell: UICollectionViewCell {
|
|
static let reuseIdentifier = "TravelAlbumMaterialCell"
|
|
|
|
private let imageView = UIImageView()
|
|
private let statusLabel = UILabel()
|
|
private let checkImageView = UIImageView()
|
|
private let nameLabel = UILabel()
|
|
private let sizeLabel = UILabel()
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
imageView.contentMode = .scaleAspectFill
|
|
imageView.clipsToBounds = true
|
|
imageView.layer.cornerRadius = 8
|
|
statusLabel.text = "已上传"
|
|
statusLabel.font = .systemFont(ofSize: 10)
|
|
statusLabel.textColor = .white
|
|
statusLabel.backgroundColor = UIColor(hex: 0x34C759)
|
|
statusLabel.layer.cornerRadius = 4
|
|
statusLabel.clipsToBounds = true
|
|
statusLabel.textAlignment = .center
|
|
checkImageView.tintColor = .white
|
|
checkImageView.backgroundColor = UIColor.black.withAlphaComponent(0.35)
|
|
checkImageView.layer.cornerRadius = 10
|
|
nameLabel.font = .systemFont(ofSize: 11)
|
|
nameLabel.textColor = AppColor.textPrimary
|
|
nameLabel.lineBreakMode = .byTruncatingMiddle
|
|
sizeLabel.font = .systemFont(ofSize: 10)
|
|
sizeLabel.textColor = AppColor.textTertiary
|
|
|
|
contentView.addSubview(imageView)
|
|
imageView.addSubview(statusLabel)
|
|
imageView.addSubview(checkImageView)
|
|
contentView.addSubview(nameLabel)
|
|
contentView.addSubview(sizeLabel)
|
|
imageView.snp.makeConstraints { make in
|
|
make.top.leading.trailing.equalToSuperview()
|
|
make.height.equalTo(imageView.snp.width)
|
|
}
|
|
statusLabel.snp.makeConstraints { make in
|
|
make.top.leading.equalToSuperview().offset(4)
|
|
make.height.equalTo(18)
|
|
make.width.equalTo(48)
|
|
}
|
|
checkImageView.snp.makeConstraints { make in
|
|
make.top.trailing.equalToSuperview().inset(4)
|
|
make.size.equalTo(20)
|
|
}
|
|
nameLabel.snp.makeConstraints { make in
|
|
make.top.equalTo(imageView.snp.bottom).offset(4)
|
|
make.leading.trailing.equalToSuperview()
|
|
}
|
|
sizeLabel.snp.makeConstraints { make in
|
|
make.top.equalTo(nameLabel.snp.bottom).offset(2)
|
|
make.leading.trailing.equalToSuperview()
|
|
}
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
func apply(material: TravelAlbumMaterial, selectionMode: Bool, selected: Bool) {
|
|
let urlString = material.coverUrl.isEmpty ? material.fileUrl : material.coverUrl
|
|
if let url = URL(string: urlString), !urlString.isEmpty {
|
|
imageView.kf.setImage(with: url, placeholder: UIImage(systemName: "photo"))
|
|
} else {
|
|
imageView.image = UIImage(systemName: "photo")
|
|
imageView.tintColor = AppColor.primary
|
|
imageView.backgroundColor = UIColor(hex: 0xEAF2FF)
|
|
}
|
|
checkImageView.isHidden = !selectionMode
|
|
checkImageView.image = UIImage(systemName: selected ? "checkmark.circle.fill" : "circle")
|
|
checkImageView.tintColor = selected ? AppColor.primary : .white
|
|
nameLabel.text = material.fileName
|
|
sizeLabel.text = TravelAlbumDisplayFormatter.fileSizeText(material.fileSize)
|
|
}
|
|
}
|