metatext/Views/UIKit/CompositionPollOptionView.swift

125 lines
4.6 KiB
Swift
Raw Normal View History

2021-01-11 00:06:20 +00:00
// Copyright © 2021 Metabolist. All rights reserved.
import Combine
import UIKit
import ViewModels
final class CompositionPollOptionView: UIView {
2021-01-19 19:59:20 +00:00
let textField = UITextField()
2021-01-11 00:06:20 +00:00
let option: CompositionViewModel.PollOption
let removeButton = UIButton(type: .close)
private let viewModel: CompositionViewModel
2021-01-14 17:49:53 +00:00
private let parentViewModel: NewStatusViewModel
2021-01-11 00:06:20 +00:00
private var cancellables = Set<AnyCancellable>()
init(viewModel: CompositionViewModel,
2021-01-14 17:49:53 +00:00
parentViewModel: NewStatusViewModel,
option: CompositionViewModel.PollOption) {
2021-01-11 00:06:20 +00:00
self.viewModel = viewModel
2021-01-14 17:49:53 +00:00
self.parentViewModel = parentViewModel
2021-01-11 00:06:20 +00:00
self.option = option
super.init(frame: .zero)
initialSetup()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
private extension CompositionPollOptionView {
// swiftlint:disable:next function_body_length
func initialSetup() {
let stackView = UIStackView()
let remainingCharactersLabel = UILabel()
addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.spacing = .defaultSpacing
stackView.addArrangedSubview(textField)
textField.borderStyle = .roundedRect
textField.adjustsFontForContentSizeCategory = true
textField.font = .preferredFont(forTextStyle: .body)
2021-01-14 17:49:53 +00:00
let textInputAccessoryView = CompositionInputAccessoryView(
viewModel: viewModel,
2021-02-14 02:28:30 +00:00
parentViewModel: parentViewModel,
autocompleteQueryPublisher: option.$autocompleteQuery.eraseToAnyPublisher())
2021-01-14 17:49:53 +00:00
textField.inputAccessoryView = textInputAccessoryView
textField.tag = textInputAccessoryView.tagForInputView
2021-01-11 00:06:20 +00:00
textField.addAction(
2021-02-15 21:52:28 +00:00
UIAction { [weak self] _ in self?.textFieldEditingChanged() },
2021-01-11 00:06:20 +00:00
for: .editingChanged)
2021-01-11 22:45:30 +00:00
textField.text = option.text
2021-01-11 00:06:20 +00:00
stackView.addArrangedSubview(remainingCharactersLabel)
remainingCharactersLabel.adjustsFontForContentSizeCategory = true
remainingCharactersLabel.font = .preferredFont(forTextStyle: .callout)
remainingCharactersLabel.setContentHuggingPriority(.required, for: .horizontal)
stackView.addArrangedSubview(removeButton)
removeButton.showsMenuAsPrimaryAction = true
removeButton.menu = UIMenu(
children: [
UIAction(
title: NSLocalizedString("remove", comment: ""),
image: UIImage(systemName: "trash"),
attributes: .destructive) { [weak self] _ in
guard let self = self else { return }
self.viewModel.remove(pollOption: self.option)
}])
removeButton.setContentHuggingPriority(.required, for: .horizontal)
removeButton.setContentHuggingPriority(.required, for: .vertical)
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
option.$remainingCharacters
.sink {
remainingCharactersLabel.text = String($0)
remainingCharactersLabel.textColor = $0 < 0 ? .systemRed : .label
}
.store(in: &cancellables)
2021-02-15 21:52:28 +00:00
textInputAccessoryView.autocompleteSelections
.sink { [weak self] in self?.autocompleteSelected($0) }
.store(in: &cancellables)
}
func textFieldEditingChanged() {
guard let text = textField.text else { return }
option.text = text
if let textToSelectedRange = textField.textToSelectedRange {
option.textToSelectedRange = textToSelectedRange
}
}
func autocompleteSelected(_ autocompleteText: String) {
guard let autocompleteQuery = option.autocompleteQuery,
let queryRange = option.textToSelectedRange.range(of: autocompleteQuery, options: .backwards),
let textToSelectedRangeRange = option.text.range(of: option.textToSelectedRange)
else { return }
let replaced = option.textToSelectedRange.replacingOccurrences(
of: autocompleteQuery,
with: autocompleteText.appending(" "),
range: queryRange)
textField.text = option.text.replacingOccurrences(
of: option.textToSelectedRange,
with: replaced,
range: textToSelectedRangeRange)
textFieldEditingChanged()
2021-01-11 00:06:20 +00:00
}
}