Fix OTG album local path storage

This commit is contained in:
2026-07-08 10:25:35 +08:00
parent e9f593643f
commit 773fbd1180
8 changed files with 206 additions and 76 deletions

View File

@ -16,7 +16,8 @@ final class TravelAlbumCameraImportViewController: UIViewController {
}
private let viewModel: TravelAlbumCameraImportViewModel
var onImportFinished: ((Int) -> Void)?
var onImportFinished: ((Int, Int) -> Void)?
var onImportCancelled: (() -> Void)?
private var collectionView: UICollectionView!
private var sections: [TravelAlbumCameraImportSection] = []
@ -75,6 +76,11 @@ final class TravelAlbumCameraImportViewController: UIViewController {
collectionView.collectionViewLayout.invalidateLayout()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationController?.presentationController?.delegate = self
}
private func setupUI() {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = Layout.spacing
@ -150,7 +156,6 @@ final class TravelAlbumCameraImportViewController: UIViewController {
}
viewModel.onSelectionUpdated = { [weak self] count in
self?.updateImportButton(count: count)
self?.collectionView.reloadData()
}
viewModel.onSonyMTPHelpVisibilityChanged = { [weak self] show in
self?.updateHelpVisibility(show)
@ -160,6 +165,7 @@ final class TravelAlbumCameraImportViewController: UIViewController {
private func render(_ state: TravelAlbumCameraImportState) {
switch state {
case .idle, .loading:
isModalInPresentation = false
collectionView.isHidden = true
messageLabel.isHidden = true
helpButton.isHidden = true
@ -168,6 +174,7 @@ final class TravelAlbumCameraImportViewController: UIViewController {
activityIndicator.startAnimating()
case .loaded(let loadedSections):
isModalInPresentation = false
activityIndicator.stopAnimating()
collectionView.isHidden = false
messageLabel.isHidden = true
@ -177,6 +184,7 @@ final class TravelAlbumCameraImportViewController: UIViewController {
collectionView.reloadData()
case .importing(let current, let total):
isModalInPresentation = true
collectionView.isHidden = true
messageLabel.isHidden = false
messageLabel.text = "正在导入 \(current)/\(total)..."
@ -185,13 +193,15 @@ final class TravelAlbumCameraImportViewController: UIViewController {
navigationItem.leftBarButtonItem?.isEnabled = false
activityIndicator.startAnimating()
case .finished(let count):
case .finished(let importedCount, let failedCount):
isModalInPresentation = false
activityIndicator.stopAnimating()
dismiss(animated: true) { [weak self] in
self?.onImportFinished?(count)
self?.onImportFinished?(importedCount, failedCount)
}
case .failed(let message):
isModalInPresentation = false
activityIndicator.stopAnimating()
collectionView.isHidden = true
messageLabel.isHidden = false
@ -229,7 +239,52 @@ final class TravelAlbumCameraImportViewController: UIViewController {
return CGSize(width: width, height: width + 28)
}
private func applyHeader(_ header: TravelAlbumCameraImportSectionHeaderView, at sectionIndex: Int) {
let section = sections[sectionIndex]
header.apply(
title: section.title,
count: section.photos.count,
importableCount: viewModel.importablePhotoCount(in: section),
importedCount: viewModel.importedPhotoCount(in: section),
hasImportablePhotos: viewModel.hasImportablePhotos(in: section),
fullySelected: viewModel.isSectionFullySelected(section),
partiallySelected: viewModel.isSectionPartiallySelected(section)
)
header.onToggle = { [weak self] in
self?.toggleSection(at: sectionIndex)
}
}
private func refreshVisibleHeader(at sectionIndex: Int) {
let indexPath = IndexPath(item: 0, section: sectionIndex)
guard let header = collectionView.supplementaryView(
forElementKind: UICollectionView.elementKindSectionHeader,
at: indexPath
) as? TravelAlbumCameraImportSectionHeaderView else {
return
}
applyHeader(header, at: sectionIndex)
}
private func reloadItemsWithoutAnimation(_ indexPaths: [IndexPath]) {
UIView.performWithoutAnimation {
collectionView.reloadItems(at: indexPaths)
collectionView.layoutIfNeeded()
}
}
private func toggleSection(at sectionIndex: Int) {
guard sections.indices.contains(sectionIndex) else { return }
viewModel.toggleSection(sections[sectionIndex])
let indexPaths = sections[sectionIndex].photos.indices.map {
IndexPath(item: $0, section: sectionIndex)
}
reloadItemsWithoutAnimation(indexPaths)
refreshVisibleHeader(at: sectionIndex)
}
@objc private func cancelTapped() {
onImportCancelled?()
dismiss(animated: true)
}
@ -282,21 +337,7 @@ extension TravelAlbumCameraImportViewController: UICollectionViewDataSource {
withReuseIdentifier: TravelAlbumCameraImportSectionHeaderView.reuseIdentifier,
for: indexPath
) as! TravelAlbumCameraImportSectionHeaderView
let section = sections[indexPath.section]
header.apply(
title: section.title,
count: section.photos.count,
importableCount: viewModel.importablePhotoCount(in: section),
importedCount: viewModel.importedPhotoCount(in: section),
hasImportablePhotos: viewModel.hasImportablePhotos(in: section),
fullySelected: viewModel.isSectionFullySelected(section),
partiallySelected: viewModel.isSectionPartiallySelected(section)
)
header.onToggle = { [weak self] in
guard let self else { return }
self.viewModel.toggleSection(section)
self.collectionView.reloadSections(IndexSet(integer: indexPath.section))
}
applyHeader(header, at: indexPath.section)
return header
}
}
@ -306,8 +347,8 @@ extension TravelAlbumCameraImportViewController: UICollectionViewDelegateFlowLay
let photo = sections[indexPath.section].photos[indexPath.item]
guard !viewModel.isPhotoAlreadyInAlbum(id: photo.id) else { return }
viewModel.togglePhoto(id: photo.id)
collectionView.reloadItems(at: [indexPath])
collectionView.reloadSections(IndexSet(integer: indexPath.section))
reloadItemsWithoutAnimation([indexPath])
refreshVisibleHeader(at: indexPath.section)
}
func collectionView(
@ -322,6 +363,12 @@ extension TravelAlbumCameraImportViewController: UICollectionViewDelegateFlowLay
}
}
extension TravelAlbumCameraImportViewController: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
onImportCancelled?()
}
}
/// Cell
private final class TravelAlbumCameraImportPhotoCell: UICollectionViewCell {
static let reuseIdentifier = "TravelAlbumCameraImportPhotoCell"