mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-25 17:50:59 +00:00
Browse files for attachments
This commit is contained in:
parent
487e8a766c
commit
377bf6aecc
4 changed files with 80 additions and 35 deletions
|
@ -46,6 +46,9 @@
|
||||||
"compose.attachment.uploading" = "Uploading";
|
"compose.attachment.uploading" = "Uploading";
|
||||||
"compose.prompt" = "What's on your mind?";
|
"compose.prompt" = "What's on your mind?";
|
||||||
"compose.mark-media-sensitive" = "Mark media as sensitive";
|
"compose.mark-media-sensitive" = "Mark media as sensitive";
|
||||||
|
"compose.photo-library" = "Photo Library";
|
||||||
|
"compose.take-photo-or-video" = "Take Photo or Video";
|
||||||
|
"compose.browse" = "Browse";
|
||||||
"error" = "Error";
|
"error" = "Error";
|
||||||
"favorites" = "Favorites";
|
"favorites" = "Favorites";
|
||||||
"registration.review-terms-of-use-and-privacy-policy-%@" = "Please review %@'s Terms of Use and Privacy Policy to continue";
|
"registration.review-terms-of-use-and-privacy-policy-%@" = "Please review %@'s Terms of Use and Privacy Policy to continue";
|
||||||
|
|
|
@ -20,6 +20,7 @@ final class NewStatusViewController: UIViewController {
|
||||||
action: nil)
|
action: nil)
|
||||||
private let mediaSelections = PassthroughSubject<[PHPickerResult], Never>()
|
private let mediaSelections = PassthroughSubject<[PHPickerResult], Never>()
|
||||||
private let imagePickerResults = PassthroughSubject<[UIImagePickerController.InfoKey: Any]?, Never>()
|
private let imagePickerResults = PassthroughSubject<[UIImagePickerController.InfoKey: Any]?, Never>()
|
||||||
|
private let documentPickerResuls = PassthroughSubject<[URL]?, Never>()
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
init(viewModel: NewStatusViewModel) {
|
init(viewModel: NewStatusViewModel) {
|
||||||
|
@ -110,6 +111,16 @@ extension NewStatusViewController: UIImagePickerControllerDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension NewStatusViewController: UIDocumentPickerDelegate {
|
||||||
|
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
||||||
|
documentPickerResuls.send(urls)
|
||||||
|
}
|
||||||
|
|
||||||
|
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
|
||||||
|
documentPickerResuls.send(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Required by UIImagePickerController
|
// Required by UIImagePickerController
|
||||||
extension NewStatusViewController: UINavigationControllerDelegate {}
|
extension NewStatusViewController: UINavigationControllerDelegate {}
|
||||||
|
|
||||||
|
@ -122,6 +133,8 @@ private extension NewStatusViewController {
|
||||||
#if !IS_SHARE_EXTENSION
|
#if !IS_SHARE_EXTENSION
|
||||||
presentCamera(compositionViewModel: compositionViewModel)
|
presentCamera(compositionViewModel: compositionViewModel)
|
||||||
#endif
|
#endif
|
||||||
|
case let .presentDocumentPicker(compositionViewModel):
|
||||||
|
presentDocumentPicker(compositionViewModel: compositionViewModel)
|
||||||
case let .editAttachment(attachmentViewModel, compositionViewModel):
|
case let .editAttachment(attachmentViewModel, compositionViewModel):
|
||||||
presentAttachmentEditor(
|
presentAttachmentEditor(
|
||||||
attachmentViewModel: attachmentViewModel,
|
attachmentViewModel: attachmentViewModel,
|
||||||
|
@ -301,6 +314,28 @@ private extension NewStatusViewController {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
func presentDocumentPicker(compositionViewModel: CompositionViewModel) {
|
||||||
|
documentPickerResuls.first().sink { [weak self] in
|
||||||
|
guard let self = self,
|
||||||
|
let result = $0?.first,
|
||||||
|
result.startAccessingSecurityScopedResource(),
|
||||||
|
let itemProvider = NSItemProvider(contentsOf: result)
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
self.viewModel.attach(itemProvider: itemProvider, to: compositionViewModel)
|
||||||
|
result.stopAccessingSecurityScopedResource()
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: [.image, .movie, .audio])
|
||||||
|
|
||||||
|
documentPickerController.delegate = self
|
||||||
|
documentPickerController.allowsMultipleSelection = false
|
||||||
|
documentPickerController.modalPresentationStyle = .overFullScreen
|
||||||
|
|
||||||
|
present(documentPickerController, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
func presentAttachmentEditor(attachmentViewModel: AttachmentViewModel, compositionViewModel: CompositionViewModel) {
|
func presentAttachmentEditor(attachmentViewModel: AttachmentViewModel, compositionViewModel: CompositionViewModel) {
|
||||||
let editAttachmentsView = EditAttachmentView { (attachmentViewModel, compositionViewModel) }
|
let editAttachmentsView = EditAttachmentView { (attachmentViewModel, compositionViewModel) }
|
||||||
let editAttachmentViewController = UIHostingController(rootView: editAttachmentsView)
|
let editAttachmentViewController = UIHostingController(rootView: editAttachmentsView)
|
||||||
|
|
|
@ -53,6 +53,7 @@ public extension NewStatusViewModel {
|
||||||
enum Event {
|
enum Event {
|
||||||
case presentMediaPicker(CompositionViewModel)
|
case presentMediaPicker(CompositionViewModel)
|
||||||
case presentCamera(CompositionViewModel)
|
case presentCamera(CompositionViewModel)
|
||||||
|
case presentDocumentPicker(CompositionViewModel)
|
||||||
case editAttachment(AttachmentViewModel, CompositionViewModel)
|
case editAttachment(AttachmentViewModel, CompositionViewModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +90,10 @@ public extension NewStatusViewModel {
|
||||||
eventsSubject.send(.presentCamera(viewModel))
|
eventsSubject.send(.presentCamera(viewModel))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func presentDocumentPicker(viewModel: CompositionViewModel) {
|
||||||
|
eventsSubject.send(.presentDocumentPicker(viewModel))
|
||||||
|
}
|
||||||
|
|
||||||
func remove(viewModel: CompositionViewModel) {
|
func remove(viewModel: CompositionViewModel) {
|
||||||
compositionViewModels.removeAll { $0 === viewModel }
|
compositionViewModels.removeAll { $0 === viewModel }
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,40 +45,44 @@ private extension CompositionInputAccessoryView {
|
||||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
stackView.spacing = .defaultSpacing
|
stackView.spacing = .defaultSpacing
|
||||||
|
|
||||||
let mediaButton = UIButton()
|
var attachmentActions = [
|
||||||
|
UIAction(
|
||||||
|
title: NSLocalizedString("compose.browse", comment: ""),
|
||||||
|
image: UIImage(systemName: "ellipsis")) { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
stackView.addArrangedSubview(mediaButton)
|
self.parentViewModel.presentDocumentPicker(viewModel: self.viewModel)
|
||||||
mediaButton.setImage(
|
},
|
||||||
UIImage(
|
UIAction(
|
||||||
systemName: "photo",
|
title: NSLocalizedString("compose.photo-library", comment: ""),
|
||||||
withConfiguration: UIImage.SymbolConfiguration(scale: .medium)),
|
image: UIImage(systemName: "rectangle.on.rectangle")) { [weak self] _ in
|
||||||
for: .normal)
|
|
||||||
mediaButton.addAction(UIAction { [weak self] _ in
|
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
self.parentViewModel.presentMediaPicker(viewModel: self.viewModel)
|
self.parentViewModel.presentMediaPicker(viewModel: self.viewModel)
|
||||||
},
|
}
|
||||||
for: .touchUpInside)
|
]
|
||||||
|
|
||||||
let cameraButton = UIButton()
|
|
||||||
|
|
||||||
#if !IS_SHARE_EXTENSION
|
#if !IS_SHARE_EXTENSION
|
||||||
if AVCaptureDevice.authorizationStatus(for: .video) != .restricted {
|
attachmentActions.insert(UIAction(
|
||||||
stackView.addArrangedSubview(cameraButton)
|
title: NSLocalizedString("compose.take-photo-or-video", comment: ""),
|
||||||
cameraButton.setImage(
|
image: UIImage(systemName: "camera.fill")) { [weak self] _ in
|
||||||
UIImage(
|
|
||||||
systemName: "camera",
|
|
||||||
withConfiguration: UIImage.SymbolConfiguration(scale: .medium)),
|
|
||||||
for: .normal)
|
|
||||||
cameraButton.addAction(UIAction { [weak self] _ in
|
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
self.parentViewModel.presentCamera(viewModel: self.viewModel)
|
self.parentViewModel.presentCamera(viewModel: self.viewModel)
|
||||||
},
|
},
|
||||||
for: .touchUpInside)
|
at: 1)
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
let attachmentButton = UIButton()
|
||||||
|
stackView.addArrangedSubview(attachmentButton)
|
||||||
|
attachmentButton.setImage(
|
||||||
|
UIImage(
|
||||||
|
systemName: "paperclip",
|
||||||
|
withConfiguration: UIImage.SymbolConfiguration(scale: .medium)),
|
||||||
|
for: .normal)
|
||||||
|
attachmentButton.showsMenuAsPrimaryAction = true
|
||||||
|
attachmentButton.menu = UIMenu(children: attachmentActions)
|
||||||
|
|
||||||
let pollButton = UIButton()
|
let pollButton = UIButton()
|
||||||
|
|
||||||
stackView.addArrangedSubview(pollButton)
|
stackView.addArrangedSubview(pollButton)
|
||||||
|
@ -126,10 +130,8 @@ private extension CompositionInputAccessoryView {
|
||||||
self.parentViewModel.insert(after: self.viewModel)
|
self.parentViewModel.insert(after: self.viewModel)
|
||||||
}, for: .touchUpInside)
|
}, for: .touchUpInside)
|
||||||
|
|
||||||
viewModel.$canAddAttachment.sink {
|
viewModel.$canAddAttachment
|
||||||
mediaButton.isEnabled = $0
|
.sink { attachmentButton.isEnabled = $0 }
|
||||||
cameraButton.isEnabled = $0
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
viewModel.$remainingCharacters.sink {
|
viewModel.$remainingCharacters.sink {
|
||||||
|
@ -148,7 +150,7 @@ private extension CompositionInputAccessoryView {
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
for button in [mediaButton, pollButton, visibilityButton, contentWarningButton, addButton] {
|
for button in [attachmentButton, pollButton, visibilityButton, contentWarningButton, addButton] {
|
||||||
button.heightAnchor.constraint(greaterThanOrEqualToConstant: .minimumButtonDimension).isActive = true
|
button.heightAnchor.constraint(greaterThanOrEqualToConstant: .minimumButtonDimension).isActive = true
|
||||||
button.widthAnchor.constraint(greaterThanOrEqualToConstant: .minimumButtonDimension).isActive = true
|
button.widthAnchor.constraint(greaterThanOrEqualToConstant: .minimumButtonDimension).isActive = true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue