Add reblog with visibility menu to reblog confirmation alert
This commit is contained in:
parent
7161861d36
commit
ca8a214cf6
|
@ -39,7 +39,11 @@ struct InstanceFeatures {
|
||||||
}
|
}
|
||||||
|
|
||||||
var trendingStatusesAndLinks: Bool {
|
var trendingStatusesAndLinks: Bool {
|
||||||
instanceType == .mastodon && version != nil && version! >= Version(3, 5, 0)
|
instanceType == .mastodon && hasVersion(3, 5, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var reblogVisibility: Bool {
|
||||||
|
instanceType == .mastodon && hasVersion(2, 8, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func update(instance: Instance, nodeInfo: NodeInfo?) {
|
mutating func update(instance: Instance, nodeInfo: NodeInfo?) {
|
||||||
|
@ -60,6 +64,14 @@ struct InstanceFeatures {
|
||||||
|
|
||||||
maxStatusChars = instance.maxStatusCharacters ?? 500
|
maxStatusChars = instance.maxStatusCharacters ?? 500
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasVersion(_ major: Int, _ minor: Int, _ patch: Int) -> Bool {
|
||||||
|
if let version {
|
||||||
|
return version >= Version(major, minor, patch)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension InstanceFeatures {
|
extension InstanceFeatures {
|
||||||
|
|
|
@ -15,7 +15,6 @@ class CustomAlertController: UIViewController {
|
||||||
fileprivate var dimmingView: UIView!
|
fileprivate var dimmingView: UIView!
|
||||||
fileprivate var buttonsStack: UIStackView!
|
fileprivate var buttonsStack: UIStackView!
|
||||||
fileprivate var actionsView: CustomAlertActionsView!
|
fileprivate var actionsView: CustomAlertActionsView!
|
||||||
private var separatorHeightConstraint: NSLayoutConstraint!
|
|
||||||
|
|
||||||
init(config: Configuration) {
|
init(config: Configuration) {
|
||||||
self.config = config
|
self.config = config
|
||||||
|
@ -88,12 +87,12 @@ class CustomAlertController: UIViewController {
|
||||||
stack.addSpacer(length: 16)
|
stack.addSpacer(length: 16)
|
||||||
|
|
||||||
let separator = UIView()
|
let separator = UIView()
|
||||||
|
separator.tag = ViewTags.customAlertSeparator
|
||||||
separator.backgroundColor = .separator
|
separator.backgroundColor = .separator
|
||||||
stack.addArrangedSubview(separator)
|
stack.addArrangedSubview(separator)
|
||||||
separatorHeightConstraint = separator.heightAnchor.constraint(equalToConstant: 0.5)
|
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
separator.widthAnchor.constraint(equalTo: stack.widthAnchor),
|
separator.widthAnchor.constraint(equalTo: stack.widthAnchor),
|
||||||
separatorHeightConstraint,
|
separator.heightAnchor.constraint(equalToConstant: 0.5),
|
||||||
])
|
])
|
||||||
|
|
||||||
actionsView = CustomAlertActionsView(config: config, dismiss: { [unowned self] in
|
actionsView = CustomAlertActionsView(config: config, dismiss: { [unowned self] in
|
||||||
|
@ -105,12 +104,6 @@ class CustomAlertController: UIViewController {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillLayoutSubviews() {
|
|
||||||
super.viewWillLayoutSubviews()
|
|
||||||
|
|
||||||
separatorHeightConstraint.constant = 1 / view.window!.screen.scale
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Configuration {
|
struct Configuration {
|
||||||
var title: String
|
var title: String
|
||||||
var content: UIView
|
var content: UIView
|
||||||
|
@ -118,9 +111,29 @@ class CustomAlertController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Action {
|
struct Action {
|
||||||
let title: String
|
var title: String?
|
||||||
let style: UIAlertAction.Style
|
var image: UIImage?
|
||||||
let handler: (() -> Void)?
|
var style: Style
|
||||||
|
var handler: (() -> Void)?
|
||||||
|
var isSecondaryMenu: Bool = false
|
||||||
|
|
||||||
|
init(title: String?, image: UIImage? = nil, style: Style, handler: (() -> Void)?) {
|
||||||
|
self.title = title
|
||||||
|
self.image = image
|
||||||
|
self.style = style
|
||||||
|
self.handler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Style {
|
||||||
|
case `default`, cancel, destructive, menu([MenuAction])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MenuAction {
|
||||||
|
var title: String
|
||||||
|
var subtitle: String?
|
||||||
|
var image: UIImage?
|
||||||
|
var handler: () -> Void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,8 +141,7 @@ class CustomAlertActionsView: UIControl {
|
||||||
private let dismiss: () -> Void
|
private let dismiss: () -> Void
|
||||||
|
|
||||||
private let stack = UIStackView()
|
private let stack = UIStackView()
|
||||||
private var labels: [UIView] = []
|
private var actionButtons: [CustomAlertActionButton] = []
|
||||||
private var labelWrappers: [UIView] = []
|
|
||||||
private var labelWrapperWidthConstraints: [NSLayoutConstraint] = []
|
private var labelWrapperWidthConstraints: [NSLayoutConstraint] = []
|
||||||
// the actions from the config but reordered to match labelWrappers order
|
// the actions from the config but reordered to match labelWrappers order
|
||||||
private var reorderedActions: [CustomAlertController.Action] = []
|
private var reorderedActions: [CustomAlertController.Action] = []
|
||||||
|
@ -155,57 +167,56 @@ class CustomAlertActionsView: UIControl {
|
||||||
])
|
])
|
||||||
|
|
||||||
for action in config.actions {
|
for action in config.actions {
|
||||||
let labelWrapper = UIView()
|
let button = CustomAlertActionButton(action: action, dismiss: dismiss)
|
||||||
labelWrapper.isAccessibilityElement = true
|
|
||||||
labelWrapper.accessibilityTraits = .button
|
|
||||||
labelWrapper.accessibilityRespondsToUserInteraction = true
|
|
||||||
labelWrapper.accessibilityLabel = action.title
|
|
||||||
|
|
||||||
let label = UILabel()
|
button.isAccessibilityElement = true
|
||||||
labels.append(label)
|
button.accessibilityTraits = .button
|
||||||
label.text = action.title
|
button.accessibilityRespondsToUserInteraction = true
|
||||||
label.textColor = .tintColor
|
button.accessibilityLabel = action.title
|
||||||
switch action.style {
|
|
||||||
case .cancel:
|
if action.isSecondaryMenu {
|
||||||
label.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).withSymbolicTraits(.traitBold)!, size: 0)
|
button.widthAnchor.constraint(greaterThanOrEqualToConstant: 44).isActive = true
|
||||||
case .destructive:
|
|
||||||
label.textColor = .systemRed
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
label.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
labelWrapper.addSubview(label)
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
label.leadingAnchor.constraint(greaterThanOrEqualTo: labelWrapper.leadingAnchor, constant: 4),
|
|
||||||
label.trailingAnchor.constraint(lessThanOrEqualTo: labelWrapper.trailingAnchor, constant: -4),
|
|
||||||
label.centerXAnchor.constraint(equalTo: labelWrapper.centerXAnchor),
|
|
||||||
label.centerYAnchor.constraint(equalTo: labelWrapper.centerYAnchor),
|
|
||||||
labelWrapper.heightAnchor.constraint(equalToConstant: 44),
|
|
||||||
])
|
|
||||||
|
|
||||||
if action.style == .cancel {
|
if case .cancel = action.style {
|
||||||
labelWrappers.insert(labelWrapper, at: 0)
|
actionButtons.insert(button, at: 0)
|
||||||
reorderedActions.insert(action, at: 0)
|
reorderedActions.insert(action, at: 0)
|
||||||
} else {
|
} else {
|
||||||
labelWrappers.append(labelWrapper)
|
actionButtons.append(button)
|
||||||
reorderedActions.append(action)
|
reorderedActions.append(action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var first = true
|
var first = true
|
||||||
for wrapper in labelWrappers {
|
for (action, button) in zip(reorderedActions, actionButtons) {
|
||||||
if first {
|
if first {
|
||||||
first = false
|
first = false
|
||||||
} else {
|
} else if !action.isSecondaryMenu {
|
||||||
let separator = UIView()
|
let separator = UIView()
|
||||||
|
separator.tag = ViewTags.customAlertSeparator
|
||||||
separator.backgroundColor = .separator
|
separator.backgroundColor = .separator
|
||||||
stack.addArrangedSubview(separator)
|
stack.addArrangedSubview(separator)
|
||||||
separators.append(separator)
|
separators.append(separator)
|
||||||
}
|
}
|
||||||
stack.addArrangedSubview(wrapper)
|
if action.isSecondaryMenu {
|
||||||
|
// prev button
|
||||||
|
let prev = stack.arrangedSubviews.last!
|
||||||
|
stack.removeArrangedSubview(prev)
|
||||||
|
let separator = UIView()
|
||||||
|
separator.tag = ViewTags.customAlertSeparator
|
||||||
|
separator.backgroundColor = .separator
|
||||||
|
separator.widthAnchor.constraint(equalToConstant: 0.5).isActive = true
|
||||||
|
let hStack = UIStackView(arrangedSubviews: [prev, separator, button])
|
||||||
|
hStack.axis = .horizontal
|
||||||
|
stack.addArrangedSubview(hStack)
|
||||||
|
} else {
|
||||||
|
stack.addArrangedSubview(button)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(panRecognized)))
|
||||||
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
@ -215,8 +226,33 @@ class CustomAlertActionsView: UIControl {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var menuActionsCount: Int {
|
||||||
|
var count = 0
|
||||||
|
for action in reorderedActions {
|
||||||
|
if case .menu(_) = action.style {
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
private var needsVertical: Bool {
|
||||||
|
if reorderedActions.count - menuActionsCount > 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var requiredWidth: CGFloat = 0
|
||||||
|
for (index, action) in actionButtons.enumerated() {
|
||||||
|
if index > 0 {
|
||||||
|
requiredWidth += 0.5
|
||||||
|
}
|
||||||
|
requiredWidth += action.titleView.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize).width
|
||||||
|
requiredWidth += 8
|
||||||
|
}
|
||||||
|
return requiredWidth > bounds.width
|
||||||
|
}
|
||||||
|
|
||||||
private func updateAxis() {
|
private func updateAxis() {
|
||||||
if reorderedActions.count > 2 || labels.map({ $0.intrinsicContentSize.width }).contains(where: { $0 > (bounds.width - 16) / 2 }) {
|
if needsVertical {
|
||||||
stack.axis = .vertical
|
stack.axis = .vertical
|
||||||
NSLayoutConstraint.deactivate(labelWrapperWidthConstraints)
|
NSLayoutConstraint.deactivate(labelWrapperWidthConstraints)
|
||||||
labelWrapperWidthConstraints = []
|
labelWrapperWidthConstraints = []
|
||||||
|
@ -227,8 +263,19 @@ class CustomAlertActionsView: UIControl {
|
||||||
NSLayoutConstraint.activate(separatorSizeConstraints)
|
NSLayoutConstraint.activate(separatorSizeConstraints)
|
||||||
} else {
|
} else {
|
||||||
stack.axis = .horizontal
|
stack.axis = .horizontal
|
||||||
labelWrapperWidthConstraints = labelWrappers.map {
|
labelWrapperWidthConstraints = []
|
||||||
$0.widthAnchor.constraint(equalToConstant: (bounds.width - 0.5) / 2)
|
var nonMenuAction: CustomAlertActionButton?
|
||||||
|
for (index, action) in reorderedActions.enumerated() {
|
||||||
|
if case .menu(_) = action.style {
|
||||||
|
} else {
|
||||||
|
if let nonMenuAction {
|
||||||
|
labelWrapperWidthConstraints.append(
|
||||||
|
actionButtons[index].widthAnchor.constraint(equalTo: nonMenuAction.widthAnchor)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
nonMenuAction = actionButtons[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
NSLayoutConstraint.activate(labelWrapperWidthConstraints)
|
NSLayoutConstraint.activate(labelWrapperWidthConstraints)
|
||||||
NSLayoutConstraint.deactivate(separatorSizeConstraints)
|
NSLayoutConstraint.deactivate(separatorSizeConstraints)
|
||||||
|
@ -239,73 +286,166 @@ class CustomAlertActionsView: UIControl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - UIControl
|
@objc private func panRecognized(_ recognizer: UIPanGestureRecognizer) {
|
||||||
|
let selectedButton = actionButtons.enumerated().first {
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
$0.1.point(inside: recognizer.location(in: $0.1), with: nil)
|
||||||
// we want this view to handle all touches inside it
|
|
||||||
return self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
|
switch recognizer.state {
|
||||||
for (index, labelWrapper) in labelWrappers.enumerated() {
|
case .began:
|
||||||
if labelWrapper.point(inside: touch.location(in: labelWrapper), with: event) {
|
currentSelectedActionIndex = selectedButton?.offset
|
||||||
currentSelectedActionIndex = index
|
selectedButton?.element.backgroundColor = .secondarySystemFill
|
||||||
labelWrapper.backgroundColor = .secondarySystemFill
|
|
||||||
|
|
||||||
generator.prepare()
|
generator.prepare()
|
||||||
|
|
||||||
return true
|
case .changed:
|
||||||
}
|
if selectedButton == nil && hitTest(recognizer.location(in: self), with: nil)?.tag == ViewTags.customAlertSeparator {
|
||||||
}
|
break
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
|
if selectedButton?.offset != currentSelectedActionIndex {
|
||||||
for (index, labelWrapper) in labelWrappers.enumerated() {
|
|
||||||
if labelWrapper.point(inside: touch.location(in: labelWrapper), with: event) {
|
|
||||||
if index != currentSelectedActionIndex {
|
|
||||||
if let currentSelectedActionIndex {
|
if let currentSelectedActionIndex {
|
||||||
labelWrappers[currentSelectedActionIndex].backgroundColor = nil
|
actionButtons[currentSelectedActionIndex].backgroundColor = nil
|
||||||
}
|
}
|
||||||
generator.selectionChanged()
|
generator.selectionChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSelectedActionIndex = index
|
currentSelectedActionIndex = selectedButton?.offset
|
||||||
labelWrapper.backgroundColor = .secondarySystemFill
|
selectedButton?.element.backgroundColor = .secondarySystemFill
|
||||||
|
|
||||||
generator.prepare()
|
generator.prepare()
|
||||||
|
|
||||||
return true
|
case .ended:
|
||||||
}
|
|
||||||
}
|
|
||||||
// didn't hit any button
|
|
||||||
if let currentSelectedActionIndex {
|
if let currentSelectedActionIndex {
|
||||||
labelWrappers[currentSelectedActionIndex].backgroundColor = nil
|
let button = actionButtons[currentSelectedActionIndex]
|
||||||
self.currentSelectedActionIndex = nil
|
button.backgroundColor = nil
|
||||||
|
let action = reorderedActions[currentSelectedActionIndex]
|
||||||
|
if action.handler == nil,
|
||||||
|
case .menu(_) = action.style,
|
||||||
|
let interaction = button.contextMenuInteraction {
|
||||||
|
let selector = NSSelectorFromString(["Location:", "At", "Menu", "present", "_"].reversed().joined())
|
||||||
|
if interaction.responds(to: selector) {
|
||||||
|
interaction.perform(selector, with: recognizer.location(in: button))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
action.handler?()
|
||||||
|
self.dismiss()
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
|
default:
|
||||||
super.endTracking(touch, with: event)
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let currentSelectedActionIndex {
|
class CustomAlertActionButton: UIControl {
|
||||||
labelWrappers[currentSelectedActionIndex].backgroundColor = nil
|
private let action: CustomAlertController.Action
|
||||||
reorderedActions[currentSelectedActionIndex].handler?()
|
private let dismiss: () -> Void
|
||||||
|
|
||||||
|
var titleView = UIStackView()
|
||||||
|
|
||||||
|
init(action: CustomAlertController.Action, dismiss: @escaping () -> Void) {
|
||||||
|
precondition(action.title != nil || action.image != nil, "action must have image and/or title")
|
||||||
|
|
||||||
|
self.action = action
|
||||||
|
self.dismiss = dismiss
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
titleView = UIStackView()
|
||||||
|
titleView.axis = .horizontal
|
||||||
|
titleView.spacing = 4
|
||||||
|
|
||||||
|
if let title = action.title {
|
||||||
|
let label = UILabel()
|
||||||
|
label.text = title
|
||||||
|
label.textColor = .tintColor
|
||||||
|
switch action.style {
|
||||||
|
case .cancel:
|
||||||
|
label.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).withSymbolicTraits(.traitBold)!, size: 0)
|
||||||
|
case .destructive:
|
||||||
|
label.textColor = .systemRed
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
titleView.addArrangedSubview(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let image = action.image {
|
||||||
|
let imageView = UIImageView(image: image)
|
||||||
|
titleView.addArrangedSubview(imageView)
|
||||||
|
}
|
||||||
|
|
||||||
|
titleView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
addSubview(titleView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
titleView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor, constant: 4),
|
||||||
|
titleView.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor, constant: -4),
|
||||||
|
titleView.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||||
|
titleView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||||
|
heightAnchor.constraint(equalToConstant: 44),
|
||||||
|
])
|
||||||
|
|
||||||
|
if case .menu(_) = action.style {
|
||||||
|
self.isContextMenuInteractionEnabled = true
|
||||||
|
self.showsMenuAsPrimaryAction = action.handler == nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
|
||||||
|
guard case .menu(let menuActions) = action.style else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return UIContextMenuConfiguration(actionProvider: { _ in
|
||||||
|
return UIMenu(children: menuActions.map { action in
|
||||||
|
UIAction(title: action.title, subtitle: action.subtitle, image: action.image) { [unowned self] _ in
|
||||||
|
action.handler()
|
||||||
|
self.dismiss()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willDisplayMenuFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
|
||||||
|
super.contextMenuInteraction(interaction, willDisplayMenuFor: configuration, animator: animator)
|
||||||
|
if let animator {
|
||||||
|
animator.addAnimations {
|
||||||
|
self.backgroundColor = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
backgroundColor = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
|
||||||
|
super.contextMenuInteraction(interaction, willEndFor: configuration, animator: animator)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||||
|
super.touchesBegan(touches, with: event)
|
||||||
|
|
||||||
|
if point(inside: touches.first!.location(in: self), with: event) {
|
||||||
|
backgroundColor = .secondarySystemFill
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||||
|
super.touchesMoved(touches, with: event)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||||
|
super.touchesEnded(touches, with: event)
|
||||||
|
backgroundColor = nil
|
||||||
|
action.handler?()
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func cancelTracking(with event: UIEvent?) {
|
|
||||||
super.cancelTracking(with: event)
|
|
||||||
|
|
||||||
if let currentSelectedActionIndex {
|
|
||||||
labelWrappers[currentSelectedActionIndex].backgroundColor = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension CustomAlertController {
|
extension CustomAlertController {
|
||||||
override func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
override func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||||
return CustomAlertPresentationAnimation()
|
return CustomAlertPresentationAnimation()
|
||||||
|
|
|
@ -17,4 +17,5 @@ struct ViewTags {
|
||||||
static let navForwardBarButton = 42004
|
static let navForwardBarButton = 42004
|
||||||
static let navEmptyTitleView = 42005
|
static let navEmptyTitleView = 42005
|
||||||
static let splitNavCloseSecondaryButton = 42006
|
static let splitNavCloseSecondaryButton = 42006
|
||||||
|
static let customAlertSeparator = 42007
|
||||||
}
|
}
|
||||||
|
|
|
@ -412,13 +412,32 @@ class BaseStatusTableViewCell: UITableViewCell {
|
||||||
// if we are about to reblog and the user has confirmation enabled
|
// if we are about to reblog and the user has confirmation enabled
|
||||||
if !reblogged,
|
if !reblogged,
|
||||||
Preferences.shared.confirmBeforeReblog {
|
Preferences.shared.confirmBeforeReblog {
|
||||||
|
let image: UIImage?
|
||||||
|
let reblogVisibilityActions: [CustomAlertController.MenuAction]?
|
||||||
|
if mastodonController.instanceFeatures.reblogVisibility {
|
||||||
|
image = UIImage(systemName: Status.Visibility.public.unfilledImageName)
|
||||||
|
reblogVisibilityActions = [Status.Visibility.unlisted, .private].map { visibility in
|
||||||
|
CustomAlertController.MenuAction(title: "Reblog as \(visibility.displayName)", subtitle: visibility.subtitle, image: UIImage(systemName: visibility.unfilledImageName)) { [unowned self] in
|
||||||
|
self.toggleReblogInternal(visibility: visibility)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
image = nil
|
||||||
|
reblogVisibilityActions = nil
|
||||||
|
}
|
||||||
|
|
||||||
let preview = ConfirmReblogStatusPreviewView(status: status)
|
let preview = ConfirmReblogStatusPreviewView(status: status)
|
||||||
let config = CustomAlertController.Configuration(title: "Are you sure you want to reblog this post?", content: preview, actions: [
|
var config = CustomAlertController.Configuration(title: "Are you sure you want to reblog this post?", content: preview, actions: [
|
||||||
CustomAlertController.Action(title: "Cancel", style: .cancel, handler: nil),
|
CustomAlertController.Action(title: "Cancel", style: .cancel, handler: nil),
|
||||||
CustomAlertController.Action(title: "Reblog", style: .default, handler: { [unowned self] in
|
CustomAlertController.Action(title: "Reblog", image: image, style: .default, handler: { [unowned self] in
|
||||||
self.toggleReblogInternal(visibility: nil)
|
self.toggleReblogInternal(visibility: nil)
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
if let reblogVisibilityActions {
|
||||||
|
var menuAction = CustomAlertController.Action(title: nil, image: UIImage(systemName: "chevron.down"), style: .menu(reblogVisibilityActions), handler: nil)
|
||||||
|
menuAction.isSecondaryMenu = true
|
||||||
|
config.actions.append(menuAction)
|
||||||
|
}
|
||||||
let alert = CustomAlertController(config: config)
|
let alert = CustomAlertController(config: config)
|
||||||
delegate?.present(alert, animated: true)
|
delegate?.present(alert, animated: true)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue