mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-22 00:01:00 +00:00
wip
This commit is contained in:
parent
ef8fd98e4b
commit
def0e3fff0
15 changed files with 249 additions and 21 deletions
|
@ -382,6 +382,18 @@ public extension ContentDatabase {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func update(emojis: [Emoji]) -> AnyPublisher<Never, Error> {
|
||||
databaseWriter.writePublisher {
|
||||
for emoji in emojis {
|
||||
try emoji.save($0)
|
||||
}
|
||||
|
||||
try Emoji.filter(!emojis.map(\.shortcode).contains(Emoji.Columns.shortcode)).deleteAll($0)
|
||||
}
|
||||
.ignoreOutput()
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func timelinePublisher(_ timeline: Timeline) -> AnyPublisher<[[CollectionItem]], Error> {
|
||||
ValueObservation.tracking(
|
||||
TimelineItemsInfo.request(TimelineRecord.filter(TimelineRecord.Columns.id == timeline.id)).fetchOne)
|
||||
|
@ -492,6 +504,13 @@ public extension ContentDatabase {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func pickerEmojisPublisher() -> AnyPublisher<[Emoji], Error> {
|
||||
ValueObservation.tracking(Emoji.filter(Emoji.Columns.visibleInPicker == true).fetchAll)
|
||||
.removeDuplicates()
|
||||
.publisher(in: databaseWriter)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func lastReadId(_ markerTimeline: Marker.Timeline) -> String? {
|
||||
try? databaseWriter.read {
|
||||
try String.fetchOne(
|
||||
|
|
17
DB/Sources/DB/Extensions/Emoji+Extensions.swift
Normal file
17
DB/Sources/DB/Extensions/Emoji+Extensions.swift
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Mastodon
|
||||
|
||||
extension Emoji: ContentDatabaseRecord {}
|
||||
|
||||
extension Emoji {
|
||||
enum Columns: String, ColumnExpression {
|
||||
case shortcode
|
||||
case staticUrl
|
||||
case url
|
||||
case visibleInPicker
|
||||
case category
|
||||
}
|
||||
}
|
|
@ -7,4 +7,5 @@ public struct Emoji: Codable, Hashable {
|
|||
public let staticUrl: URL
|
||||
public let url: URL
|
||||
public let visibleInPicker: Bool
|
||||
public let category: String?
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import HTTP
|
||||
import Mastodon
|
||||
|
||||
public enum EmojisEndpoint {
|
||||
case customEmojis
|
||||
}
|
||||
|
||||
extension EmojisEndpoint: Endpoint {
|
||||
public typealias ResultType = [Emoji]
|
||||
|
||||
public var pathComponentsInContext: [String] {
|
||||
["custom_emojis"]
|
||||
}
|
||||
|
||||
public var method: HTTPMethod {
|
||||
.get
|
||||
}
|
||||
}
|
|
@ -55,6 +55,8 @@
|
|||
D0625E5D250F0B5C00502611 /* StatusContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */; };
|
||||
D06BC5E625202AD90079541D /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06BC5E525202AD90079541D /* ProfileViewController.swift */; };
|
||||
D0849C7F25903C4900A5EBCC /* Status+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0849C7E25903C4900A5EBCC /* Status+Extensions.swift */; };
|
||||
D088406D25AFBBE200BB749B /* EmojiPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D088406C25AFBBE200BB749B /* EmojiPickerViewController.swift */; };
|
||||
D088406E25AFBBE200BB749B /* EmojiPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D088406C25AFBBE200BB749B /* EmojiPickerViewController.swift */; };
|
||||
D08B8D3D253F929E00B1EBEF /* ImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B8D3C253F929E00B1EBEF /* ImageViewController.swift */; };
|
||||
D08B8D42253F92B600B1EBEF /* ImagePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B8D41253F92B600B1EBEF /* ImagePageViewController.swift */; };
|
||||
D08B8D4A253FC36500B1EBEF /* ImageNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B8D49253FC36500B1EBEF /* ImageNavigationController.swift */; };
|
||||
|
@ -211,6 +213,7 @@
|
|||
D06BC5E525202AD90079541D /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
|
||||
D0849C7E25903C4900A5EBCC /* Status+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Status+Extensions.swift"; sourceTree = "<group>"; };
|
||||
D085C3BB25008DEC008A6C5E /* DB */ = {isa = PBXFileReference; lastKnownFileType = folder; path = DB; sourceTree = "<group>"; };
|
||||
D088406C25AFBBE200BB749B /* EmojiPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerViewController.swift; sourceTree = "<group>"; };
|
||||
D08B8D3C253F929E00B1EBEF /* ImageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewController.swift; sourceTree = "<group>"; };
|
||||
D08B8D41253F92B600B1EBEF /* ImagePageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePageViewController.swift; sourceTree = "<group>"; };
|
||||
D08B8D49253FC36500B1EBEF /* ImageNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageNavigationController.swift; sourceTree = "<group>"; };
|
||||
|
@ -511,6 +514,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D05936CE25A8D79800754FDF /* EditAttachmentViewController.swift */,
|
||||
D088406C25AFBBE200BB749B /* EmojiPickerViewController.swift */,
|
||||
D08B8D49253FC36500B1EBEF /* ImageNavigationController.swift */,
|
||||
D08B8D41253F92B600B1EBEF /* ImagePageViewController.swift */,
|
||||
D08B8D3C253F929E00B1EBEF /* ImageViewController.swift */,
|
||||
|
@ -866,6 +870,7 @@
|
|||
D0BEB20524FA1107001B0F04 /* FiltersView.swift in Sources */,
|
||||
D0FCC110259C4F20000B67DF /* NewStatusView.swift in Sources */,
|
||||
D0C7D49B24F7616A001EBDBB /* PreferencesView.swift in Sources */,
|
||||
D088406D25AFBBE200BB749B /* EmojiPickerViewController.swift in Sources */,
|
||||
D0C7D4D724F7616A001EBDBB /* UIColor+Extensions.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -904,6 +909,7 @@
|
|||
D0FCC106259C4E62000B67DF /* NewStatusViewController.swift in Sources */,
|
||||
D036EBBD259FE2A100EC1CFC /* Array+Extensions.swift in Sources */,
|
||||
D036EBB3259FE28800EC1CFC /* UIColor+Extensions.swift in Sources */,
|
||||
D088406E25AFBBE200BB749B /* EmojiPickerViewController.swift in Sources */,
|
||||
D036EBB8259FE29800EC1CFC /* Status+Extensions.swift in Sources */,
|
||||
D05936DF25A937EC00754FDF /* EditThumbnailView.swift in Sources */,
|
||||
);
|
||||
|
|
|
@ -62,6 +62,12 @@ public extension IdentityService {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func refreshEmojis() -> AnyPublisher<Never, Error> {
|
||||
mastodonAPIClient.request(EmojisEndpoint.customEmojis)
|
||||
.flatMap(contentDatabase.update(emojis:))
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func confirmIdentity() -> AnyPublisher<Never, Error> {
|
||||
identityDatabase.confirmIdentity(id: id)
|
||||
}
|
||||
|
@ -165,6 +171,10 @@ public extension IdentityService {
|
|||
contentDatabase.expiredFiltersPublisher()
|
||||
}
|
||||
|
||||
func pickerEmojisPublisher() -> AnyPublisher<[Emoji], Error> {
|
||||
contentDatabase.pickerEmojisPublisher()
|
||||
}
|
||||
|
||||
func updatePreferences(_ preferences: Identity.Preferences) -> AnyPublisher<Never, Error> {
|
||||
identityDatabase.updatePreferences(preferences, id: id)
|
||||
.collect()
|
||||
|
|
63
View Controllers/EmojiPickerViewController.swift
Normal file
63
View Controllers/EmojiPickerViewController.swift
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Copyright © 2021 Metabolist. All rights reserved.
|
||||
|
||||
import Combine
|
||||
import UIKit
|
||||
import ViewModels
|
||||
|
||||
final class EmojiPickerViewController: UIViewController {
|
||||
let searchBar = UISearchBar()
|
||||
|
||||
private let viewModel: EmojiPickerViewModel
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init(viewModel: EmojiPickerViewModel) {
|
||||
self.viewModel = viewModel
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
let searchBar = UISearchBar()
|
||||
|
||||
view.addSubview(searchBar)
|
||||
searchBar.translatesAutoresizingMaskIntoConstraints = false
|
||||
searchBar.searchBarStyle = .minimal
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
searchBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
searchBar.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
|
||||
searchBar.trailingAnchor.constraint(equalTo: view.trailingAnchor)
|
||||
])
|
||||
|
||||
// print(UITextInputMode.activeInputModes.map(\.primaryLanguage))
|
||||
print(Locale.availableIdentifiers)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
guard let containerView = popoverPresentationController?.containerView else { return }
|
||||
|
||||
// gets the popover presentation controller's built-in visual effect view to actually show
|
||||
func setClear(view: UIView) {
|
||||
view.backgroundColor = .clear
|
||||
|
||||
if view == self.view {
|
||||
return
|
||||
}
|
||||
|
||||
for view in view.subviews {
|
||||
setClear(view: view)
|
||||
}
|
||||
}
|
||||
|
||||
setClear(view: containerView)
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import SwiftUI
|
|||
import UniformTypeIdentifiers
|
||||
import ViewModels
|
||||
|
||||
// swiftlint:disable file_length
|
||||
final class NewStatusViewController: UIViewController {
|
||||
private let viewModel: NewStatusViewModel
|
||||
private let scrollView = UIScrollView()
|
||||
|
@ -121,6 +122,13 @@ extension NewStatusViewController: UIDocumentPickerDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
extension NewStatusViewController: UIPopoverPresentationControllerDelegate {
|
||||
func adaptivePresentationStyle(for controller: UIPresentationController,
|
||||
traitCollection: UITraitCollection) -> UIModalPresentationStyle {
|
||||
.none
|
||||
}
|
||||
}
|
||||
|
||||
// Required by UIImagePickerController
|
||||
extension NewStatusViewController: UINavigationControllerDelegate {}
|
||||
|
||||
|
@ -135,6 +143,8 @@ private extension NewStatusViewController {
|
|||
#endif
|
||||
case let .presentDocumentPicker(compositionViewModel):
|
||||
presentDocumentPicker(compositionViewModel: compositionViewModel)
|
||||
case let .presentEmojiPicker(tag):
|
||||
presentEmojiPicker(tag: tag)
|
||||
case let .editAttachment(attachmentViewModel, compositionViewModel):
|
||||
presentAttachmentEditor(
|
||||
attachmentViewModel: attachmentViewModel,
|
||||
|
@ -222,7 +232,10 @@ private extension NewStatusViewController {
|
|||
.store(in: &cancellables)
|
||||
viewModel.$alertItem
|
||||
.compactMap { $0 }
|
||||
.sink { [weak self] in self?.present(alertItem: $0) }
|
||||
.sink { [weak self] in
|
||||
self?.dismissEmojiPickerIfPresented()
|
||||
self?.present(alertItem: $0)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
|
@ -258,6 +271,7 @@ private extension NewStatusViewController {
|
|||
|
||||
picker.modalPresentationStyle = .overFullScreen
|
||||
picker.delegate = self
|
||||
dismissEmojiPickerIfPresented()
|
||||
present(picker, animated: true)
|
||||
}
|
||||
|
||||
|
@ -280,7 +294,6 @@ private extension NewStatusViewController {
|
|||
|
||||
alertController.addAction(openSystemSettingsAction)
|
||||
alertController.addAction(cancelAction)
|
||||
|
||||
present(alertController, animated: true)
|
||||
|
||||
return
|
||||
|
@ -310,6 +323,7 @@ private extension NewStatusViewController {
|
|||
picker.mediaTypes = [UTType.image.description]
|
||||
}
|
||||
|
||||
dismissEmojiPickerIfPresented()
|
||||
present(picker, animated: true)
|
||||
}
|
||||
#endif
|
||||
|
@ -332,16 +346,49 @@ private extension NewStatusViewController {
|
|||
documentPickerController.delegate = self
|
||||
documentPickerController.allowsMultipleSelection = false
|
||||
documentPickerController.modalPresentationStyle = .overFullScreen
|
||||
|
||||
dismissEmojiPickerIfPresented()
|
||||
present(documentPickerController, animated: true)
|
||||
}
|
||||
|
||||
func presentEmojiPicker(tag: Int) {
|
||||
if dismissEmojiPickerIfPresented() {
|
||||
return
|
||||
}
|
||||
|
||||
guard let fromView = view.viewWithTag(tag) else { return }
|
||||
|
||||
let emojiPickerController = EmojiPickerViewController(
|
||||
viewModel: .init(identification: viewModel.identification))
|
||||
|
||||
emojiPickerController.searchBar.inputAccessoryView = fromView.inputAccessoryView
|
||||
emojiPickerController.preferredContentSize = view.frame.size
|
||||
emojiPickerController.modalPresentationStyle = .popover
|
||||
emojiPickerController.popoverPresentationController?.delegate = self
|
||||
emojiPickerController.popoverPresentationController?.sourceView = fromView
|
||||
emojiPickerController.popoverPresentationController?.sourceRect = fromView.bounds
|
||||
emojiPickerController.popoverPresentationController?.backgroundColor = .clear
|
||||
|
||||
present(emojiPickerController, animated: true)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func dismissEmojiPickerIfPresented() -> Bool {
|
||||
let emojiPickerPresented = presentedViewController is EmojiPickerViewController
|
||||
|
||||
if emojiPickerPresented {
|
||||
dismiss(animated: true)
|
||||
}
|
||||
|
||||
return emojiPickerPresented
|
||||
}
|
||||
|
||||
func presentAttachmentEditor(attachmentViewModel: AttachmentViewModel, compositionViewModel: CompositionViewModel) {
|
||||
let editAttachmentsView = EditAttachmentView { (attachmentViewModel, compositionViewModel) }
|
||||
let editAttachmentViewController = UIHostingController(rootView: editAttachmentsView)
|
||||
let navigationController = UINavigationController(rootViewController: editAttachmentViewController)
|
||||
|
||||
navigationController.modalPresentationStyle = .overFullScreen
|
||||
dismissEmojiPickerIfPresented()
|
||||
present(navigationController, animated: true)
|
||||
}
|
||||
|
||||
|
@ -383,3 +430,4 @@ private extension NewStatusViewController {
|
|||
return changeIdentityButton
|
||||
}
|
||||
}
|
||||
// swiftlint:enable file_length
|
||||
|
|
12
ViewModels/Sources/ViewModels/EmojiPickerViewModel.swift
Normal file
12
ViewModels/Sources/ViewModels/EmojiPickerViewModel.swift
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
final public class EmojiPickerViewModel: ObservableObject {
|
||||
private let identification: Identification
|
||||
|
||||
public init(identification: Identification) {
|
||||
self.identification = identification
|
||||
}
|
||||
}
|
|
@ -120,6 +120,9 @@ public extension NavigationViewModel {
|
|||
identification.service.refreshFilters()
|
||||
.sink { _ in } receiveValue: { _ in }
|
||||
.store(in: &cancellables)
|
||||
identification.service.refreshEmojis()
|
||||
.sink { _ in } receiveValue: { _ in }
|
||||
.store(in: &cancellables)
|
||||
|
||||
if identification.identity.preferences.useServerPostingReadingPreferences {
|
||||
identification.service.refreshServerPreferences()
|
||||
|
|
|
@ -66,6 +66,7 @@ public extension NewStatusViewModel {
|
|||
case presentMediaPicker(CompositionViewModel)
|
||||
case presentCamera(CompositionViewModel)
|
||||
case presentDocumentPicker(CompositionViewModel)
|
||||
case presentEmojiPicker(Int)
|
||||
case editAttachment(AttachmentViewModel, CompositionViewModel)
|
||||
}
|
||||
|
||||
|
@ -106,6 +107,10 @@ public extension NewStatusViewModel {
|
|||
eventsSubject.send(.presentDocumentPicker(viewModel))
|
||||
}
|
||||
|
||||
func presentEmojiPicker(tag: Int) {
|
||||
eventsSubject.send(.presentEmojiPicker(tag))
|
||||
}
|
||||
|
||||
func remove(viewModel: CompositionViewModel) {
|
||||
compositionViewModels.removeAll { $0 === viewModel }
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ final class CompositionInputAccessoryView: UIView {
|
|||
let visibilityButton = UIButton()
|
||||
let addButton = UIButton()
|
||||
let contentWarningButton = UIButton(type: .system)
|
||||
let tagForInputView = UUID().hashValue
|
||||
|
||||
private let viewModel: CompositionViewModel
|
||||
private let parentViewModel: NewStatusViewModel
|
||||
|
@ -111,6 +112,19 @@ private extension CompositionInputAccessoryView {
|
|||
UIAction { [weak self] _ in self?.viewModel.displayContentWarning.toggle() },
|
||||
for: .touchUpInside)
|
||||
|
||||
let emojiButton = UIButton(primaryAction: UIAction { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
|
||||
self.parentViewModel.presentEmojiPicker(tag: self.tagForInputView)
|
||||
})
|
||||
|
||||
stackView.addArrangedSubview(emojiButton)
|
||||
emojiButton.setImage(
|
||||
UIImage(
|
||||
systemName: "face.smiling",
|
||||
withConfiguration: UIImage.SymbolConfiguration(scale: .medium)),
|
||||
for: .normal)
|
||||
|
||||
stackView.addArrangedSubview(UIView())
|
||||
|
||||
let charactersLabel = UILabel()
|
||||
|
@ -155,7 +169,7 @@ private extension CompositionInputAccessoryView {
|
|||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
for button in [attachmentButton, pollButton, visibilityButton, contentWarningButton, addButton] {
|
||||
for button in [attachmentButton, pollButton, visibilityButton, contentWarningButton, emojiButton, addButton] {
|
||||
button.heightAnchor.constraint(greaterThanOrEqualToConstant: .minimumButtonDimension).isActive = true
|
||||
button.widthAnchor.constraint(greaterThanOrEqualToConstant: .minimumButtonDimension).isActive = true
|
||||
}
|
||||
|
|
|
@ -8,15 +8,15 @@ final class CompositionPollOptionView: UIView {
|
|||
let option: CompositionViewModel.PollOption
|
||||
let removeButton = UIButton(type: .close)
|
||||
private let viewModel: CompositionViewModel
|
||||
private let compositionInputAccessoryView: CompositionInputAccessoryView
|
||||
private let parentViewModel: NewStatusViewModel
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init(viewModel: CompositionViewModel,
|
||||
option: CompositionViewModel.PollOption,
|
||||
inputAccessoryView: CompositionInputAccessoryView) {
|
||||
parentViewModel: NewStatusViewModel,
|
||||
option: CompositionViewModel.PollOption) {
|
||||
self.viewModel = viewModel
|
||||
self.parentViewModel = parentViewModel
|
||||
self.option = option
|
||||
self.compositionInputAccessoryView = inputAccessoryView
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
|
@ -44,7 +44,11 @@ private extension CompositionPollOptionView {
|
|||
textField.borderStyle = .roundedRect
|
||||
textField.adjustsFontForContentSizeCategory = true
|
||||
textField.font = .preferredFont(forTextStyle: .body)
|
||||
textField.inputAccessoryView = compositionInputAccessoryView
|
||||
let textInputAccessoryView = CompositionInputAccessoryView(
|
||||
viewModel: viewModel,
|
||||
parentViewModel: parentViewModel)
|
||||
textField.inputAccessoryView = textInputAccessoryView
|
||||
textField.tag = textInputAccessoryView.tagForInputView
|
||||
textField.addAction(
|
||||
UIAction { [weak self] _ in
|
||||
self?.option.text = textField.text ?? "" },
|
||||
|
|
|
@ -6,13 +6,13 @@ import ViewModels
|
|||
|
||||
final class CompositionPollView: UIView {
|
||||
private let viewModel: CompositionViewModel
|
||||
private let compositionInputAccessoryView: CompositionInputAccessoryView
|
||||
private let parentViewModel: NewStatusViewModel
|
||||
private let stackView = UIStackView()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init(viewModel: CompositionViewModel, inputAccessoryView: CompositionInputAccessoryView) {
|
||||
init(viewModel: CompositionViewModel, parentViewModel: NewStatusViewModel) {
|
||||
self.viewModel = viewModel
|
||||
self.compositionInputAccessoryView = inputAccessoryView
|
||||
self.parentViewModel = parentViewModel
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
|
@ -118,8 +118,8 @@ private extension CompositionPollView {
|
|||
if !self.pollOptionViews.contains(where: { $0.option === option }) {
|
||||
let optionView = CompositionPollOptionView(
|
||||
viewModel: self.viewModel,
|
||||
option: option,
|
||||
inputAccessoryView: self.compositionInputAccessoryView)
|
||||
parentViewModel: self.parentViewModel,
|
||||
option: option)
|
||||
|
||||
self.stackView.insertArrangedSubview(optionView, at: index)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ final class CompositionView: UIView {
|
|||
let removeButton = UIButton(type: .close)
|
||||
let inReplyToView = UIView()
|
||||
let hasReplyFollowingView = UIView()
|
||||
let compositionInputAccessoryView: CompositionInputAccessoryView
|
||||
let attachmentsView = AttachmentsView()
|
||||
let attachmentUploadView: AttachmentUploadView
|
||||
let pollView: CompositionPollView
|
||||
|
@ -27,12 +26,9 @@ final class CompositionView: UIView {
|
|||
self.viewModel = viewModel
|
||||
self.parentViewModel = parentViewModel
|
||||
|
||||
compositionInputAccessoryView = CompositionInputAccessoryView(
|
||||
viewModel: viewModel,
|
||||
parentViewModel: parentViewModel)
|
||||
attachmentUploadView = AttachmentUploadView(viewModel: viewModel)
|
||||
markAttachmentsSensitiveView = MarkAttachmentsSensitiveView(viewModel: viewModel)
|
||||
pollView = CompositionPollView(viewModel: viewModel, inputAccessoryView: compositionInputAccessoryView)
|
||||
pollView = CompositionPollView(viewModel: viewModel, parentViewModel: parentViewModel)
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
|
@ -75,12 +71,17 @@ private extension CompositionView {
|
|||
stackView.axis = .vertical
|
||||
stackView.spacing = .defaultSpacing
|
||||
|
||||
let spoilerTextinputAccessoryView = CompositionInputAccessoryView(
|
||||
viewModel: viewModel,
|
||||
parentViewModel: parentViewModel)
|
||||
|
||||
stackView.addArrangedSubview(spoilerTextField)
|
||||
spoilerTextField.borderStyle = .roundedRect
|
||||
spoilerTextField.adjustsFontForContentSizeCategory = true
|
||||
spoilerTextField.font = .preferredFont(forTextStyle: .body)
|
||||
spoilerTextField.placeholder = NSLocalizedString("status.spoiler-text-placeholder", comment: "")
|
||||
spoilerTextField.inputAccessoryView = compositionInputAccessoryView
|
||||
spoilerTextField.inputAccessoryView = spoilerTextinputAccessoryView
|
||||
spoilerTextField.tag = spoilerTextinputAccessoryView.tagForInputView
|
||||
spoilerTextField.addAction(
|
||||
UIAction { [weak self] _ in
|
||||
guard let self = self, let text = self.spoilerTextField.text else { return }
|
||||
|
@ -90,6 +91,9 @@ private extension CompositionView {
|
|||
for: .editingChanged)
|
||||
|
||||
let textViewFont = UIFont.preferredFont(forTextStyle: .body)
|
||||
let textInputAccessoryView = CompositionInputAccessoryView(
|
||||
viewModel: viewModel,
|
||||
parentViewModel: parentViewModel)
|
||||
|
||||
stackView.addArrangedSubview(textView)
|
||||
textView.isScrollEnabled = false
|
||||
|
@ -97,7 +101,8 @@ private extension CompositionView {
|
|||
textView.font = textViewFont
|
||||
textView.textContainerInset = .zero
|
||||
textView.textContainer.lineFragmentPadding = 0
|
||||
textView.inputAccessoryView = compositionInputAccessoryView
|
||||
textView.inputAccessoryView = textInputAccessoryView
|
||||
textView.tag = textInputAccessoryView.tagForInputView
|
||||
textView.inputAccessoryView?.sizeToFit()
|
||||
textView.delegate = self
|
||||
|
||||
|
|
Loading…
Reference in a new issue