You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
8.6 KiB

import SwiftUI
// MARK: -
struct KeyboardToolbarView: View {
let onDone: () -> Void
let showDoneButton: Bool
let additionalButtons: [KeyboardToolbarButton]
init(
onDone: @escaping () -> Void = {},
showDoneButton: Bool = true,
additionalButtons: [KeyboardToolbarButton] = []
) {
self.onDone = onDone
self.showDoneButton = showDoneButton
self.additionalButtons = additionalButtons
}
var body: some View {
Group {
//
HStack(spacing: 12) {
ForEach(additionalButtons.filter { $0.position == .left }, id: \.id) { button in
Button(action: button.action) {
HStack(spacing: 4) {
if let icon = button.icon {
Image(systemName: icon)
.font(.system(size: 16, weight: .medium))
}
Text(button.title)
.font(.system(size: 16, weight: .medium))
}
.foregroundColor(button.color)
}
}
}
Spacer()
//
HStack(spacing: 12) {
ForEach(additionalButtons.filter { $0.position == .right }, id: \.id) { button in
Button(action: button.action) {
HStack(spacing: 4) {
if let icon = button.icon {
Image(systemName: icon)
.font(.system(size: 16, weight: .medium))
}
Text(button.title)
.font(.system(size: 16, weight: .medium))
}
.foregroundColor(button.color)
}
}
if showDoneButton {
Button(NSLocalizedString("done", comment: "Done"), action: onDone)
.foregroundColor(.blue)
.font(.system(size: 16, weight: .medium))
}
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
//
HStack(spacing: 12) {
ForEach(additionalButtons.filter { $0.position == .left }, id: \.id) { button in
Button(action: button.action) {
HStack(spacing: 4) {
if let icon = button.icon {
Image(systemName: icon)
.font(.system(size: 16, weight: .medium))
}
Text(button.title)
.font(.system(size: 16, weight: .medium))
}
.foregroundColor(button.color)
}
}
}
Spacer()
//
HStack(spacing: 12) {
ForEach(additionalButtons.filter { $0.position == .right }, id: \.id) { button in
Button(action: button.action) {
HStack(spacing: 4) {
if let icon = button.icon {
Image(systemName: icon)
.font(.system(size: 16, weight: .medium))
}
Text(button.title)
.font(.system(size: 16, weight: .medium))
}
.foregroundColor(button.color)
}
}
if showDoneButton {
Button(NSLocalizedString("done", comment: "Done"), action: onDone)
.foregroundColor(.blue)
.font(.system(size: 16, weight: .medium))
}
}
}
}
}
}
// MARK: -
struct KeyboardToolbarButton {
let id = UUID()
let title: String
let icon: String?
let color: Color
let position: ButtonPosition
let action: () -> Void
enum ButtonPosition {
case left, right
}
init(
title: String,
icon: String? = nil,
color: Color = .blue,
position: ButtonPosition = .right,
action: @escaping () -> Void
) {
self.title = title
self.icon = icon
self.color = color
self.position = position
self.action = action
}
}
// MARK: -
extension KeyboardToolbarButton {
static func clear(
text: Binding<String>,
position: ButtonPosition = .left
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: NSLocalizedString("clear", comment: "Clear"),
icon: "trash",
color: .red,
position: position
) {
text.wrappedValue = ""
}
}
static func copy(
text: String,
position: ButtonPosition = .left
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: NSLocalizedString("copy", comment: "Copy"),
icon: "doc.on.doc",
color: .blue,
position: position
) {
UIPasteboard.general.string = text
}
}
static func paste(
text: Binding<String>,
position: ButtonPosition = .left
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: NSLocalizedString("paste", comment: "Paste"),
icon: "doc.on.clipboard",
color: .green,
position: position
) {
if let pastedText = UIPasteboard.general.string {
text.wrappedValue = pastedText
}
}
}
static func next(
action: @escaping () -> Void,
position: ButtonPosition = .right
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: NSLocalizedString("next", comment: "Next"),
icon: "arrow.right",
color: .blue,
position: position,
action: action
)
}
static func previous(
action: @escaping () -> Void,
position: ButtonPosition = .left
) -> KeyboardToolbarButton {
KeyboardToolbarButton(
title: NSLocalizedString("previous", comment: "Previous"),
icon: "arrow.left",
color: .blue,
position: position,
action: action
)
}
}
// MARK: -
extension KeyboardToolbarView {
static func simple(onDone: @escaping () -> Void = {}) -> KeyboardToolbarView {
KeyboardToolbarView(onDone: onDone)
}
static func withClear(
text: Binding<String>,
onDone: @escaping () -> Void = {}
) -> KeyboardToolbarView {
KeyboardToolbarView(
onDone: onDone,
additionalButtons: [
.clear(text: text)
]
)
}
static func withCopyPaste(
text: Binding<String>,
onDone: @escaping () -> Void = {}
) -> KeyboardToolbarView {
KeyboardToolbarView(
onDone: onDone,
additionalButtons: [
.copy(text: text.wrappedValue),
.paste(text: text)
]
)
}
static func withNavigation(
onPrevious: @escaping () -> Void,
onNext: @escaping () -> Void,
onDone: @escaping () -> Void = {}
) -> KeyboardToolbarView {
KeyboardToolbarView(
onDone: onDone,
additionalButtons: [
.previous(action: onPrevious),
.next(action: onNext)
]
)
}
}
#Preview {
VStack(spacing: 16) {
Text(NSLocalizedString("simple_toolbar", comment: "Simple toolbar"))
.font(.headline)
Text(NSLocalizedString("toolbar_with_clear", comment: "Toolbar with clear button"))
.font(.headline)
Text(NSLocalizedString("toolbar_with_copy_paste", comment: "Toolbar with copy/paste"))
.font(.headline)
Text(NSLocalizedString("toolbar_with_navigation", comment: "Toolbar with navigation"))
.font(.headline)
}
.padding()
}