command picker for drawing toolkit

This commit is contained in:
True Zhuanjia
2026-04-07 14:35:06 +08:00
parent 9cd72271ca
commit 84adf3ac95
9 changed files with 461 additions and 142 deletions
+78 -39
View File
@@ -283,6 +283,9 @@ struct WidgetPickerView: View {
private let initialShape: String?
private let availableTabs: [WidgetPickerTab]
private let preferredInitialTab: WidgetPickerTab?
private let keyboardPickerMode: VirtualKeyboardMode
private let shortcutPickerTipText: String?
private let shortcutIdentifier: String?
var onWidgetCreated: (([String: String]) -> Void)? = nil
var onCloseRequested: (() -> Void)? = nil
@@ -291,7 +294,7 @@ struct WidgetPickerView: View {
@SwiftUI.State private var selectedCmds: [String] = []
@SwiftUI.State private var poolItems: [WidgetPoolItem] = []
@SwiftUI.State private var resetToken: Int = 0
@SwiftUI.State private var tipMessage: String = SwiftLocalizationHelper.localizedString(forKey: "Tap any control to add it")
@SwiftUI.State private var tipMessage: String
@SwiftUI.State private var tipMessageType: PoolTipMessageType = .normal
@SwiftUI.State private var keyboardDeselectionCommand: String = ""
@SwiftUI.State private var keyboardDeselectionToken: Int = 0
@@ -316,6 +319,9 @@ struct WidgetPickerView: View {
initialShape: String? = nil,
availableTabs: [WidgetPickerTab] = WidgetPickerTab.allCases,
preferredInitialTab: WidgetPickerTab? = nil,
keyboardPickerMode: VirtualKeyboardMode = .picker,
shortcutPickerTipText: String? = nil,
shortcutIdentififier: String? = nil,
onWidgetCreated: (([String: String]) -> Void)? = nil,
onCloseRequested: (() -> Void)? = nil
) {
@@ -327,9 +333,17 @@ struct WidgetPickerView: View {
self.initialShape = initialShape
self.availableTabs = normalizedTabs
self.preferredInitialTab = resolvedInitialTab
self.keyboardPickerMode = keyboardPickerMode
self.shortcutPickerTipText = shortcutPickerTipText
self.shortcutIdentifier = shortcutIdentififier
self.onWidgetCreated = onWidgetCreated
self.onCloseRequested = onCloseRequested
_selectedTab = SwiftUI.State(initialValue: resolvedInitialTab ?? (normalizedTabs.contains(.keyboard) ? .keyboard : normalizedTabs[0]))
_tipMessage = SwiftUI.State(
initialValue: (keyboardPickerMode == .shortcutPicker && !(shortcutPickerTipText ?? "").isEmpty)
? (shortcutPickerTipText ?? "")
: SwiftLocalizationHelper.localizedString(forKey: "Tap any control to add it")
)
}
private let functionalButtonOptions: [FunctionalButtonOption] = [
@@ -487,7 +501,10 @@ struct WidgetPickerView: View {
]
private var defaultTipMessage: String {
SwiftLocalizationHelper.localizedString(forKey: "Tap any control to add it")
if isShortcutPickerMode, let shortcutPickerTipText, !shortcutPickerTipText.isEmpty {
return shortcutPickerTipText
}
return SwiftLocalizationHelper.localizedString(forKey: "Tap any control to add it")
}
private var tipMessageColor: Color {
@@ -500,6 +517,11 @@ struct WidgetPickerView: View {
}
private func setTipMessage(_ message: String, type: PoolTipMessageType = .normal) {
if isShortcutPickerMode, let shortcutPickerTipText, !shortcutPickerTipText.isEmpty {
tipMessage = shortcutPickerTipText
tipMessageType = .normal
return
}
tipMessage = message
tipMessageType = type
}
@@ -678,7 +700,7 @@ struct WidgetPickerView: View {
.padding(.vertical, pickerInsetGamepadVertical)
case .keyboard:
VirtualKeyboardView(
mode: .picker,
mode: keyboardPickerMode,
canSelectCommand: { canSelectCommand($0, source: .keyboard) },
isCommandSelected: { selectedCmds.contains($0) },
onCommandSelected: { appendCommand($0, source: .keyboard) },
@@ -852,44 +874,48 @@ struct WidgetPickerView: View {
.frame(maxWidth: poolGridWidth ?? .infinity, alignment: .center)
.frame(maxWidth: .infinity, alignment: .center)
if keyboardPickerMode != .shortcutPicker {
PoolActionChip(
title: SwiftLocalizationHelper.localizedString(forKey: "Gyro switch button"),
isPrimary: false,
height: poolChipHeight,
fontSize: poolChipFontSize,
cornerRadius: metrics.chipCornerRadius
) {
handleGyroButtonTap()
}
.overlay(
Group {
if selectedGyroCommand != nil {
RoundedRectangle(cornerRadius: 16, style: .continuous)
.stroke(Color.orange.opacity(0.75), lineWidth: 1.4)
.background(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(
LinearGradient(
gradient: Gradient(colors: [
Color(red: 1.00, green: 0.96, blue: 0.74).opacity(0.34),
Color(red: 0.95, green: 0.78, blue: 0.32).opacity(0.22)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
)
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
.allowsHitTesting(false)
}
title: SwiftLocalizationHelper.localizedString(forKey: "Gyro switch button"),
isPrimary: false,
height: poolChipHeight,
fontSize: poolChipFontSize,
cornerRadius: metrics.chipCornerRadius
) {
handleGyroButtonTap()
}
)
.overlay(
Group {
if selectedGyroCommand != nil {
RoundedRectangle(cornerRadius: 16, style: .continuous)
.stroke(Color.orange.opacity(0.75), lineWidth: 1.4)
.background(
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(
LinearGradient(
gradient: Gradient(colors: [
Color(red: 1.00, green: 0.96, blue: 0.74).opacity(0.34),
Color(red: 0.95, green: 0.78, blue: 0.32).opacity(0.22)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
)
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
.allowsHitTesting(false)
}
}
)
}
HStack(spacing: metrics.isPhone ? 8 : 12) {
PoolActionChip(
title: isEditMode
? WidgetPickerSubmissionAction.create.poolActionTitle
: SwiftLocalizationHelper.localizedString(forKey: "Create widget"),
title: isShortcutPickerMode
? SwiftLocalizationHelper.localizedString(forKey: "Create shortcut")
: (isEditMode
? WidgetPickerSubmissionAction.create.poolActionTitle
: SwiftLocalizationHelper.localizedString(forKey: "Create widget")),
isPrimary: true,
height: poolChipHeight,
fontSize: poolChipFontSize,
@@ -1662,7 +1688,15 @@ struct WidgetPickerView: View {
return "{\n \"cmdString\": \"\(payload["cmdString"] ?? "")\",\n \"buttonLabel\": \"\(payload["buttonLabel"] ?? "")\",\n \"shape\": \"\(payload["shape"] ?? "")\"\n}"
}
private var isShortcutPickerMode: Bool {
keyboardPickerMode == .shortcutPicker
}
private var shouldBypassCreateWidgetSheet: Bool {
if isShortcutPickerMode {
return true
}
guard !poolItems.isEmpty else { return false }
let hasVisibleConfigurationSection =
@@ -1724,7 +1758,7 @@ struct WidgetPickerView: View {
}
private func presentCreateWidgetSheet(for submissionAction: WidgetPickerSubmissionAction) {
guard !poolItems.isEmpty else {
guard isShortcutPickerMode || !poolItems.isEmpty else {
setTipMessage(SwiftLocalizationHelper.localizedString(forKey: "Select at least one command before creating a widget"), type: .error)
return
}
@@ -1740,7 +1774,7 @@ struct WidgetPickerView: View {
}
private func submitWidgetPayload() {
let payload = makeWidgetPayload()
var payload = makeWidgetPayload()
lastCreatedWidgetPayload = payload
setTipMessage(SwiftLocalizationHelper.localizedString(forKey: "Widget config generated"))
onWidgetCreated?(payload)
@@ -1753,11 +1787,16 @@ struct WidgetPickerView: View {
"cmdString": buildCmdString(),
"buttonLabel": targetWidgetKind == .button ? widgetButtonLabel : "",
"shape": targetWidgetKind == .button ? widgetShape.rawValue : "",
"pickerAction": pendingSubmissionAction.payloadValue
"pickerAction": pendingSubmissionAction.payloadValue,
"shortcutIdentifier": shortcutIdentifier ?? ""
]
}
private func buildCmdString() -> String {
if isShortcutPickerMode {
return selectedCmds.joined(separator: "+")
}
let joiner = effectiveWidgetComboMode == .shortcut && showsComboModeControl ? "+" : "-"
var cmdString = selectedCmds.joined(separator: joiner)