diff --git a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift index 885840110..f44d29a68 100644 --- a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift +++ b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift @@ -11,12 +11,17 @@ import Combine import MetaTextKit import UITextView_Placeholder +protocol ComposeStatusContentTableViewCellDelegate: AnyObject { + func composeStatusContentTableViewCell(_ cell: ComposeStatusContentTableViewCell, textViewShouldBeginEditing textView: UITextView) -> Bool +} + final class ComposeStatusContentTableViewCell: UITableViewCell { let logger = Logger(subsystem: "ComposeStatusContentTableViewCell", category: "UI") var disposeBag = Set() - + weak var delegate: ComposeStatusContentTableViewCellDelegate? + let statusView = ReplicaStatusView() let statusContentWarningEditorView = StatusContentWarningEditorView() @@ -136,6 +141,10 @@ extension ComposeStatusContentTableViewCell { // MARK: - UITextViewDelegate extension ComposeStatusContentTableViewCell: UITextViewDelegate { + + func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { + return delegate?.composeStatusContentTableViewCell(self, textViewShouldBeginEditing: textView) ?? true + } func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { switch textView { diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index 460d12cac..3f8327909 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -26,9 +26,20 @@ final class ComposeViewController: UIViewController, NeedsDependency { var viewModel: ComposeViewModel! let logger = Logger(subsystem: "ComposeViewController", category: "logic") - - private var suffixedAttachmentViews: [UIView] = [] + private(set) lazy var cancelBarButtonItem = UIBarButtonItem(title: L10n.Common.Controls.Actions.cancel, style: .plain, target: self, action: #selector(ComposeViewController.cancelBarButtonItemPressed(_:))) + let characterCountLabel: UILabel = { + let label = UILabel() + label.font = .systemFont(ofSize: 15, weight: .regular) + label.text = "500" + label.textColor = Asset.Colors.Label.secondary.color + label.accessibilityLabel = L10n.A11y.Plural.Count.inputLimitRemains(500) + return label + }() + private(set) lazy var characterCountBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem(customView: characterCountLabel) + return barButtonItem + }() let publishButton: UIButton = { let button = RoundedEdgesButton(type: .custom) button.setTitle(L10n.Scene.Compose.composeAction, for: .normal) @@ -41,8 +52,6 @@ final class ComposeViewController: UIViewController, NeedsDependency { button.adjustsImageWhenHighlighted = false return button }() - - private(set) lazy var cancelBarButtonItem = UIBarButtonItem(title: L10n.Common.Controls.Actions.cancel, style: .plain, target: self, action: #selector(ComposeViewController.cancelBarButtonItemPressed(_:))) private(set) lazy var publishBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem(customView: publishButton) return barButtonItem @@ -136,17 +145,16 @@ extension ComposeViewController { override func viewDidLoad() { super.viewDidLoad() - - let groups = [UIBarButtonItemGroup(barButtonItems: [ - composeToolbarView.mediaBarButtonItem, - composeToolbarView.pollBarButtonItem, - composeToolbarView.contentWarningBarButtonItem, - composeToolbarView.visibilityBarButtonItem, - ], representativeItem: nil)] - - tableView.inputAssistantItem.trailingBarButtonGroups = groups - textEditorView()?.textView.inputAssistantItem.trailingBarButtonGroups = groups + configureNavigationBarTitleStyle() + viewModel.traitCollectionDidChangePublisher + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.configureNavigationBarTitleStyle() + } + .store(in: &disposeBag) + viewModel.title .receive(on: DispatchQueue.main) .sink { [weak self] title in @@ -164,6 +172,18 @@ extension ComposeViewController { .store(in: &disposeBag) navigationItem.leftBarButtonItem = cancelBarButtonItem navigationItem.rightBarButtonItem = publishBarButtonItem + viewModel.traitCollectionDidChangePublisher + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + guard self.traitCollection.userInterfaceIdiom == .pad else { return } + var items = [self.publishBarButtonItem] + if self.traitCollection.horizontalSizeClass == .regular { + items.append(self.characterCountBarButtonItem) + } + self.navigationItem.rightBarButtonItems = items + } + .store(in: &disposeBag) publishButton.addTarget(self, action: #selector(ComposeViewController.publishBarButtonItemPressed(_:)), for: .touchUpInside) @@ -229,8 +249,12 @@ extension ComposeViewController { dependency: self ) + viewModel.composeStatusContentTableViewCell.delegate = self + // update layout when keyboard show/dismiss view.layoutIfNeeded() + + let keyboardHasShortcutBar = CurrentValueSubject(traitCollection.userInterfaceIdiom == .pad) // update default value later let keyboardEventPublishers = Publishers.CombineLatest3( KeyboardResponderService.shared.isShow, KeyboardResponderService.shared.state, @@ -243,8 +267,16 @@ extension ComposeViewController { ) .sink(receiveValue: { [weak self] keyboardEvents, isCustomEmojiComposing, autoCompleteInfo in guard let self = self else { return } - + let (isShow, state, endFrame) = keyboardEvents + + switch self.traitCollection.userInterfaceIdiom { + case .pad: + keyboardHasShortcutBar.value = state != .floating + default: + keyboardHasShortcutBar.value = false + } + let extraMargin: CGFloat = { var margin = self.composeToolbarView.frame.height if autoCompleteInfo != nil { @@ -342,7 +374,7 @@ extension ComposeViewController { .receive(on: DispatchQueue.main) .sink { [weak self] isMediaToolbarButtonEnabled in guard let self = self else { return } -// self.composeToolbarView.mediaBarButtonItem.isEnabled = isMediaToolbarButtonEnabled + self.composeToolbarView.mediaBarButtonItem.isEnabled = isMediaToolbarButtonEnabled self.composeToolbarView.mediaButton.isEnabled = isMediaToolbarButtonEnabled } .store(in: &disposeBag) @@ -352,7 +384,7 @@ extension ComposeViewController { .receive(on: DispatchQueue.main) .sink { [weak self] isPollToolbarButtonEnabled in guard let self = self else { return } -// self.composeToolbarView.pollBarButtonItem.isEnabled = isPollToolbarButtonEnabled + self.composeToolbarView.pollBarButtonItem.isEnabled = isPollToolbarButtonEnabled self.composeToolbarView.pollButton.isEnabled = isPollToolbarButtonEnabled } .store(in: &disposeBag) @@ -366,12 +398,12 @@ extension ComposeViewController { guard let self = self else { return } guard isPollToolbarButtonEnabled else { let accessibilityLabel = L10n.Scene.Compose.Accessibility.appendPoll -// self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel + self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel self.composeToolbarView.pollButton.accessibilityLabel = accessibilityLabel return } let accessibilityLabel = isPollComposing ? L10n.Scene.Compose.Accessibility.removePoll : L10n.Scene.Compose.Accessibility.appendPoll -// self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel + self.composeToolbarView.pollBarButtonItem.accessibilityLabel = accessibilityLabel self.composeToolbarView.pollButton.accessibilityLabel = accessibilityLabel } .store(in: &disposeBag) @@ -381,7 +413,9 @@ extension ComposeViewController { .receive(on: DispatchQueue.main) .sink { [weak self] attachmentServices in guard let self = self else { return } - self.composeToolbarView.mediaButton.isEnabled = attachmentServices.count < 4 + let isEnabled = attachmentServices.count < 4 + self.composeToolbarView.mediaBarButtonItem.isEnabled = isEnabled + self.composeToolbarView.mediaButton.isEnabled = isEnabled self.resetImagePicker() } .store(in: &disposeBag) @@ -391,7 +425,9 @@ extension ComposeViewController { .receive(on: DispatchQueue.main) .sink { [weak self] isContentWarningComposing in guard let self = self else { return } - self.composeToolbarView.contentWarningButton.accessibilityLabel = isContentWarningComposing ? L10n.Scene.Compose.Accessibility.disableContentWarning : L10n.Scene.Compose.Accessibility.enableContentWarning + let accessibilityLabel = isContentWarningComposing ? L10n.Scene.Compose.Accessibility.disableContentWarning : L10n.Scene.Compose.Accessibility.enableContentWarning + self.composeToolbarView.contentWarningBarButtonItem.accessibilityLabel = accessibilityLabel + self.composeToolbarView.contentWarningButton.accessibilityLabel = accessibilityLabel } .store(in: &disposeBag) @@ -404,6 +440,7 @@ extension ComposeViewController { .sink { [weak self] type, _ in guard let self = self else { return } let image = type.image(interfaceStyle: self.traitCollection.userInterfaceStyle) + self.composeToolbarView.visibilityBarButtonItem.image = image self.composeToolbarView.visibilityButton.setImage(image, for: .normal) self.composeToolbarView.activeVisibilityType.value = type } @@ -415,16 +452,27 @@ extension ComposeViewController { guard let self = self else { return } let count = ComposeViewModel.composeContentLimit - characterCount self.composeToolbarView.characterCountLabel.text = "\(count)" + self.characterCountLabel.text = "\(count)" + let font: UIFont + let textColor: UIColor + let accessibilityLabel: String switch count { case _ where count < 0: - self.composeToolbarView.characterCountLabel.font = .monospacedDigitSystemFont(ofSize: 24, weight: .bold) - self.composeToolbarView.characterCountLabel.textColor = Asset.Colors.danger.color - self.composeToolbarView.characterCountLabel.accessibilityLabel = L10n.A11y.Plural.Count.inputLimitExceeds(abs(count)) + font = .monospacedDigitSystemFont(ofSize: 24, weight: .bold) + textColor = Asset.Colors.danger.color + accessibilityLabel = L10n.A11y.Plural.Count.inputLimitExceeds(abs(count)) default: - self.composeToolbarView.characterCountLabel.font = .monospacedDigitSystemFont(ofSize: 15, weight: .regular) - self.composeToolbarView.characterCountLabel.textColor = Asset.Colors.Label.secondary.color - self.composeToolbarView.characterCountLabel.accessibilityLabel = L10n.A11y.Plural.Count.inputLimitRemains(count) + font = .monospacedDigitSystemFont(ofSize: 15, weight: .regular) + textColor = Asset.Colors.Label.secondary.color + accessibilityLabel = L10n.A11y.Plural.Count.inputLimitRemains(count) } + self.composeToolbarView.characterCountLabel.font = font + self.composeToolbarView.characterCountLabel.textColor = textColor + self.composeToolbarView.characterCountLabel.accessibilityLabel = accessibilityLabel + self.characterCountLabel.font = font + self.characterCountLabel.textColor = textColor + self.characterCountLabel.accessibilityLabel = accessibilityLabel + self.characterCountLabel.sizeToFit() } .store(in: &disposeBag) @@ -467,6 +515,18 @@ extension ComposeViewController { } } .store(in: &disposeBag) + + configureToolbarDisplay(keyboardHasShortcutBar: keyboardHasShortcutBar.value) + Publishers.CombineLatest( + keyboardHasShortcutBar, + viewModel.traitCollectionDidChangePublisher + ) + .receive(on: DispatchQueue.main) + .sink { [weak self] keyboardHasShortcutBar, _ in + guard let self = self else { return } + self.configureToolbarDisplay(keyboardHasShortcutBar: keyboardHasShortcutBar) + } + .store(in: &disposeBag) } override func viewWillAppear(_ animated: Bool) { @@ -578,11 +638,7 @@ extension ComposeViewController { } private func showDismissConfirmAlertController() { - let alertController = UIAlertController( - title: L10n.Common.Alerts.DiscardPostContent.title, - message: L10n.Common.Alerts.DiscardPostContent.message, - preferredStyle: .alert - ) + let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let discardAction = UIAlertAction(title: L10n.Common.Controls.Actions.discard, style: .destructive) { [weak self] _ in guard let self = self else { return } self.dismiss(animated: true, completion: nil) @@ -590,6 +646,7 @@ extension ComposeViewController { alertController.addAction(discardAction) let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel) alertController.addAction(cancelAction) + alertController.popoverPresentationController?.barButtonItem = cancelBarButtonItem present(alertController, animated: true, completion: nil) } @@ -610,6 +667,37 @@ extension ComposeViewController { tableView.backgroundColor = theme.systemElevatedBackgroundColor composeToolbarBackgroundView.backgroundColor = theme.composeToolbarBackgroundColor } + + private func setupInputAssistantItem(item: UITextInputAssistantItem) { + let groups = [UIBarButtonItemGroup(barButtonItems: [ + composeToolbarView.mediaBarButtonItem, + composeToolbarView.pollBarButtonItem, + composeToolbarView.contentWarningBarButtonItem, + composeToolbarView.visibilityBarButtonItem, + ], representativeItem: nil)] + + item.trailingBarButtonGroups = groups + } + + private func configureToolbarDisplay(keyboardHasShortcutBar: Bool) { + switch self.traitCollection.userInterfaceIdiom { + case .pad: + let shouldHideToolbar = keyboardHasShortcutBar && self.traitCollection.horizontalSizeClass == .regular + self.composeToolbarView.alpha = shouldHideToolbar ? 0 : 1 + self.composeToolbarBackgroundView.alpha = shouldHideToolbar ? 0 : 1 + default: + break + } + } + + private func configureNavigationBarTitleStyle() { + switch traitCollection.userInterfaceIdiom { + case .pad: + navigationController?.navigationBar.prefersLargeTitles = traitCollection.horizontalSizeClass == .regular + default: + break + } + } } @@ -661,6 +749,20 @@ extension ComposeViewController: MetaTextDelegate { // MARK: - UITextViewDelegate extension ComposeViewController: UITextViewDelegate { + + func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { + setupInputAssistantItem(item: textView.inputAssistantItem) + return true + } +// func textViewDidBeginEditing(_ textView: UITextView) { +// switch textView { +// case textEditorView()?.textView: +// setupInputAssistantItem(item: textView.inputAssistantItem) +// default: +// assertionFailure() +// break +// } +// } func textViewDidChange(_ textView: UITextView) { if textEditorView()?.textView === textView { @@ -801,7 +903,7 @@ extension ComposeViewController: UITextViewDelegate { // MARK: - ComposeToolbarViewDelegate extension ComposeViewController: ComposeToolbarViewDelegate { - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: UIButton, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: Any, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) { switch type { case .photoLibrary: present(photoLibraryPicker, animated: true, completion: nil) @@ -812,7 +914,7 @@ extension ComposeViewController: ComposeToolbarViewDelegate { } } - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: UIButton) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: Any) { // toggle poll composing state viewModel.isPollComposing.value.toggle() @@ -834,11 +936,11 @@ extension ComposeViewController: ComposeToolbarViewDelegate { } } - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: UIButton) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: Any) { viewModel.isCustomEmojiComposing.value.toggle() } - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: UIButton) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: Any) { // cancel custom picker input viewModel.isCustomEmojiComposing.value = false @@ -858,7 +960,7 @@ extension ComposeViewController: ComposeToolbarViewDelegate { } } - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: UIButton, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType) { + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: Any, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType) { viewModel.selectedStatusVisibility.value = type } @@ -1048,6 +1150,9 @@ extension ComposeViewController: ComposeStatusAttachmentCollectionViewCellDelega extension ComposeViewController: ComposeStatusPollOptionCollectionViewCellDelegate { func composeStatusPollOptionCollectionViewCell(_ cell: ComposeStatusPollOptionCollectionViewCell, textFieldDidBeginEditing textField: UITextField) { + + setupInputAssistantItem(item: textField.inputAssistantItem) + // FIXME: make poll section visible // DispatchQueue.main.async { // self.collectionView.scroll(to: .bottom, animated: true) @@ -1144,6 +1249,14 @@ extension ComposeViewController: ComposeStatusPollExpiresOptionCollectionViewCel } } +// MARK: - ComposeStatusContentTableViewCellDelegate +extension ComposeViewController: ComposeStatusContentTableViewCellDelegate { + func composeStatusContentTableViewCell(_ cell: ComposeStatusContentTableViewCell, textViewShouldBeginEditing textView: UITextView) -> Bool { + setupInputAssistantItem(item: textView.inputAssistantItem) + return true + } +} + // MARK: - AutoCompleteViewControllerDelegate extension ComposeViewController: AutoCompleteViewControllerDelegate { func autoCompleteViewController(_ viewController: AutoCompleteViewController, didSelectItem item: AutoCompleteItem) { diff --git a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift index f6e700fbb..03ee911e4 100644 --- a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift +++ b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift @@ -39,6 +39,24 @@ extension ComposeViewModel { // setup data source tableView.dataSource = self + + composeStatusAttachmentTableViewCell.collectionViewHeightDidUpdate + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let _ = self else { return } + tableView.beginUpdates() + tableView.endUpdates() + } + .store(in: &disposeBag) + +// composeStatusPollTableViewCell.collectionViewHeightDidUpdate +// .receive(on: DispatchQueue.main) +// .sink { [weak self] _ in +// guard let _ = self else { return } +// tableView.beginUpdates() +// tableView.endUpdates() +// } +// .store(in: &disposeBag) attachmentServices .removeDuplicates() @@ -55,10 +73,10 @@ extension ComposeViewModel { let items = attachmentServices.map { ComposeStatusAttachmentItem.attachment(attachmentService: $0) } snapshot.appendItems(items, toSection: .main) - tableView.performBatchUpdates { - dataSource.apply(snapshot, animatingDifferences: true) - } completion: { _ in - // do nothing + if #available(iOS 15.0, *) { + dataSource.applySnapshotUsingReloadData(snapshot) + } else { + dataSource.apply(snapshot, animatingDifferences: false) } } .store(in: &disposeBag) @@ -90,9 +108,11 @@ extension ComposeViewModel { snapshot.appendItems(items, toSection: .main) tableView.performBatchUpdates { - dataSource.apply(snapshot, animatingDifferences: true) - } completion: { _ in - // do nothing + if #available(iOS 15.0, *) { + dataSource.apply(snapshot, animatingDifferences: false) + } else { + dataSource.apply(snapshot, animatingDifferences: true) + } } } .store(in: &disposeBag) diff --git a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusAttachmentTableViewCell.swift b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusAttachmentTableViewCell.swift index 561c6c3ba..6d2bbe93a 100644 --- a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusAttachmentTableViewCell.swift +++ b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusAttachmentTableViewCell.swift @@ -35,6 +35,7 @@ final class ComposeStatusAttachmentTableViewCell: UITableViewCell { collectionView.isScrollEnabled = false return collectionView }() + let collectionViewHeightDidUpdate = PassthroughSubject() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -68,6 +69,7 @@ extension ComposeStatusAttachmentTableViewCell { collectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] collectionView, _ in guard let self = self else { return } self.collectionViewHeightLayoutConstraint.constant = collectionView.contentSize.height + self.collectionViewHeightDidUpdate.send() } .store(in: &observations) diff --git a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift index 0c2abb262..ac8d5094f 100644 --- a/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift +++ b/Mastodon/Scene/Compose/TableViewCell/ComposeStatusPollTableViewCell.swift @@ -7,6 +7,7 @@ import os.log import UIKit +import Combine protocol ComposeStatusPollTableViewCellDelegate: AnyObject { func composeStatusPollTableViewCell(_ cell: ComposeStatusPollTableViewCell, pollOptionAttributesDidReorder options: [ComposeStatusPollItem.PollOptionAttribute]) @@ -49,6 +50,7 @@ final class ComposeStatusPollTableViewCell: UITableViewCell { collectionView.dragInteractionEnabled = true return collectionView }() + let collectionViewHeightDidUpdate = PassthroughSubject() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -82,6 +84,7 @@ extension ComposeStatusPollTableViewCell { collectionView.observe(\.contentSize, options: [.initial, .new]) { [weak self] collectionView, _ in guard let self = self else { return } self.collectionViewHeightLayoutConstraint.constant = collectionView.contentSize.height + self.collectionViewHeightDidUpdate.send() } .store(in: &observations) diff --git a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift index a8ceeee3a..373ce1a15 100644 --- a/Mastodon/Scene/Compose/View/ComposeToolbarView.swift +++ b/Mastodon/Scene/Compose/View/ComposeToolbarView.swift @@ -11,11 +11,11 @@ import Combine import MastodonSDK protocol ComposeToolbarViewDelegate: AnyObject { - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: UIButton, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: UIButton) - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: UIButton) - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: UIButton) - func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: UIButton, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, cameraButtonDidPressed sender: Any, mediaSelectionType type: ComposeToolbarView.MediaSelectionType) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: Any) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, emojiButtonDidPressed sender: Any) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: Any) + func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: Any, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType) } final class ComposeToolbarView: UIView { @@ -28,13 +28,9 @@ final class ComposeToolbarView: UIView { weak var delegate: ComposeToolbarViewDelegate? // barButtonItem - let mediaBarButton: UIButton = { - let button = UIButton() - button.setImage(UIImage(systemName: "photo"), for: .normal) - return button - }() private(set) lazy var mediaBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem(customView: mediaBarButton) + let barButtonItem = UIBarButtonItem() + barButtonItem.image = UIImage(systemName: "photo") barButtonItem.accessibilityLabel = L10n.Scene.Compose.Accessibility.appendAttachment return barButtonItem }() @@ -177,11 +173,17 @@ extension ComposeToolbarView { ]) characterCountLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal) + mediaBarButtonItem.menu = createMediaContextMenu() mediaButton.menu = createMediaContextMenu() mediaButton.showsMenuAsPrimaryAction = true + pollBarButtonItem.target = self + pollBarButtonItem.action = #selector(ComposeToolbarView.pollButtonDidPressed(_:)) pollButton.addTarget(self, action: #selector(ComposeToolbarView.pollButtonDidPressed(_:)), for: .touchUpInside) emojiButton.addTarget(self, action: #selector(ComposeToolbarView.emojiButtonDidPressed(_:)), for: .touchUpInside) + contentWarningBarButtonItem.target = self + contentWarningBarButtonItem.action = #selector(ComposeToolbarView.contentWarningButtonDidPressed(_:)) contentWarningButton.addTarget(self, action: #selector(ComposeToolbarView.contentWarningButtonDidPressed(_:)), for: .touchUpInside) + visibilityBarButtonItem.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle) visibilityButton.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle) visibilityButton.showsMenuAsPrimaryAction = true @@ -192,6 +194,7 @@ extension ComposeToolbarView { .receive(on: RunLoop.main) .sink { [weak self] type in guard let self = self else { return } + self.visibilityBarButtonItem.menu = self.createVisibilityContextMenu(interfaceStyle: self.traitCollection.userInterfaceStyle) self.visibilityButton.menu = self.createVisibilityContextMenu(interfaceStyle: self.traitCollection.userInterfaceStyle) } .store(in: &disposeBag) @@ -275,17 +278,22 @@ extension ComposeToolbarView { switch traitCollection.userInterfaceStyle { case .light: + mediaBarButtonItem.image = UIImage(systemName: "photo") mediaButton.setImage(UIImage(systemName: "photo", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal) + contentWarningBarButtonItem.image = UIImage(systemName: "exclamationmark.shield") contentWarningButton.setImage(UIImage(systemName: "exclamationmark.shield", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal) case .dark: + mediaBarButtonItem.image = UIImage(systemName: "photo.fill") mediaButton.setImage(UIImage(systemName: "photo.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal) + contentWarningBarButtonItem.image = UIImage(systemName: "exclamationmark.shield.fill") contentWarningButton.setImage(UIImage(systemName: "exclamationmark.shield.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))!, for: .normal) default: assertionFailure() } + visibilityBarButtonItem.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle) visibilityButton.menu = createVisibilityContextMenu(interfaceStyle: traitCollection.userInterfaceStyle) } @@ -331,17 +339,17 @@ extension ComposeToolbarView { extension ComposeToolbarView { - @objc private func pollButtonDidPressed(_ sender: UIButton) { + @objc private func pollButtonDidPressed(_ sender: Any) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) delegate?.composeToolbarView(self, pollButtonDidPressed: sender) } - @objc private func emojiButtonDidPressed(_ sender: UIButton) { + @objc private func emojiButtonDidPressed(_ sender: Any) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) delegate?.composeToolbarView(self, emojiButtonDidPressed: sender) } - @objc private func contentWarningButtonDidPressed(_ sender: UIButton) { + @objc private func contentWarningButtonDidPressed(_ sender: Any) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) delegate?.composeToolbarView(self, contentWarningButtonDidPressed: sender) }