Browse files for attachments

This commit is contained in:
Justin Mazzocchi 2021-01-09 23:08:45 -08:00
parent 487e8a766c
commit 377bf6aecc
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
4 changed files with 80 additions and 35 deletions

View file

@ -46,6 +46,9 @@
"compose.attachment.uploading" = "Uploading";
"compose.prompt" = "What's on your mind?";
"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";
"favorites" = "Favorites";
"registration.review-terms-of-use-and-privacy-policy-%@" = "Please review %@'s Terms of Use and Privacy Policy to continue";

View file

@ -20,6 +20,7 @@ final class NewStatusViewController: UIViewController {
action: nil)
private let mediaSelections = PassthroughSubject<[PHPickerResult], Never>()
private let imagePickerResults = PassthroughSubject<[UIImagePickerController.InfoKey: Any]?, Never>()
private let documentPickerResuls = PassthroughSubject<[URL]?, Never>()
private var cancellables = Set<AnyCancellable>()
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
extension NewStatusViewController: UINavigationControllerDelegate {}
@ -122,6 +133,8 @@ private extension NewStatusViewController {
#if !IS_SHARE_EXTENSION
presentCamera(compositionViewModel: compositionViewModel)
#endif
case let .presentDocumentPicker(compositionViewModel):
presentDocumentPicker(compositionViewModel: compositionViewModel)
case let .editAttachment(attachmentViewModel, compositionViewModel):
presentAttachmentEditor(
attachmentViewModel: attachmentViewModel,
@ -301,6 +314,28 @@ private extension NewStatusViewController {
}
#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) {
let editAttachmentsView = EditAttachmentView { (attachmentViewModel, compositionViewModel) }
let editAttachmentViewController = UIHostingController(rootView: editAttachmentsView)

View file

@ -53,6 +53,7 @@ public extension NewStatusViewModel {
enum Event {
case presentMediaPicker(CompositionViewModel)
case presentCamera(CompositionViewModel)
case presentDocumentPicker(CompositionViewModel)
case editAttachment(AttachmentViewModel, CompositionViewModel)
}
@ -89,6 +90,10 @@ public extension NewStatusViewModel {
eventsSubject.send(.presentCamera(viewModel))
}
func presentDocumentPicker(viewModel: CompositionViewModel) {
eventsSubject.send(.presentDocumentPicker(viewModel))
}
func remove(viewModel: CompositionViewModel) {
compositionViewModels.removeAll { $0 === viewModel }
}

View file

@ -45,40 +45,44 @@ private extension CompositionInputAccessoryView {
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.spacing = .defaultSpacing
let mediaButton = UIButton()
stackView.addArrangedSubview(mediaButton)
mediaButton.setImage(
UIImage(
systemName: "photo",
withConfiguration: UIImage.SymbolConfiguration(scale: .medium)),
for: .normal)
mediaButton.addAction(UIAction { [weak self] _ in
guard let self = self else { return }
self.parentViewModel.presentMediaPicker(viewModel: self.viewModel)
},
for: .touchUpInside)
let cameraButton = UIButton()
#if !IS_SHARE_EXTENSION
if AVCaptureDevice.authorizationStatus(for: .video) != .restricted {
stackView.addArrangedSubview(cameraButton)
cameraButton.setImage(
UIImage(
systemName: "camera",
withConfiguration: UIImage.SymbolConfiguration(scale: .medium)),
for: .normal)
cameraButton.addAction(UIAction { [weak self] _ in
var attachmentActions = [
UIAction(
title: NSLocalizedString("compose.browse", comment: ""),
image: UIImage(systemName: "ellipsis")) { [weak self] _ in
guard let self = self else { return }
self.parentViewModel.presentCamera(viewModel: self.viewModel)
self.parentViewModel.presentDocumentPicker(viewModel: self.viewModel)
},
for: .touchUpInside)
}
UIAction(
title: NSLocalizedString("compose.photo-library", comment: ""),
image: UIImage(systemName: "rectangle.on.rectangle")) { [weak self] _ in
guard let self = self else { return }
self.parentViewModel.presentMediaPicker(viewModel: self.viewModel)
}
]
#if !IS_SHARE_EXTENSION
attachmentActions.insert(UIAction(
title: NSLocalizedString("compose.take-photo-or-video", comment: ""),
image: UIImage(systemName: "camera.fill")) { [weak self] _ in
guard let self = self else { return }
self.parentViewModel.presentCamera(viewModel: self.viewModel)
},
at: 1)
#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()
stackView.addArrangedSubview(pollButton)
@ -126,11 +130,9 @@ private extension CompositionInputAccessoryView {
self.parentViewModel.insert(after: self.viewModel)
}, for: .touchUpInside)
viewModel.$canAddAttachment.sink {
mediaButton.isEnabled = $0
cameraButton.isEnabled = $0
}
.store(in: &cancellables)
viewModel.$canAddAttachment
.sink { attachmentButton.isEnabled = $0 }
.store(in: &cancellables)
viewModel.$remainingCharacters.sink {
charactersLabel.text = String($0)
@ -148,7 +150,7 @@ private extension CompositionInputAccessoryView {
}
.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.widthAnchor.constraint(greaterThanOrEqualToConstant: .minimumButtonDimension).isActive = true
}