forked from zelo72/mastodon-ios
feat: add post publish validate state binding
This commit is contained in:
parent
b8e062c92e
commit
3eb2b916a7
|
@ -25,7 +25,7 @@ extension ComposeStatusItem: Hashable { }
|
||||||
extension ComposeStatusItem {
|
extension ComposeStatusItem {
|
||||||
final class ComposeStatusAttribute: Equatable, Hashable {
|
final class ComposeStatusAttribute: Equatable, Hashable {
|
||||||
private let id = UUID()
|
private let id = UUID()
|
||||||
|
|
||||||
let avatarURL = CurrentValueSubject<URL?, Never>(nil)
|
let avatarURL = CurrentValueSubject<URL?, Never>(nil)
|
||||||
let displayName = CurrentValueSubject<String?, Never>(nil)
|
let displayName = CurrentValueSubject<String?, Never>(nil)
|
||||||
let username = CurrentValueSubject<String?, Never>(nil)
|
let username = CurrentValueSubject<String?, Never>(nil)
|
||||||
|
@ -44,12 +44,32 @@ extension ComposeStatusItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protocol ComposeStatusItemDelegate: class {
|
||||||
|
func composePollAttribute(_ attribute: ComposeStatusItem.ComposePollAttribute, pollOptionDidChange: String?)
|
||||||
|
}
|
||||||
|
|
||||||
extension ComposeStatusItem {
|
extension ComposeStatusItem {
|
||||||
final class ComposePollAttribute: Equatable, Hashable {
|
final class ComposePollAttribute: Equatable, Hashable {
|
||||||
private let id = UUID()
|
private let id = UUID()
|
||||||
|
|
||||||
|
var disposeBag = Set<AnyCancellable>()
|
||||||
|
weak var delegate: ComposeStatusItemDelegate?
|
||||||
|
|
||||||
let option = CurrentValueSubject<String, Never>("")
|
let option = CurrentValueSubject<String, Never>("")
|
||||||
|
|
||||||
|
init() {
|
||||||
|
option
|
||||||
|
.sink { [weak self] option in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.delegate?.composePollAttribute(self, pollOptionDidChange: option)
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
disposeBag.removeAll()
|
||||||
|
}
|
||||||
|
|
||||||
static func == (lhs: ComposePollAttribute, rhs: ComposePollAttribute) -> Bool {
|
static func == (lhs: ComposePollAttribute, rhs: ComposePollAttribute) -> Bool {
|
||||||
return lhs.id == rhs.id &&
|
return lhs.id == rhs.id &&
|
||||||
lhs.option.value == rhs.option.value
|
lhs.option.value == rhs.option.value
|
||||||
|
|
|
@ -629,7 +629,6 @@ extension ComposeViewController: PHPickerViewControllerDelegate {
|
||||||
pickerResult: result,
|
pickerResult: result,
|
||||||
initalAuthenticationBox: viewModel.activeAuthenticationBox.value
|
initalAuthenticationBox: viewModel.activeAuthenticationBox.value
|
||||||
)
|
)
|
||||||
service.delegate = viewModel
|
|
||||||
return service
|
return service
|
||||||
}
|
}
|
||||||
viewModel.attachmentServices.value = viewModel.attachmentServices.value + attachmentServices
|
viewModel.attachmentServices.value = viewModel.attachmentServices.value + attachmentServices
|
||||||
|
@ -649,7 +648,6 @@ extension ComposeViewController: UIImagePickerControllerDelegate & UINavigationC
|
||||||
image: image,
|
image: image,
|
||||||
initalAuthenticationBox: viewModel.activeAuthenticationBox.value
|
initalAuthenticationBox: viewModel.activeAuthenticationBox.value
|
||||||
)
|
)
|
||||||
attachmentService.delegate = viewModel
|
|
||||||
viewModel.attachmentServices.value = viewModel.attachmentServices.value + [attachmentService]
|
viewModel.attachmentServices.value = viewModel.attachmentServices.value + [attachmentService]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,7 +671,6 @@ extension ComposeViewController: UIDocumentPickerDelegate {
|
||||||
imageData: imageData,
|
imageData: imageData,
|
||||||
initalAuthenticationBox: viewModel.activeAuthenticationBox.value
|
initalAuthenticationBox: viewModel.activeAuthenticationBox.value
|
||||||
)
|
)
|
||||||
attachmentService.delegate = viewModel
|
|
||||||
viewModel.attachmentServices.value = viewModel.attachmentServices.value + [attachmentService]
|
viewModel.attachmentServices.value = viewModel.attachmentServices.value + [attachmentService]
|
||||||
} catch {
|
} catch {
|
||||||
os_log("%{public}s[%{public}ld], %{public}s: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
|
os_log("%{public}s[%{public}ld], %{public}s: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
|
||||||
|
|
|
@ -104,19 +104,48 @@ final class ComposeViewModel {
|
||||||
.map { services in
|
.map { services in
|
||||||
services.allSatisfy { $0.uploadStateMachineSubject.value is MastodonAttachmentService.UploadState.Finish }
|
services.allSatisfy { $0.uploadStateMachineSubject.value is MastodonAttachmentService.UploadState.Finish }
|
||||||
}
|
}
|
||||||
Publishers.CombineLatest4(
|
let isPollAttributeAllValid = pollAttributes
|
||||||
|
.map { pollAttributes in
|
||||||
|
pollAttributes.allSatisfy { attribute -> Bool in
|
||||||
|
!attribute.option.value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let isPublishBarButtonItemEnabledPrecondition1 = Publishers.CombineLatest4(
|
||||||
isComposeContentEmpty.eraseToAnyPublisher(),
|
isComposeContentEmpty.eraseToAnyPublisher(),
|
||||||
isComposeContentValid.eraseToAnyPublisher(),
|
isComposeContentValid.eraseToAnyPublisher(),
|
||||||
isMediaEmpty.eraseToAnyPublisher(),
|
isMediaEmpty.eraseToAnyPublisher(),
|
||||||
isMediaUploadAllSuccess.eraseToAnyPublisher()
|
isMediaUploadAllSuccess.eraseToAnyPublisher()
|
||||||
)
|
)
|
||||||
.map { isComposeContentEmpty, isComposeContentValid, isMediaEmpty, isMediaUploadAllSuccess in
|
.map { isComposeContentEmpty, isComposeContentValid, isMediaEmpty, isMediaUploadAllSuccess -> Bool in
|
||||||
if isMediaEmpty {
|
if isMediaEmpty {
|
||||||
return isComposeContentValid && !isComposeContentEmpty
|
return isComposeContentValid && !isComposeContentEmpty
|
||||||
} else {
|
} else {
|
||||||
return isComposeContentValid && isMediaUploadAllSuccess
|
return isComposeContentValid && isMediaUploadAllSuccess
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
|
||||||
|
let isPublishBarButtonItemEnabledPrecondition2 = Publishers.CombineLatest4(
|
||||||
|
isComposeContentEmpty.eraseToAnyPublisher(),
|
||||||
|
isComposeContentValid.eraseToAnyPublisher(),
|
||||||
|
isPollComposing.eraseToAnyPublisher(),
|
||||||
|
isPollAttributeAllValid.eraseToAnyPublisher()
|
||||||
|
)
|
||||||
|
.map { isComposeContentEmpty, isComposeContentValid, isPollComposing, isPollAttributeAllValid -> Bool in
|
||||||
|
if isPollComposing {
|
||||||
|
return isComposeContentValid && !isComposeContentEmpty && isPollAttributeAllValid
|
||||||
|
} else {
|
||||||
|
return isComposeContentValid && !isComposeContentEmpty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
|
||||||
|
Publishers.CombineLatest(
|
||||||
|
isPublishBarButtonItemEnabledPrecondition1,
|
||||||
|
isPublishBarButtonItemEnabledPrecondition2
|
||||||
|
)
|
||||||
|
.map { $0 && $1 }
|
||||||
.assign(to: \.value, on: isPublishBarButtonItemEnabled)
|
.assign(to: \.value, on: isPublishBarButtonItemEnabled)
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
@ -201,6 +230,22 @@ final class ComposeViewModel {
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
// bind delegate
|
||||||
|
attachmentServices
|
||||||
|
.sink { [weak self] attachmentServices in
|
||||||
|
guard let self = self else { return }
|
||||||
|
attachmentServices.forEach { $0.delegate = self }
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
pollAttributes
|
||||||
|
.sink { [weak self] pollAttributes in
|
||||||
|
guard let self = self else { return }
|
||||||
|
pollAttributes.forEach { $0.delegate = self }
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
// bind compose toolbar UI state
|
||||||
Publishers.CombineLatest(
|
Publishers.CombineLatest(
|
||||||
isPollComposing.eraseToAnyPublisher(),
|
isPollComposing.eraseToAnyPublisher(),
|
||||||
attachmentServices.eraseToAnyPublisher()
|
attachmentServices.eraseToAnyPublisher()
|
||||||
|
@ -235,3 +280,11 @@ extension ComposeViewModel: MastodonAttachmentServiceDelegate {
|
||||||
attachmentServices.value = attachmentServices.value
|
attachmentServices.value = attachmentServices.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - ComposeStatusAttributeDelegate
|
||||||
|
extension ComposeViewModel: ComposeStatusItemDelegate {
|
||||||
|
func composePollAttribute(_ attribute: ComposeStatusItem.ComposePollAttribute, pollOptionDidChange: String?) {
|
||||||
|
// trigger update
|
||||||
|
pollAttributes.value = pollAttributes.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue