Composition niceties

This commit is contained in:
Justin Mazzocchi 2021-01-19 11:59:20 -08:00
parent c104f47ea9
commit 5c179457e5
No known key found for this signature in database
GPG Key ID: E223E6937AAFB01C
8 changed files with 60 additions and 25 deletions

View File

@ -51,6 +51,7 @@
"compose.photo-library" = "Photo Library";
"compose.poll.add-choice" = "Add a choice";
"compose.poll.allow-multiple-choices" = "Allow multiple choices";
"compose.poll.option-%ld" = "Option %ld";
"compose.prompt" = "What's on your mind?";
"compose.take-photo-or-video" = "Take Photo or Video";
"emoji.custom" = "Custom";

View File

@ -193,9 +193,19 @@ private extension NewStatusViewController {
}
for removal in diff.removals {
guard case let .remove(_, id, _) = removal else { continue }
guard case let .remove(_, id, _) = removal,
let index = stackView.arrangedSubviews.firstIndex(where: { ($0 as? CompositionView)?.id == id })
else { continue }
stackView.arrangedSubviews.first { ($0 as? CompositionView)?.id == id }?.removeFromSuperview()
if (stackView.arrangedSubviews[index] as? CompositionView)?.textView.isFirstResponder ?? false {
if index > 0 {
(stackView.arrangedSubviews[index - 1] as? CompositionView)?.textView.becomeFirstResponder()
} else if stackView.arrangedSubviews.count > index {
(stackView.arrangedSubviews[index + 1] as? CompositionView)?.textView.becomeFirstResponder()
}
}
stackView.arrangedSubviews[index].removeFromSuperview()
}
for compositionView in stackView.arrangedSubviews.compactMap({ $0 as? CompositionView }) {

View File

@ -50,16 +50,18 @@ final class AttachmentUploadView: UIView {
progressView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)
])
viewModel.$attachmentUpload.sink { [weak self] in
viewModel.$attachmentUpload.sink { [weak self] attachmentUpload in
guard let self = self else { return }
if let attachmentUpload = $0 {
self.progressCancellable = attachmentUpload.progress.publisher(for: \.fractionCompleted)
.receive(on: DispatchQueue.main)
.sink { self.progressView.progress = Float($0) }
self.isHidden = false
} else {
self.isHidden = true
UIView.animate(withDuration: .zeroIfReduceMotion(.shortAnimationDuration)) {
if let attachmentUpload = attachmentUpload {
self.progressCancellable = attachmentUpload.progress.publisher(for: \.fractionCompleted)
.receive(on: DispatchQueue.main)
.sink { self.progressView.progress = Float($0) }
self.isHidden = false
} else {
self.isHidden = true
}
}
}
.store(in: &cancellables)

View File

@ -65,7 +65,6 @@ private extension CompositionInputAccessoryView {
#endif
let attachmentButton = UIBarButtonItem(
title: "hm",
image: UIImage(systemName: "paperclip"),
menu: UIMenu(children: attachmentActions))
let pollButton = UIBarButtonItem(

View File

@ -5,6 +5,7 @@ import UIKit
import ViewModels
final class CompositionPollOptionView: UIView {
let textField = UITextField()
let option: CompositionViewModel.PollOption
let removeButton = UIButton(type: .close)
private let viewModel: CompositionViewModel
@ -33,7 +34,6 @@ private extension CompositionPollOptionView {
// swiftlint:disable:next function_body_length
func initialSetup() {
let stackView = UIStackView()
let textField = UITextField()
let remainingCharactersLabel = UILabel()
addSubview(stackView)
@ -51,7 +51,7 @@ private extension CompositionPollOptionView {
textField.tag = textInputAccessoryView.tagForInputView
textField.addAction(
UIAction { [weak self] _ in
self?.option.text = textField.text ?? "" },
self?.option.text = self?.textField.text ?? "" },
for: .editingChanged)
textField.text = option.text

View File

@ -62,6 +62,7 @@ private extension CompositionPollView {
withConfiguration: UIImage.SymbolConfiguration(scale: .medium)),
for: .normal)
addChoiceButton.setTitle(NSLocalizedString("compose.poll.add-choice", comment: ""), for: .normal)
addChoiceButton.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: .defaultSpacing)
let expiresInButton = UIButton(type: .system)
@ -76,6 +77,7 @@ private extension CompositionPollView {
self?.viewModel.pollExpiresIn = expiry
}
})
expiresInButton.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: .defaultSpacing)
let switchStackView = UIStackView()
@ -121,6 +123,9 @@ private extension CompositionPollView {
parentViewModel: self.parentViewModel,
option: option)
optionView.textField.placeholder = String.localizedStringWithFormat(
NSLocalizedString("compose.poll.option-%ld", comment: ""),
index + 1)
self.stackView.insertArrangedSubview(optionView, at: index)
}
}
@ -129,6 +134,14 @@ private extension CompositionPollView {
optionView.removeButton.isHidden = index < CompositionViewModel.minPollOptionCount
if !$0.contains(where: { $0 === optionView.option }) {
if optionView.textField.isFirstResponder {
if index > 0 {
self.pollOptionViews[index - 1].textField.becomeFirstResponder()
} else if self.pollOptionViews.count > index {
self.pollOptionViews[index + 1].textField.becomeFirstResponder()
}
}
optionView.removeFromSuperview()
}
}

View File

@ -157,17 +157,21 @@ private extension CompositionView {
.store(in: &cancellables)
viewModel.$displayContentWarning
.sink { [weak self] in
.sink { [weak self] displayContentWarning in
guard let self = self else { return }
if self.spoilerTextField.isHidden && self.textView.isFirstResponder && $0 {
if self.spoilerTextField.isHidden && self.textView.isFirstResponder && displayContentWarning {
self.spoilerTextField.becomeFirstResponder()
} else if !self.spoilerTextField.isHidden && self.spoilerTextField.isFirstResponder && !$0 {
} else if !self.spoilerTextField.isHidden
&& self.spoilerTextField.isFirstResponder
&& !displayContentWarning {
self.textView.becomeFirstResponder()
}
self.spoilerTextField.isHidden = !$0
textViewBaselineConstraint.isActive = !$0
UIView.animate(withDuration: .zeroIfReduceMotion(.shortAnimationDuration)) {
self.spoilerTextField.isHidden = !displayContentWarning
textViewBaselineConstraint.isActive = !displayContentWarning
}
}
.store(in: &cancellables)
@ -177,20 +181,24 @@ private extension CompositionView {
viewModel.$attachmentViewModels
.receive(on: RunLoop.main)
.sink { [weak self] in
self?.attachmentsView.viewModel = self?.viewModel
self?.attachmentsView.isHidden = $0.isEmpty
self?.markAttachmentsSensitiveView.isHidden = $0.isEmpty
.sink { [weak self] attachmentViewModels in
UIView.animate(withDuration: .zeroIfReduceMotion(.shortAnimationDuration)) {
self?.attachmentsView.viewModel = self?.viewModel
self?.attachmentsView.isHidden = attachmentViewModels.isEmpty
self?.markAttachmentsSensitiveView.isHidden = attachmentViewModels.isEmpty
}
}
.store(in: &cancellables)
viewModel.$displayPoll
.sink { [weak self] in
if !$0 {
.sink { [weak self] displayPoll in
if !displayPoll {
self?.textView.becomeFirstResponder()
}
self?.pollView.isHidden = !$0
UIView.animate(withDuration: .zeroIfReduceMotion(.shortAnimationDuration)) {
self?.pollView.isHidden = !displayPoll
}
}
.store(in: &cancellables)

View File

@ -22,6 +22,8 @@ extension CGRect {
extension TimeInterval {
static let defaultAnimationDuration: Self = 0.5
static let shortAnimationDuration = defaultAnimationDuration / 2
static func zeroIfReduceMotion(_ duration: Self) -> Self { UIAccessibility.isReduceMotionEnabled ? 0 : duration }
}
extension UIImage {