forked from shadowfacts/Tusker
101 lines
2.9 KiB
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"),
|
|
])
|
|
}
|
|
}
|