feat: add state for visibility menu in compose scene

This commit is contained in:
CMK 2021-06-15 18:58:43 +08:00
parent 43b67a4cc3
commit 2669caeec2
2 changed files with 33 additions and 15 deletions

View File

@ -368,6 +368,7 @@ extension ComposeViewController {
guard let self = self else { return } guard let self = self else { return }
let image = type.image(interfaceStyle: self.traitCollection.userInterfaceStyle) let image = type.image(interfaceStyle: self.traitCollection.userInterfaceStyle)
self.composeToolbarView.visibilityButton.setImage(image, for: .normal) self.composeToolbarView.visibilityButton.setImage(image, for: .normal)
self.composeToolbarView.activeVisibilityType.value = type
} }
.store(in: &disposeBag) .store(in: &disposeBag)
@ -676,7 +677,7 @@ extension ComposeViewController: TextEditorViewTextAttributesDelegate {
updateAttributedString attributedString: NSAttributedString, updateAttributedString attributedString: NSAttributedString,
completion: @escaping (NSAttributedString?) -> Void completion: @escaping (NSAttributedString?) -> Void
) { ) {
// FIXME: needs O(1) update completion to fix profermance issue // FIXME: needs O(1) update completion to fix performance issue
DispatchQueue.global().async { DispatchQueue.global().async {
let string = attributedString.string let string = attributedString.string
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: update: %s", ((#file as NSString).lastPathComponent), #line, #function, string) os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: update: %s", ((#file as NSString).lastPathComponent), #line, #function, string)
@ -1291,7 +1292,8 @@ extension ComposeViewController {
case togglePoll case togglePoll
case toggleContentWarning case toggleContentWarning
case selectVisibilityPublic case selectVisibilityPublic
case selectVisibilityUnlisted // TODO: remove selectVisibilityUnlisted from codebase
// case selectVisibilityUnlisted
case selectVisibilityPrivate case selectVisibilityPrivate
case selectVisibilityDirect case selectVisibilityDirect
@ -1305,7 +1307,7 @@ extension ComposeViewController {
case .togglePoll: return L10n.Scene.Compose.Keyboard.togglePoll case .togglePoll: return L10n.Scene.Compose.Keyboard.togglePoll
case .toggleContentWarning: return L10n.Scene.Compose.Keyboard.toggleContentWarning case .toggleContentWarning: return L10n.Scene.Compose.Keyboard.toggleContentWarning
case .selectVisibilityPublic: return L10n.Scene.Compose.Keyboard.selectVisibilityEntry(L10n.Scene.Compose.Visibility.public) case .selectVisibilityPublic: return L10n.Scene.Compose.Keyboard.selectVisibilityEntry(L10n.Scene.Compose.Visibility.public)
case .selectVisibilityUnlisted: return L10n.Scene.Compose.Keyboard.selectVisibilityEntry(L10n.Scene.Compose.Visibility.unlisted) // case .selectVisibilityUnlisted: return L10n.Scene.Compose.Keyboard.selectVisibilityEntry(L10n.Scene.Compose.Visibility.unlisted)
case .selectVisibilityPrivate: return L10n.Scene.Compose.Keyboard.selectVisibilityEntry(L10n.Scene.Compose.Visibility.private) case .selectVisibilityPrivate: return L10n.Scene.Compose.Keyboard.selectVisibilityEntry(L10n.Scene.Compose.Visibility.private)
case .selectVisibilityDirect: return L10n.Scene.Compose.Keyboard.selectVisibilityEntry(L10n.Scene.Compose.Visibility.direct) case .selectVisibilityDirect: return L10n.Scene.Compose.Keyboard.selectVisibilityEntry(L10n.Scene.Compose.Visibility.direct)
} }
@ -1322,9 +1324,9 @@ extension ComposeViewController {
case .togglePoll: return "p" // + shift + command case .togglePoll: return "p" // + shift + command
case .toggleContentWarning: return "c" // + shift + command case .toggleContentWarning: return "c" // + shift + command
case .selectVisibilityPublic: return "1" // + command case .selectVisibilityPublic: return "1" // + command
case .selectVisibilityUnlisted: return "2" // + command // case .selectVisibilityUnlisted: return "2" // + command
case .selectVisibilityPrivate: return "3" // + command case .selectVisibilityPrivate: return "2" // + command
case .selectVisibilityDirect: return "4" // + command case .selectVisibilityDirect: return "3" // + command
} }
} }
@ -1338,7 +1340,7 @@ extension ComposeViewController {
case .togglePoll: return [.shift, .command] case .togglePoll: return [.shift, .command]
case .toggleContentWarning: return [.shift, .command] case .toggleContentWarning: return [.shift, .command]
case .selectVisibilityPublic: return [.command] case .selectVisibilityPublic: return [.command]
case .selectVisibilityUnlisted: return [.command] // case .selectVisibilityUnlisted: return [.command]
case .selectVisibilityPrivate: return [.command] case .selectVisibilityPrivate: return [.command]
case .selectVisibilityDirect: return [.command] case .selectVisibilityDirect: return [.command]
} }
@ -1390,8 +1392,8 @@ extension ComposeViewController {
composeToolbarView.contentWarningButton.sendActions(for: .touchUpInside) composeToolbarView.contentWarningButton.sendActions(for: .touchUpInside)
case .selectVisibilityPublic: case .selectVisibilityPublic:
viewModel.selectedStatusVisibility.value = .public viewModel.selectedStatusVisibility.value = .public
case .selectVisibilityUnlisted: // case .selectVisibilityUnlisted:
viewModel.selectedStatusVisibility.value = .unlisted // viewModel.selectedStatusVisibility.value = .unlisted
case .selectVisibilityPrivate: case .selectVisibilityPrivate:
viewModel.selectedStatusVisibility.value = .private viewModel.selectedStatusVisibility.value = .private
case .selectVisibilityDirect: case .selectVisibilityDirect:

View File

@ -7,6 +7,7 @@
import os.log import os.log
import UIKit import UIKit
import Combine
import MastodonSDK import MastodonSDK
protocol ComposeToolbarViewDelegate: AnyObject { protocol ComposeToolbarViewDelegate: AnyObject {
@ -19,6 +20,8 @@ protocol ComposeToolbarViewDelegate: AnyObject {
final class ComposeToolbarView: UIView { final class ComposeToolbarView: UIView {
var disposeBag = Set<AnyCancellable>()
static let toolbarButtonSize: CGSize = CGSize(width: 44, height: 44) static let toolbarButtonSize: CGSize = CGSize(width: 44, height: 44)
static let toolbarHeight: CGFloat = 44 static let toolbarHeight: CGFloat = 44
@ -76,6 +79,8 @@ final class ComposeToolbarView: UIView {
return label return label
}() }()
let activeVisibilityType = CurrentValueSubject<VisibilitySelectionType, Never>(.public)
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
_init() _init()
@ -142,6 +147,15 @@ extension ComposeToolbarView {
visibilityButton.showsMenuAsPrimaryAction = true visibilityButton.showsMenuAsPrimaryAction = true
updateToolbarButtonUserInterfaceStyle() updateToolbarButtonUserInterfaceStyle()
// update menu when selected visibility type changed
activeVisibilityType
.receive(on: RunLoop.main)
.sink { [weak self] type in
guard let self = self else { return }
self.visibilityButton.menu = self.createVisibilityContextMenu(interfaceStyle: self.traitCollection.userInterfaceStyle)
}
.store(in: &disposeBag)
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
@ -161,14 +175,15 @@ extension ComposeToolbarView {
enum VisibilitySelectionType: String, CaseIterable { enum VisibilitySelectionType: String, CaseIterable {
case `public` case `public`
case unlisted // TODO: remove unlisted option from codebase
// case unlisted
case `private` case `private`
case direct case direct
var title: String { var title: String {
switch self { switch self {
case .public: return L10n.Scene.Compose.Visibility.public case .public: return L10n.Scene.Compose.Visibility.public
case .unlisted: return L10n.Scene.Compose.Visibility.unlisted // case .unlisted: return L10n.Scene.Compose.Visibility.unlisted
case .private: return L10n.Scene.Compose.Visibility.private case .private: return L10n.Scene.Compose.Visibility.private
case .direct: return L10n.Scene.Compose.Visibility.direct case .direct: return L10n.Scene.Compose.Visibility.direct
} }
@ -181,7 +196,7 @@ extension ComposeToolbarView {
case .light: return UIImage(systemName: "person.3", withConfiguration: UIImage.SymbolConfiguration(pointSize: 15, weight: .medium))! case .light: return UIImage(systemName: "person.3", withConfiguration: UIImage.SymbolConfiguration(pointSize: 15, weight: .medium))!
default: return UIImage(systemName: "person.3.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 15, weight: .medium))! default: return UIImage(systemName: "person.3.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 15, weight: .medium))!
} }
case .unlisted: return UIImage(systemName: "eye.slash", withConfiguration: UIImage.SymbolConfiguration(pointSize: 18, weight: .regular))! // case .unlisted: return UIImage(systemName: "eye.slash", withConfiguration: UIImage.SymbolConfiguration(pointSize: 18, weight: .regular))!
case .private: return UIImage(systemName: "person.crop.circle.badge.plus", withConfiguration: UIImage.SymbolConfiguration(pointSize: 18, weight: .regular))! case .private: return UIImage(systemName: "person.crop.circle.badge.plus", withConfiguration: UIImage.SymbolConfiguration(pointSize: 18, weight: .regular))!
case .direct: return UIImage(systemName: "at", withConfiguration: UIImage.SymbolConfiguration(pointSize: 19, weight: .regular))! case .direct: return UIImage(systemName: "at", withConfiguration: UIImage.SymbolConfiguration(pointSize: 19, weight: .regular))!
} }
@ -190,7 +205,7 @@ extension ComposeToolbarView {
func imageNameForTimeline() -> String { func imageNameForTimeline() -> String {
switch self { switch self {
case .public: return "person.3" case .public: return "person.3"
case .unlisted: return "eye.slash" // case .unlisted: return "eye.slash"
case .private: return "person.crop.circle.badge.plus" case .private: return "person.crop.circle.badge.plus"
case .direct: return "at" case .direct: return "at"
} }
@ -199,7 +214,7 @@ extension ComposeToolbarView {
var visibility: Mastodon.Entity.Status.Visibility { var visibility: Mastodon.Entity.Status.Visibility {
switch self { switch self {
case .public: return .public case .public: return .public
case .unlisted: return .unlisted // case .unlisted: return .unlisted
case .private: return .private case .private: return .private
case .direct: return .direct case .direct: return .direct
} }
@ -268,7 +283,8 @@ extension ComposeToolbarView {
private func createVisibilityContextMenu(interfaceStyle: UIUserInterfaceStyle) -> UIMenu { private func createVisibilityContextMenu(interfaceStyle: UIUserInterfaceStyle) -> UIMenu {
let children: [UIMenuElement] = VisibilitySelectionType.allCases.map { type in let children: [UIMenuElement] = VisibilitySelectionType.allCases.map { type in
UIAction(title: type.title, image: type.image(interfaceStyle: interfaceStyle), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] action in let state: UIMenuElement.State = activeVisibilityType.value == type ? .on : .off
return UIAction(title: type.title, image: type.image(interfaceStyle: interfaceStyle), identifier: nil, discoverabilityTitle: nil, attributes: [], state: state) { [weak self] action in
guard let self = self else { return } guard let self = self else { return }
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: visibilitySelectionType: %s", ((#file as NSString).lastPathComponent), #line, #function, type.rawValue) os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: visibilitySelectionType: %s", ((#file as NSString).lastPathComponent), #line, #function, type.rawValue)
self.delegate?.composeToolbarView(self, visibilityButtonDidPressed: self.visibilityButton, visibilitySelectionType: type) self.delegate?.composeToolbarView(self, visibilityButtonDidPressed: self.visibilityButton, visibilitySelectionType: type)