feat: make image attachments uploading in the queue

This commit is contained in:
CMK 2021-03-22 18:40:32 +08:00
parent d64a06aa9d
commit c35fcfb08f
5 changed files with 60 additions and 34 deletions

View File

@ -147,8 +147,9 @@ extension ComposeViewController {
])
collectionView.delegate = self
let longPressReorderGesture = UILongPressGestureRecognizer(target: self, action: #selector(ComposeViewController.longPressReorderGestureHandler(_:)))
collectionView.addGestureRecognizer(longPressReorderGesture)
// Note: do not allow reorder due to the images display order following the upload time
// let longPressReorderGesture = UILongPressGestureRecognizer(target: self, action: #selector(ComposeViewController.longPressReorderGestureHandler(_:)))
// collectionView.addGestureRecognizer(longPressReorderGesture)
viewModel.setupDiffableDataSource(
for: collectionView,
dependency: self,
@ -321,7 +322,7 @@ extension ComposeViewController {
dismiss(animated: true, completion: nil)
}
/* Do not allow reorder image due to image display order following the update time
@objc private func longPressReorderGestureHandler(_ sender: UILongPressGestureRecognizer) {
switch(sender.state) {
case .began:
@ -347,6 +348,7 @@ extension ComposeViewController {
collectionView.cancelInteractiveMovement()
}
}
*/
}

View File

@ -25,26 +25,28 @@ extension ComposeViewModel {
composeStatusAttachmentTableViewCellDelegate: composeStatusAttachmentTableViewCellDelegate
)
diffableDataSource.reorderingHandlers.canReorderItem = { item in
switch item {
case .attachment: return true
default: return false
}
// Note: do not allow reorder due to the images display order following the upload time
// diffableDataSource.reorderingHandlers.canReorderItem = { item in
// switch item {
// case .attachment: return true
// default: return false
// }
//
// }
// diffableDataSource.reorderingHandlers.didReorder = { [weak self] transaction in
// guard let self = self else { return }
//
// let items = transaction.finalSnapshot.itemIdentifiers
// var attachmentServices: [MastodonAttachmentService] = []
// for item in items {
// guard case let .attachment(attachmentService) = item else { continue }
// attachmentServices.append(attachmentService)
// }
// self.attachmentServices.value = attachmentServices
// }
//
}
diffableDataSource.reorderingHandlers.didReorder = { [weak self] transaction in
guard let self = self else { return }
let items = transaction.finalSnapshot.itemIdentifiers
var attachmentServices: [MastodonAttachmentService] = []
for item in items {
guard case let .attachment(attachmentService) = item else { continue }
attachmentServices.append(attachmentService)
}
self.attachmentServices.value = attachmentServices
}
self.diffableDataSource = diffableDataSource
var snapshot = NSDiffableDataSourceSnapshot<ComposeStatusSection, ComposeStatusItem>()
snapshot.appendSections([.repliedTo, .status, .attachment])
switch composeKind {

View File

@ -137,7 +137,7 @@ final class ComposeViewModel {
}
.store(in: &disposeBag)
// bind snapshot
// bind snapshot and drive service upload state
attachmentServices
.receive(on: DispatchQueue.main)
.sink { [weak self] attachmentServices in
@ -154,6 +154,26 @@ final class ComposeViewModel {
snapshot.appendItems(items, toSection: .attachment)
diffableDataSource.apply(snapshot)
// make image upload in the queue
for attachmentService in attachmentServices {
// skip when prefix N task when task finish OR fail OR uploading
guard let currentState = attachmentService.uploadStateMachine.currentState else { break }
if currentState is MastodonAttachmentService.UploadState.Fail {
continue
}
if currentState is MastodonAttachmentService.UploadState.Finish {
continue
}
if currentState is MastodonAttachmentService.UploadState.Uploading {
break
}
// trigger uploading one by one
if currentState is MastodonAttachmentService.UploadState.Initial {
attachmentService.uploadStateMachine.enter(MastodonAttachmentService.UploadState.Uploading.self)
break
}
}
}
.store(in: &disposeBag)
}

View File

@ -31,8 +31,15 @@ extension MastodonAttachmentService.UploadState {
class Initial: MastodonAttachmentService.UploadState {
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
guard service?.authenticationBox != nil else { return false }
guard service?.imageData.value != nil else { return false }
return stateClass == Uploading.self
if stateClass == Initial.self {
return true
}
if service?.imageData.value != nil {
return stateClass == Uploading.self
} else {
return stateClass == Fail.self
}
}
}

View File

@ -64,15 +64,14 @@ final class MastodonAttachmentService {
switch completion {
case .failure(let error):
self.error.value = error
self.uploadStateMachine.enter(UploadState.Fail.self)
case .finished:
break
}
} receiveValue: { [weak self] imageData in
guard let self = self else { return }
self.imageData.value = imageData
// Try pre-upload attachment for current active user
self.uploadStateMachine.enter(UploadState.Uploading.self)
self.uploadStateMachine.enter(UploadState.Initial.self)
}
.store(in: &disposeBag)
}
@ -89,9 +88,7 @@ final class MastodonAttachmentService {
setupServiceObserver()
imageData.value = image.jpegData(compressionQuality: 0.75)
// Try pre-upload attachment for current active user
uploadStateMachine.enter(UploadState.Uploading.self)
uploadStateMachine.enter(UploadState.Initial.self)
}
init(
@ -106,9 +103,7 @@ final class MastodonAttachmentService {
setupServiceObserver()
self.imageData.value = imageData
// Try pre-upload attachment for current active user
uploadStateMachine.enter(UploadState.Uploading.self)
uploadStateMachine.enter(UploadState.Initial.self)
}
private func setupServiceObserver() {