mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-22 00:01:00 +00:00
Composition niceties
This commit is contained in:
parent
c104f47ea9
commit
5c179457e5
8 changed files with 60 additions and 25 deletions
|
@ -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";
|
||||
|
|
|
@ -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 }) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -65,7 +65,6 @@ private extension CompositionInputAccessoryView {
|
|||
#endif
|
||||
|
||||
let attachmentButton = UIBarButtonItem(
|
||||
title: "hm",
|
||||
image: UIImage(systemName: "paperclip"),
|
||||
menu: UIMenu(children: attachmentActions))
|
||||
let pollButton = UIBarButtonItem(
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue