Tusker/Tusker/Views/MenuPicker.swift

101 lines
2.9 KiB
Swift

//
// MenuPicker.swift
// Tusker
//
// Created by Shadowfacts on 11/7/22.
// Copyright © 2022 Shadowfacts. All rights reserved.
//
import SwiftUI
struct MenuPicker<Value: Hashable>: UIViewRepresentable {
typealias UIViewType = UIButton
@Binding var selection: Value
let options: [Option]
var buttonStyle: ButtonStyle = .labelAndIcon
private var selectedOption: Option {
options.first(where: { $0.value == selection })!
}
func makeUIView(context: Context) -> UIButton {
let button = UIButton()
button.showsMenuAsPrimaryAction = true
button.setContentHuggingPriority(.required, for: .horizontal)
return button
}
func updateUIView(_ button: UIButton, context: Context) {
var config = UIButton.Configuration.borderless()
if #available(iOS 16.0, *) {
config.indicator = .popup
}
if buttonStyle.hasIcon {
config.image = selectedOption.image
}
if buttonStyle.hasLabel {
config.title = selectedOption.title
}
button.configuration = config
button.menu = UIMenu(children: options.map { opt in
let action = UIAction(title: opt.title, subtitle: opt.subtitle, image: opt.image, state: opt.value == selection ? .on : .off) { _ in
selection = opt.value
}
action.accessibilityLabel = opt.accessibilityLabel
return action
})
button.accessibilityLabel = selectedOption.accessibilityLabel ?? selectedOption.title
button.isPointerInteractionEnabled = buttonStyle == .iconOnly
}
struct Option {
let value: Value
let title: String
let subtitle: String?
let image: UIImage?
let accessibilityLabel: String?
init(value: Value, title: String, subtitle: String? = nil, image: UIImage? = nil, accessibilityLabel: String? = nil) {
self.value = value
self.title = title
self.subtitle = subtitle
self.image = image
self.accessibilityLabel = accessibilityLabel
}
}
enum ButtonStyle {
case labelAndIcon, labelOnly, iconOnly
var hasLabel: Bool {
switch self {
case .labelAndIcon, .labelOnly:
return true
default:
return false
}
}
var hasIcon: Bool {
switch self {
case .labelAndIcon, .iconOnly:
return true
default:
return false
}
}
}
}
struct MenuPicker_Previews: PreviewProvider {
@State static var value = 0
static var previews: some View {
MenuPicker(selection: $value, options: [
.init(value: 0, title: "Zero"),
.init(value: 1, title: "One"),
.init(value: 2, title: "Two"),
])
}
}