From 18c90acda54cb46815a081ecfc36ea8f2b9e93fd Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Mon, 29 Jun 2026 00:12:04 +0800
Subject: [PATCH] Fix custom hotkey settings UI for 8.2.1
---
src/Apptag/PreferencesView.swift | 170 ++++++++++++++++++++++++++++++++++++++------------------
1 files changed, 115 insertions(+), 55 deletions(-)
diff --git a/src/Apptag/PreferencesView.swift b/src/Apptag/PreferencesView.swift
index 41fec66..8838d3d 100644
--- a/src/Apptag/PreferencesView.swift
+++ b/src/Apptag/PreferencesView.swift
@@ -944,6 +944,7 @@
customizeTitle: proEntitlement.isUnlocked ? tr("hotkeys.customize") : tr("pro.card.badge"),
restoreTitle: tr("hotkeys.restoreDefault"),
isRecording: recordingHotkeyKind == .main,
+ isProLocked: !proEntitlement.isUnlocked,
canRestore: proEntitlement.isUnlocked && LauncherHotkeySettings.hasCustomHotkey(for: .main),
onCustomize: { startHotkeyRecording(for: .main) },
onRestore: { restoreDefaultHotkey(for: .main) }
@@ -966,6 +967,7 @@
customizeTitle: proEntitlement.isUnlocked ? tr("hotkeys.customize") : tr("pro.card.badge"),
restoreTitle: tr("hotkeys.restoreDefault"),
isRecording: recordingHotkeyKind == .quickSearch,
+ isProLocked: !proEntitlement.isUnlocked,
canRestore: proEntitlement.isUnlocked && LauncherHotkeySettings.hasCustomHotkey(for: .quickSearch),
onCustomize: { startHotkeyRecording(for: .quickSearch) },
onRestore: { restoreDefaultHotkey(for: .quickSearch) }
@@ -1728,32 +1730,27 @@
let statusTone: HotkeyStatusTone
var body: some View {
- VStack(alignment: .leading, spacing: 12) {
- HStack(alignment: .top, spacing: 12) {
- VStack(alignment: .leading, spacing: 3) {
- Text(title)
- .font(.system(size: 13, weight: .semibold))
- Text(description)
- .font(.caption)
- .foregroundStyle(.secondary)
- .fixedSize(horizontal: false, vertical: true)
- }
- .frame(maxWidth: .infinity, alignment: .leading)
-
- VStack(alignment: .leading, spacing: 4) {
- Text(displayText)
- .font(.system(size: 15, weight: .semibold))
- .lineLimit(1)
- .minimumScaleFactor(0.85)
- Text(statusText)
- .font(.system(size: 11, weight: .semibold))
- .foregroundStyle(statusTone.foreground)
- .padding(.horizontal, 8)
- .padding(.vertical, 3)
- .background(Capsule().fill(statusTone.background))
- }
- .frame(width: 180, alignment: .leading)
+ HStack(alignment: .center, spacing: 18) {
+ VStack(alignment: .leading, spacing: 3) {
+ Text(title)
+ .font(.system(size: 13, weight: .semibold))
+ Text(description)
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ .fixedSize(horizontal: false, vertical: true)
}
+ .frame(maxWidth: .infinity, alignment: .leading)
+
+ HStack(alignment: .center, spacing: 12) {
+ Text(displayText)
+ .font(.system(size: 15, weight: .semibold))
+ .lineLimit(1)
+ .minimumScaleFactor(0.85)
+ .frame(width: 156, alignment: .leading)
+
+ HotkeyStatusPill(text: statusText, tone: statusTone)
+ }
+ .frame(width: 310, alignment: .leading)
}
.padding(12)
.background(
@@ -1776,36 +1773,32 @@
let customizeTitle: String
let restoreTitle: String
let isRecording: Bool
+ let isProLocked: Bool
let canRestore: Bool
let onCustomize: () -> Void
let onRestore: () -> Void
var body: some View {
- VStack(alignment: .leading, spacing: 12) {
- HStack(alignment: .top, spacing: 12) {
- VStack(alignment: .leading, spacing: 3) {
- Text(title)
- .font(.system(size: 13, weight: .semibold))
- Text(description)
- .font(.caption)
- .foregroundStyle(.secondary)
- .fixedSize(horizontal: false, vertical: true)
- }
- .frame(maxWidth: .infinity, alignment: .leading)
+ HStack(alignment: .center, spacing: 18) {
+ VStack(alignment: .leading, spacing: 3) {
+ Text(title)
+ .font(.system(size: 13, weight: .semibold))
+ Text(description)
+ .font(.caption)
+ .foregroundStyle(.secondary)
+ .fixedSize(horizontal: false, vertical: true)
+ }
+ .frame(maxWidth: .infinity, alignment: .leading)
- VStack(alignment: .leading, spacing: 7) {
+ HStack(alignment: .center, spacing: 12) {
+ VStack(alignment: .leading, spacing: 6) {
Text(isRecording ? "…" : displayText)
.font(.system(size: 15, weight: .semibold))
.lineLimit(1)
.minimumScaleFactor(0.85)
HStack(spacing: 6) {
- Text(statusText)
- .font(.system(size: 11, weight: .semibold))
- .foregroundStyle(statusTone.foreground)
- .padding(.horizontal, 8)
- .padding(.vertical, 3)
- .background(Capsule().fill(statusTone.background))
+ HotkeyStatusPill(text: statusText, tone: statusTone)
if isRecording {
Text(tr("hotkeys.recordingInline"))
@@ -1813,20 +1806,23 @@
.foregroundStyle(.blue)
}
}
-
- HStack(spacing: 8) {
- Button(customizeTitle, action: onCustomize)
- .buttonStyle(.borderedProminent)
- .controlSize(.small)
-
- Button(restoreTitle, action: onRestore)
- .buttonStyle(.bordered)
- .controlSize(.small)
- .disabled(!canRestore)
- }
}
- .frame(width: 230, alignment: .leading)
+ .frame(width: 156, alignment: .leading)
+
+ HotkeyPrimaryActionButton(
+ title: customizeTitle,
+ isProLocked: isProLocked,
+ action: onCustomize
+ )
+
+ if canRestore {
+ HotkeySecondaryActionButton(
+ title: restoreTitle,
+ action: onRestore
+ )
+ }
}
+ .frame(width: 310, alignment: .leading)
}
.padding(12)
.background(
@@ -1840,6 +1836,70 @@
}
}
+private struct HotkeyStatusPill: View {
+ let text: String
+ let tone: HotkeyStatusTone
+
+ var body: some View {
+ Text(text)
+ .font(.system(size: 11, weight: .semibold))
+ .foregroundStyle(tone.foreground)
+ .lineLimit(1)
+ .padding(.horizontal, 8)
+ .padding(.vertical, 3)
+ .background(Capsule().fill(tone.background))
+ }
+}
+
+private struct HotkeyPrimaryActionButton: View {
+ let title: String
+ let isProLocked: Bool
+ let action: () -> Void
+
+ var body: some View {
+ Button(action: action) {
+ if isProLocked {
+ ProStatusPill(text: title, style: .locked, compact: true)
+ } else {
+ Text(title)
+ .font(.system(size: 11, weight: .semibold))
+ .foregroundStyle(Color.white)
+ .lineLimit(1)
+ .padding(.horizontal, 12)
+ .padding(.vertical, 6)
+ .background(
+ Capsule(style: .continuous)
+ .fill(Color.accentColor)
+ )
+ }
+ }
+ .buttonStyle(.plain)
+ .contentShape(Capsule(style: .continuous))
+ }
+}
+
+private struct HotkeySecondaryActionButton: View {
+ let title: String
+ let action: () -> Void
+
+ var body: some View {
+ Button(action: action) {
+ Text(title)
+ .font(.system(size: 11, weight: .semibold))
+ .foregroundStyle(.secondary)
+ .lineLimit(1)
+ .padding(.horizontal, 12)
+ .padding(.vertical, 6)
+ .background(
+ Capsule(style: .continuous)
+ .fill(Color.secondary.opacity(0.12))
+ )
+ }
+ .buttonStyle(.plain)
+ .contentShape(Capsule(style: .continuous))
+ }
+}
+
private struct SettingsConfirmationView: View {
let title: String
let message: String
--
Gitblit v1.9.3