forked from zelo72/mastodon-ios
feat: make image attachments uploading in the queue
This commit is contained in:
parent
d64a06aa9d
commit
c35fcfb08f
|
@ -147,8 +147,9 @@ extension ComposeViewController {
|
||||||
])
|
])
|
||||||
|
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
let longPressReorderGesture = UILongPressGestureRecognizer(target: self, action: #selector(ComposeViewController.longPressReorderGestureHandler(_:)))
|
// Note: do not allow reorder due to the images display order following the upload time
|
||||||
collectionView.addGestureRecognizer(longPressReorderGesture)
|
// let longPressReorderGesture = UILongPressGestureRecognizer(target: self, action: #selector(ComposeViewController.longPressReorderGestureHandler(_:)))
|
||||||
|
// collectionView.addGestureRecognizer(longPressReorderGesture)
|
||||||
viewModel.setupDiffableDataSource(
|
viewModel.setupDiffableDataSource(
|
||||||
for: collectionView,
|
for: collectionView,
|
||||||
dependency: self,
|
dependency: self,
|
||||||
|
@ -321,7 +322,7 @@ extension ComposeViewController {
|
||||||
dismiss(animated: true, completion: nil)
|
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) {
|
@objc private func longPressReorderGestureHandler(_ sender: UILongPressGestureRecognizer) {
|
||||||
switch(sender.state) {
|
switch(sender.state) {
|
||||||
case .began:
|
case .began:
|
||||||
|
@ -347,6 +348,7 @@ extension ComposeViewController {
|
||||||
collectionView.cancelInteractiveMovement()
|
collectionView.cancelInteractiveMovement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,27 +24,29 @@ extension ComposeViewModel {
|
||||||
textEditorViewTextAttributesDelegate: textEditorViewTextAttributesDelegate,
|
textEditorViewTextAttributesDelegate: textEditorViewTextAttributesDelegate,
|
||||||
composeStatusAttachmentTableViewCellDelegate: composeStatusAttachmentTableViewCellDelegate
|
composeStatusAttachmentTableViewCellDelegate: composeStatusAttachmentTableViewCellDelegate
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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.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
|
|
||||||
}
|
|
||||||
self.diffableDataSource = diffableDataSource
|
self.diffableDataSource = diffableDataSource
|
||||||
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<ComposeStatusSection, ComposeStatusItem>()
|
var snapshot = NSDiffableDataSourceSnapshot<ComposeStatusSection, ComposeStatusItem>()
|
||||||
snapshot.appendSections([.repliedTo, .status, .attachment])
|
snapshot.appendSections([.repliedTo, .status, .attachment])
|
||||||
switch composeKind {
|
switch composeKind {
|
||||||
|
|
|
@ -137,7 +137,7 @@ final class ComposeViewModel {
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
// bind snapshot
|
// bind snapshot and drive service upload state
|
||||||
attachmentServices
|
attachmentServices
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] attachmentServices in
|
.sink { [weak self] attachmentServices in
|
||||||
|
@ -154,6 +154,26 @@ final class ComposeViewModel {
|
||||||
snapshot.appendItems(items, toSection: .attachment)
|
snapshot.appendItems(items, toSection: .attachment)
|
||||||
|
|
||||||
diffableDataSource.apply(snapshot)
|
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)
|
.store(in: &disposeBag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,15 @@ extension MastodonAttachmentService.UploadState {
|
||||||
class Initial: MastodonAttachmentService.UploadState {
|
class Initial: MastodonAttachmentService.UploadState {
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
guard service?.authenticationBox != nil else { return false }
|
guard service?.authenticationBox != nil else { return false }
|
||||||
guard service?.imageData.value != nil else { return false }
|
if stateClass == Initial.self {
|
||||||
return stateClass == Uploading.self
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if service?.imageData.value != nil {
|
||||||
|
return stateClass == Uploading.self
|
||||||
|
} else {
|
||||||
|
return stateClass == Fail.self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,15 +64,14 @@ final class MastodonAttachmentService {
|
||||||
switch completion {
|
switch completion {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
self.error.value = error
|
self.error.value = error
|
||||||
|
self.uploadStateMachine.enter(UploadState.Fail.self)
|
||||||
case .finished:
|
case .finished:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} receiveValue: { [weak self] imageData in
|
} receiveValue: { [weak self] imageData in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.imageData.value = imageData
|
self.imageData.value = imageData
|
||||||
|
self.uploadStateMachine.enter(UploadState.Initial.self)
|
||||||
// Try pre-upload attachment for current active user
|
|
||||||
self.uploadStateMachine.enter(UploadState.Uploading.self)
|
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
}
|
}
|
||||||
|
@ -89,9 +88,7 @@ final class MastodonAttachmentService {
|
||||||
setupServiceObserver()
|
setupServiceObserver()
|
||||||
|
|
||||||
imageData.value = image.jpegData(compressionQuality: 0.75)
|
imageData.value = image.jpegData(compressionQuality: 0.75)
|
||||||
|
uploadStateMachine.enter(UploadState.Initial.self)
|
||||||
// Try pre-upload attachment for current active user
|
|
||||||
uploadStateMachine.enter(UploadState.Uploading.self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init(
|
init(
|
||||||
|
@ -106,9 +103,7 @@ final class MastodonAttachmentService {
|
||||||
setupServiceObserver()
|
setupServiceObserver()
|
||||||
|
|
||||||
self.imageData.value = imageData
|
self.imageData.value = imageData
|
||||||
|
uploadStateMachine.enter(UploadState.Initial.self)
|
||||||
// Try pre-upload attachment for current active user
|
|
||||||
uploadStateMachine.enter(UploadState.Uploading.self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupServiceObserver() {
|
private func setupServiceObserver() {
|
||||||
|
|
Loading…
Reference in New Issue