Freeze prep TagLauncher 8.2.9 Pro status UI
| | |
| | | - `src/Apptag/PreferencesView.swift` |
| | | - `PreferencesView`:设置窗口、语言、通用、主题、快捷键、标签、数据、Pro、关于等设置页。 |
| | | - 顶部设置页签必须保持 8 个标签总宽不超过旧 7 标签宽度;图标统一使用线型 SF Symbols,`Pro` 页签位于数据之后、关于之前,使用线型皇冠。 |
| | | - 设置页签下方按页签渲染统一固定位置的 `settingsFixedProHeader`:通用 / 主题 / 快捷键 / 标签 / 数据 / Pro 页显示该行且位置不漂移;语言和关于页不显示该 Pro 引导行。免费态显示当前 tab 对应购买引导和解锁/恢复按钮;Pro 已解锁态只显示权益状态说明,不显示恢复购买按钮。 |
| | | - 设置页签下方按页签渲染统一固定位置的 `settingsFixedProHeader`:语言 / 通用 / 主题 / 快捷键 / 标签 / 数据 / Pro / 关于 8 个页签都显示该行且位置不漂移。免费态左侧状态用“当前免费版用户”完整句而不是“免费版”胶囊;通用 / 主题 / 快捷键 / 标签 / 数据页显示当前 tab 对应购买引导和解锁/恢复按钮,语言和关于页只显示状态与操作按钮,不显示购买说明文字;已解锁 Pro 时,语言 / Pro / 关于页统一居中显示 `Pro 已解锁` 胶囊加 `settings.proStatus.proUser` 文案,不显示恢复购买按钮,且 `settings.proStatus.proUser` 本地化文字不再内置皇冠图标。 |
| | | - Pro 专属主题、彩色容器 / 彩色网格、自定义快捷键、自定义标签颜色和数据导入导出入口即使已解锁,也应保留皇冠 Pro 标识。 |
| | | - Language tab 去掉重复标题说明,语言矩阵在主内容区域上下左右居中;About tab 应用信息块也在主内容区域居中。 |
| | | - Theme tab 只写视觉偏好 `appGridThemeID` 和炫彩主题调色值,炫彩滑轨只能影响 AppGrid 背景,不得改变标签、排序、备注或分类数据。 |
| | | - 免费用户预览 Pro 主题时,Theme tab 状态行和当前预览主题卡片显示基于 `ProThemePreviewState.endsAt` 推导的 `MM:SS` 倒计时;倒计时到期只退出预览,不弹阻塞提示。 |
| | | - Pro tab 展示免费版 / Pro 版对比表;对比表不显示独立标题,Pro 列标题前必须有线型皇冠标识。 |
| | | - Pro tab 对比表包含自定义标签颜色、彩色容器 / 彩色网格、高级主题、自定义快捷键、自定义应用备注和数据导入导出 / 分类与布局备份恢复;免费列锁定功能显示“不可用”,彩色容器 / 彩色网格和高级主题显示“只可预览 5 分钟”,备注显示“免费 3 个”;Pro 列未购买时显示带勾的“支持”,备注行显示带勾的“无限备注”,已购买后功能行显示带勾的“已解锁”。表格内所有状态胶囊使用与“免费 3 个”一致的中性样式,不显示皇冠图标或黄色 Pro 背景。 |
| | | - About tab 只保留应用信息、帮助文档和联系信息,不放 Pro 汇总卡或免费 / Pro 差异表。 |
| | | - Pro tab 对比表包含自定义标签颜色、彩色容器 / 彩色网格、高级主题、自定义快捷键、自定义应用备注和数据导入导出 / 分类与布局备份恢复;免费列锁定功能显示“不可用”,彩色容器 / 彩色网格和高级主题显示“只可预览 5 分钟”,备注显示“免费 3 个”;Pro 列未购买时显示带勾的“支持”,备注行显示带勾的“无限备注”,已购买后功能行显示带勾的“已解锁”。表格内免费列和 Pro 列的表头及状态胶囊都在列内左对齐;所有状态胶囊使用与“免费 3 个”一致的中性样式,不显示皇冠图标或黄色 Pro 背景。 |
| | | - About tab 保留顶部固定 Pro 状态行;主内容只保留应用信息、帮助文档和联系信息,不放 Pro 汇总卡或免费 / Pro 差异表。 |
| | | |
| | | ## AppGrid 显示与交互 |
| | | |
| | |
| | | <key>CFBundlePackageType</key> |
| | | <string>APPL</string> |
| | | <key>CFBundleShortVersionString</key> |
| | | <string>8.2.8</string> |
| | | <string>8.2.9</string> |
| | | <key>CFBundleURLTypes</key> |
| | | <array> |
| | | <dict> |
| | |
| | | </dict> |
| | | </array> |
| | | <key>CFBundleVersion</key> |
| | | <string>20260630.0128</string> |
| | | <string>20260630.1617</string> |
| | | <key>LSApplicationCategoryType</key> |
| | | <string>public.app-category.utilities</string> |
| | | <key>LSMinimumSystemVersion</key> |
| | |
| | | "pro.feature.customTagColors.benefit": "عيّن أي لون لكل وسم، بما في ذلك وسوم فئات النظام SmartStart.", |
| | | "pro.prompt.customTagColors": "ألوان الوسوم المخصصة من ميزات Pro. افتح Pro لمنح كل وسم أي لون وجعل الفئات أسهل تمييزًا.", |
| | | "settings.proStatus.freeUser": "أنت حاليًا مستخدم مجاني", |
| | | "settings.proStatus.proUser": "أنت حاليًا مستخدم 👑Pro مميز", |
| | | "settings.proStatus.proUser": "أنت حاليًا مستخدم Pro مميز", |
| | | "settings.proStatus.lockedListTitle": "ميزات Pro بانتظار الفتح", |
| | | "settings.proStatus.unlockedListTitle": "الميزات المفتوحة", |
| | | "settings.proStatus.lockedFeature": "✅ مدعوم", |
| | |
| | | "pro.feature.customTagColors.benefit": "عيّن أي لون لكل وسم، بما في ذلك وسوم فئات النظام SmartStart.", |
| | | "pro.prompt.customTagColors": "ألوان الوسوم المخصصة من ميزات Pro. افتح Pro لمنح كل وسم أي لون وجعل الفئات أسهل تمييزًا.", |
| | | "settings.proStatus.freeUser": "أنت حاليًا مستخدم مجاني", |
| | | "settings.proStatus.proUser": "أنت حاليًا مستخدم 👑Pro مميز", |
| | | "settings.proStatus.proUser": "أنت حاليًا مستخدم Pro مميز", |
| | | "settings.proStatus.lockedListTitle": "ميزات Pro بانتظار الفتح", |
| | | "settings.proStatus.unlockedListTitle": "الميزات المفتوحة", |
| | | "settings.proStatus.lockedFeature": "✅ مدعوم", |
| | |
| | | "pro.feature.customTagColors.benefit": "Nastavte libovolnou barvu každému štítku včetně systémových kategorií SmartStart.", |
| | | "pro.prompt.customTagColors": "Vlastní barvy štítků jsou funkce Pro. Odemkněte Pro, dejte každému štítku libovolnou barvu a snáze rozeznáte kategorie.", |
| | | "settings.proStatus.freeUser": "Právě jste uživatel bezplatné verze", |
| | | "settings.proStatus.proUser": "Právě jste vážený uživatel 👑Pro", |
| | | "settings.proStatus.proUser": "Právě jste vážený uživatel Pro", |
| | | "settings.proStatus.lockedListTitle": "Funkce Pro k odemčení", |
| | | "settings.proStatus.unlockedListTitle": "Odemčené funkce", |
| | | "settings.proStatus.lockedFeature": "✅ Podporováno", |
| | |
| | | "pro.feature.customTagColors.benefit": "Vælg en hvilken som helst farve til hvert tag, også SmartStart-systemkategorier.", |
| | | "pro.prompt.customTagColors": "Egne tagfarver er en Pro-funktion. Lås Pro op for at give hvert tag en valgfri farve og gøre kategorier lettere at kende.", |
| | | "settings.proStatus.freeUser": "Du er i øjeblikket gratisbruger", |
| | | "settings.proStatus.proUser": "Du er i øjeblikket en værdsat 👑Pro-bruger", |
| | | "settings.proStatus.proUser": "Du er i øjeblikket en værdsat Pro-bruger", |
| | | "settings.proStatus.lockedListTitle": "Pro-funktioner at låse op", |
| | | "settings.proStatus.unlockedListTitle": "Oplåste funktioner", |
| | | "settings.proStatus.lockedFeature": "✅ Understøttet", |
| | |
| | | "pro.feature.customTagColors.benefit": "Lege für jedes Tag eine beliebige Farbe fest, auch für SmartStart-Systemkategorien.", |
| | | "pro.prompt.customTagColors": "Eigene Tag-Farben sind eine Pro-Funktion. Mit Pro gibst du jedem Tag eine beliebige Farbe und erkennst Kategorien leichter.", |
| | | "settings.proStatus.freeUser": "Du bist derzeit Nutzer der Gratisversion", |
| | | "settings.proStatus.proUser": "Du bist derzeit ein geschätzter 👑Pro-Nutzer", |
| | | "settings.proStatus.proUser": "Du bist derzeit ein geschätzter Pro-Nutzer", |
| | | "settings.proStatus.lockedListTitle": "Freizuschaltende Pro-Funktionen", |
| | | "settings.proStatus.unlockedListTitle": "Freigeschaltete Funktionen", |
| | | "settings.proStatus.lockedFeature": "✅ Unterstützt", |
| | |
| | | "pro.feature.customTagColors.benefit": "Set any color for every tag, including SmartStart system category tags.", |
| | | "pro.prompt.customTagColors": "Custom tag colors are a Pro feature. Unlock Pro to give every tag any color and make categories easier to recognize.", |
| | | "settings.proStatus.freeUser": "You are currently a Free user", |
| | | "settings.proStatus.proUser": "You are currently a valued 👑Pro user", |
| | | "settings.proStatus.proUser": "You are currently a valued Pro user", |
| | | "settings.proStatus.lockedListTitle": "Pro features to unlock", |
| | | "settings.proStatus.unlockedListTitle": "Unlocked features", |
| | | "settings.proStatus.lockedFeature": "✅ Supported", |
| | |
| | | "pro.feature.customTagColors.benefit": "Elige cualquier color para cada etiqueta, incluidas las categorías del sistema SmartStart.", |
| | | "pro.prompt.customTagColors": "Los colores personalizados de etiquetas son una función Pro. Desbloquea Pro para dar cualquier color a cada etiqueta y reconocer mejor tus categorías.", |
| | | "settings.proStatus.freeUser": "Actualmente eres usuario gratuito", |
| | | "settings.proStatus.proUser": "Actualmente eres un usuario 👑Pro distinguido", |
| | | "settings.proStatus.proUser": "Actualmente eres un usuario Pro distinguido", |
| | | "settings.proStatus.lockedListTitle": "Funciones Pro por desbloquear", |
| | | "settings.proStatus.unlockedListTitle": "Funciones desbloqueadas", |
| | | "settings.proStatus.lockedFeature": "✅ Compatible", |
| | |
| | | "pro.feature.customTagColors.benefit": "Choisissez n’importe quelle couleur pour chaque tag, y compris les catégories système SmartStart.", |
| | | "pro.prompt.customTagColors": "Les couleurs de tags personnalisées sont une fonction Pro. Débloquez Pro pour donner toute couleur à chaque tag et mieux reconnaître les catégories.", |
| | | "settings.proStatus.freeUser": "Vous êtes actuellement utilisateur gratuit", |
| | | "settings.proStatus.proUser": "Vous êtes actuellement un utilisateur 👑Pro privilégié", |
| | | "settings.proStatus.proUser": "Vous êtes actuellement un utilisateur Pro privilégié", |
| | | "settings.proStatus.lockedListTitle": "Fonctions Pro à débloquer", |
| | | "settings.proStatus.unlockedListTitle": "Fonctions débloquées", |
| | | "settings.proStatus.lockedFeature": "✅ Pris en charge", |
| | |
| | | "pro.feature.customTagColors.benefit": "Atur warna apa pun untuk tiap tag, termasuk tag kategori sistem SmartStart.", |
| | | "pro.prompt.customTagColors": "Warna tag khusus adalah fitur Pro. Buka Pro untuk memberi tiap tag warna apa pun agar kategori lebih mudah dikenali.", |
| | | "settings.proStatus.freeUser": "Saat ini Anda pengguna Gratis", |
| | | "settings.proStatus.proUser": "Saat ini Anda pengguna 👑Pro istimewa", |
| | | "settings.proStatus.proUser": "Saat ini Anda pengguna Pro istimewa", |
| | | "settings.proStatus.lockedListTitle": "Fitur Pro untuk dibuka", |
| | | "settings.proStatus.unlockedListTitle": "Fitur yang terbuka", |
| | | "settings.proStatus.lockedFeature": "✅ Didukung", |
| | |
| | | "pro.feature.customTagColors.benefit": "Imposta qualsiasi colore per ogni tag, incluse le categorie di sistema SmartStart.", |
| | | "pro.prompt.customTagColors": "I colori tag personalizzati sono una funzione Pro. Sblocca Pro per dare qualsiasi colore a ogni tag e riconoscere meglio le categorie.", |
| | | "settings.proStatus.freeUser": "Al momento sei un utente gratuito", |
| | | "settings.proStatus.proUser": "Al momento sei un utente 👑Pro privilegiato", |
| | | "settings.proStatus.proUser": "Al momento sei un utente Pro privilegiato", |
| | | "settings.proStatus.lockedListTitle": "Funzioni Pro da sbloccare", |
| | | "settings.proStatus.unlockedListTitle": "Funzioni sbloccate", |
| | | "settings.proStatus.lockedFeature": "✅ Supportato", |
| | |
| | | "pro.feature.customTagColors.benefit": "SmartStart のシステムカテゴリタグを含め、各タグに任意の色を設定できます。", |
| | | "pro.prompt.customTagColors": "カスタムタグ色は Pro 機能です。Pro を解除すると各タグに任意の色を設定でき、カテゴリを見分けやすくなります。", |
| | | "settings.proStatus.freeUser": "現在は無料版ユーザーです", |
| | | "settings.proStatus.proUser": "現在は特別な 👑Pro ユーザーです", |
| | | "settings.proStatus.proUser": "現在は特別な Pro ユーザーです", |
| | | "settings.proStatus.lockedListTitle": "解除待ちの Pro 機能", |
| | | "settings.proStatus.unlockedListTitle": "解除済み機能", |
| | | "settings.proStatus.lockedFeature": "✅ 対応", |
| | |
| | | "pro.feature.customTagColors.benefit": "SmartStart 시스템 카테고리 태그를 포함해 모든 태그에 원하는 색상을 설정합니다.", |
| | | "pro.prompt.customTagColors": "사용자 지정 태그 색상은 Pro 기능입니다. Pro를 잠금 해제하면 각 태그에 원하는 색을 지정해 카테고리를 더 쉽게 구분할 수 있습니다.", |
| | | "settings.proStatus.freeUser": "현재 무료 사용자입니다", |
| | | "settings.proStatus.proUser": "현재 특별 👑Pro 사용자입니다", |
| | | "settings.proStatus.proUser": "현재 특별 Pro 사용자입니다", |
| | | "settings.proStatus.lockedListTitle": "잠금 해제할 Pro 기능", |
| | | "settings.proStatus.unlockedListTitle": "잠금 해제된 기능", |
| | | "settings.proStatus.lockedFeature": "✅ 지원", |
| | |
| | | "pro.feature.customTagColors.benefit": "Tetapkan sebarang warna untuk setiap tag, termasuk tag kategori sistem SmartStart.", |
| | | "pro.prompt.customTagColors": "Warna tag tersuai ialah ciri Pro. Buka Pro untuk memberi setiap tag sebarang warna dan mengenal pasti kategori dengan lebih mudah.", |
| | | "settings.proStatus.freeUser": "Anda kini pengguna Percuma", |
| | | "settings.proStatus.proUser": "Anda kini pengguna 👑Pro istimewa", |
| | | "settings.proStatus.proUser": "Anda kini pengguna Pro istimewa", |
| | | "settings.proStatus.lockedListTitle": "Ciri Pro untuk dibuka", |
| | | "settings.proStatus.unlockedListTitle": "Ciri dibuka", |
| | | "settings.proStatus.lockedFeature": "✅ Disokong", |
| | |
| | | "pro.feature.customTagColors.benefit": "Vælg en hvilken som helst farve til hvert tag, også SmartStart-systemkategorier.", |
| | | "pro.prompt.customTagColors": "Egne tagfarver er en Pro-funktion. Lås Pro op for at give hvert tag en valgfri farve og gøre kategorier lettere at kende.", |
| | | "settings.proStatus.freeUser": "Du er nå gratisbruker", |
| | | "settings.proStatus.proUser": "Du er nå en verdsatt 👑Pro-bruker", |
| | | "settings.proStatus.proUser": "Du er nå en verdsatt Pro-bruker", |
| | | "settings.proStatus.lockedListTitle": "Pro-funksjoner å låse opp", |
| | | "settings.proStatus.unlockedListTitle": "Opplåste funksjoner", |
| | | "settings.proStatus.lockedFeature": "✅ Støttet", |
| | |
| | | "pro.feature.customTagColors.benefit": "Stel elke kleur in voor elk tag, inclusief SmartStart-systeemcategorieën.", |
| | | "pro.prompt.customTagColors": "Eigen tagkleuren zijn een Pro-functie. Ontgrendel Pro om elk tag een kleur te geven en categorieën makkelijker te herkennen.", |
| | | "settings.proStatus.freeUser": "Je bent momenteel een gratis gebruiker", |
| | | "settings.proStatus.proUser": "Je bent momenteel een gewaardeerde 👑Pro-gebruiker", |
| | | "settings.proStatus.proUser": "Je bent momenteel een gewaardeerde Pro-gebruiker", |
| | | "settings.proStatus.lockedListTitle": "Pro-functies om te ontgrendelen", |
| | | "settings.proStatus.unlockedListTitle": "Ontgrendelde functies", |
| | | "settings.proStatus.lockedFeature": "✅ Ondersteund", |
| | |
| | | "pro.feature.customTagColors.benefit": "Vælg en hvilken som helst farve til hvert tag, også SmartStart-systemkategorier.", |
| | | "pro.prompt.customTagColors": "Egne tagfarver er en Pro-funktion. Lås Pro op for at give hvert tag en valgfri farve og gøre kategorier lettere at kende.", |
| | | "settings.proStatus.freeUser": "Du er no gratisbrukar", |
| | | "settings.proStatus.proUser": "Du er no ein verdsett 👑Pro-brukar", |
| | | "settings.proStatus.proUser": "Du er no ein verdsett Pro-brukar", |
| | | "settings.proStatus.lockedListTitle": "Pro-funksjonar å låse opp", |
| | | "settings.proStatus.unlockedListTitle": "Opplåste funksjonar", |
| | | "settings.proStatus.lockedFeature": "✅ Støtta", |
| | |
| | | "pro.feature.customTagColors.benefit": "Vælg en hvilken som helst farve til hvert tag, også SmartStart-systemkategorier.", |
| | | "pro.prompt.customTagColors": "Egne tagfarver er en Pro-funktion. Lås Pro op for at give hvert tag en valgfri farve og gøre kategorier lettere at kende.", |
| | | "settings.proStatus.freeUser": "Du er nå gratisbruker", |
| | | "settings.proStatus.proUser": "Du er nå en verdsatt 👑Pro-bruker", |
| | | "settings.proStatus.proUser": "Du er nå en verdsatt Pro-bruker", |
| | | "settings.proStatus.lockedListTitle": "Pro-funksjoner å låse opp", |
| | | "settings.proStatus.unlockedListTitle": "Opplåste funksjoner", |
| | | "settings.proStatus.lockedFeature": "✅ Støttet", |
| | |
| | | "pro.feature.customTagColors.benefit": "Ustaw dowolny kolor dla każdego tagu, także kategorii systemowych SmartStart.", |
| | | "pro.prompt.customTagColors": "Własne kolory tagów są funkcją Pro. Odblokuj Pro, nadaj każdemu tagowi dowolny kolor i łatwiej rozpoznawaj kategorie.", |
| | | "settings.proStatus.freeUser": "Obecnie jesteś użytkownikiem bezpłatnym", |
| | | "settings.proStatus.proUser": "Obecnie jesteś cenionym użytkownikiem 👑Pro", |
| | | "settings.proStatus.proUser": "Obecnie jesteś cenionym użytkownikiem Pro", |
| | | "settings.proStatus.lockedListTitle": "Funkcje Pro do odblokowania", |
| | | "settings.proStatus.unlockedListTitle": "Odblokowane funkcje", |
| | | "settings.proStatus.lockedFeature": "✅ Obsługiwane", |
| | |
| | | "pro.feature.customTagColors.benefit": "Defina qualquer cor para cada etiqueta, incluindo categorias de sistema do SmartStart.", |
| | | "pro.prompt.customTagColors": "Cores personalizadas de etiquetas são um recurso Pro. Desbloqueie o Pro para dar qualquer cor a cada etiqueta e reconhecer categorias com mais facilidade.", |
| | | "settings.proStatus.freeUser": "Você está usando a versão gratuita", |
| | | "settings.proStatus.proUser": "Você é um usuário 👑Pro valorizado", |
| | | "settings.proStatus.proUser": "Você é um usuário Pro valorizado", |
| | | "settings.proStatus.lockedListTitle": "Recursos Pro para desbloquear", |
| | | "settings.proStatus.unlockedListTitle": "Recursos desbloqueados", |
| | | "settings.proStatus.lockedFeature": "✅ Compatível", |
| | |
| | | "pro.feature.customTagColors.benefit": "Setează orice culoare pentru fiecare etichetă, inclusiv categoriile de sistem SmartStart.", |
| | | "pro.prompt.customTagColors": "Culorile personalizate pentru etichete sunt o funcție Pro. Deblochează Pro pentru a colora fiecare etichetă și a recunoaște mai ușor categoriile.", |
| | | "settings.proStatus.freeUser": "Ești în prezent utilizator gratuit", |
| | | "settings.proStatus.proUser": "Ești în prezent un utilizator 👑Pro apreciat", |
| | | "settings.proStatus.proUser": "Ești în prezent un utilizator Pro apreciat", |
| | | "settings.proStatus.lockedListTitle": "Funcții Pro de deblocat", |
| | | "settings.proStatus.unlockedListTitle": "Funcții deblocate", |
| | | "settings.proStatus.lockedFeature": "✅ Acceptat", |
| | |
| | | "pro.feature.customTagColors.benefit": "Задавайте любой цвет для каждого тега, включая системные категории SmartStart.", |
| | | "pro.prompt.customTagColors": "Собственные цвета тегов — функция Pro. Откройте Pro, чтобы назначать любому тегу любой цвет и легче различать категории.", |
| | | "settings.proStatus.freeUser": "Сейчас вы пользователь бесплатной версии", |
| | | "settings.proStatus.proUser": "Сейчас вы ценный пользователь 👑Pro", |
| | | "settings.proStatus.proUser": "Сейчас вы ценный пользователь Pro", |
| | | "settings.proStatus.lockedListTitle": "Функции Pro для разблокировки", |
| | | "settings.proStatus.unlockedListTitle": "Разблокированные функции", |
| | | "settings.proStatus.lockedFeature": "✅ Поддерживается", |
| | |
| | | "pro.feature.customTagColors.benefit": "Подесите било коју боју за сваку ознаку, укључујући SmartStart системске категорије.", |
| | | "pro.prompt.customTagColors": "Прилагођене боје ознака су Pro функција. Откључајте Pro да свакој ознаци дате било коју боју и лакше препознате категорије.", |
| | | "settings.proStatus.freeUser": "Тренутно сте корисник бесплатне верзије", |
| | | "settings.proStatus.proUser": "Тренутно сте цењени 👑Pro корисник", |
| | | "settings.proStatus.proUser": "Тренутно сте цењени Pro корисник", |
| | | "settings.proStatus.lockedListTitle": "Pro функције за откључавање", |
| | | "settings.proStatus.unlockedListTitle": "Откључане функције", |
| | | "settings.proStatus.lockedFeature": "✅ Подржано", |
| | |
| | | "pro.feature.customTagColors.benefit": "Ange valfri färg för varje tagg, inklusive SmartStart-systemkategorier.", |
| | | "pro.prompt.customTagColors": "Egna taggfärger är en Pro-funktion. Lås upp Pro för att ge varje tagg valfri färg och göra kategorier lättare att känna igen.", |
| | | "settings.proStatus.freeUser": "Du är för närvarande gratisanvändare", |
| | | "settings.proStatus.proUser": "Du är för närvarande en uppskattad 👑Pro-användare", |
| | | "settings.proStatus.proUser": "Du är för närvarande en uppskattad Pro-användare", |
| | | "settings.proStatus.lockedListTitle": "Pro-funktioner att låsa upp", |
| | | "settings.proStatus.unlockedListTitle": "Upplåsta funktioner", |
| | | "settings.proStatus.lockedFeature": "✅ Stöds", |
| | |
| | | "pro.feature.customTagColors.benefit": "ตั้งค่าสีใดก็ได้ให้ทุกแท็ก รวมถึงแท็กหมวดหมู่ระบบ SmartStart", |
| | | "pro.prompt.customTagColors": "สีแท็กแบบกำหนดเองเป็นฟีเจอร์ Pro ปลดล็อก Pro เพื่อให้ทุกแท็กใช้สีใดก็ได้และแยกหมวดหมู่ได้ง่ายขึ้น", |
| | | "settings.proStatus.freeUser": "ตอนนี้คุณเป็นผู้ใช้ฟรี", |
| | | "settings.proStatus.proUser": "ตอนนี้คุณเป็นผู้ใช้ 👑Pro ระดับพิเศษ", |
| | | "settings.proStatus.proUser": "ตอนนี้คุณเป็นผู้ใช้ Pro ระดับพิเศษ", |
| | | "settings.proStatus.lockedListTitle": "ฟีเจอร์ Pro ที่รอปลดล็อก", |
| | | "settings.proStatus.unlockedListTitle": "ฟีเจอร์ที่ปลดล็อกแล้ว", |
| | | "settings.proStatus.lockedFeature": "✅ รองรับ", |
| | |
| | | "pro.feature.customTagColors.benefit": "SmartStart sistem kategorileri dahil her etikete istediğiniz rengi verin.", |
| | | "pro.prompt.customTagColors": "Özel etiket renkleri bir Pro özelliğidir. Pro’yu açarak her etikete istediğiniz rengi verin ve kategorileri daha kolay tanıyın.", |
| | | "settings.proStatus.freeUser": "Şu anda ücretsiz kullanıcısısınız", |
| | | "settings.proStatus.proUser": "Şu anda değerli bir 👑Pro kullanıcısısınız", |
| | | "settings.proStatus.proUser": "Şu anda değerli bir Pro kullanıcısısınız", |
| | | "settings.proStatus.lockedListTitle": "Açılacak Pro özellikleri", |
| | | "settings.proStatus.unlockedListTitle": "Açılmış özellikler", |
| | | "settings.proStatus.lockedFeature": "✅ Desteklenir", |
| | |
| | | "pro.feature.customTagColors.benefit": "Задавайте будь-який колір для кожного тега, включно із системними категоріями SmartStart.", |
| | | "pro.prompt.customTagColors": "Власні кольори тегів — функція Pro. Відкрийте Pro, щоб давати кожному тегу будь-який колір і легше розпізнавати категорії.", |
| | | "settings.proStatus.freeUser": "Зараз ви користувач безкоштовної версії", |
| | | "settings.proStatus.proUser": "Зараз ви цінний користувач 👑Pro", |
| | | "settings.proStatus.proUser": "Зараз ви цінний користувач Pro", |
| | | "settings.proStatus.lockedListTitle": "Функції Pro для відкриття", |
| | | "settings.proStatus.unlockedListTitle": "Відкриті функції", |
| | | "settings.proStatus.lockedFeature": "✅ Підтримується", |
| | |
| | | "pro.feature.customTagColors.benefit": "Đặt bất kỳ màu nào cho mỗi thẻ, kể cả thẻ danh mục hệ thống SmartStart.", |
| | | "pro.prompt.customTagColors": "Màu thẻ tùy chỉnh là tính năng Pro. Mở khóa Pro để đặt màu bất kỳ cho từng thẻ và nhận diện danh mục dễ hơn.", |
| | | "settings.proStatus.freeUser": "Bạn hiện là người dùng Miễn phí", |
| | | "settings.proStatus.proUser": "Bạn hiện là người dùng 👑Pro danh giá", |
| | | "settings.proStatus.proUser": "Bạn hiện là người dùng Pro danh giá", |
| | | "settings.proStatus.lockedListTitle": "Tính năng Pro chờ mở khóa", |
| | | "settings.proStatus.unlockedListTitle": "Tính năng đã mở khóa", |
| | | "settings.proStatus.lockedFeature": "✅ Hỗ trợ", |
| | |
| | | "pro.feature.customTagColors.benefit": "为每个标签设置任意颜色,包括 SmartStart 系统分类标签。", |
| | | "pro.prompt.customTagColors": "自定义标签颜色属于 Pro 功能。解锁 Pro 后,可为每个标签设置任意颜色,让分类更容易识别。", |
| | | "settings.proStatus.freeUser": "您当前是免费版用户", |
| | | "settings.proStatus.proUser": "您当前是尊贵的 👑Pro版用户", |
| | | "settings.proStatus.proUser": "您当前是尊贵的 Pro 用户", |
| | | "settings.proStatus.lockedListTitle": "待解锁的 Pro 功能", |
| | | "settings.proStatus.unlockedListTitle": "已解锁的功能", |
| | | "settings.proStatus.lockedFeature": "✅支持", |
| | |
| | | "pro.feature.customTagColors.benefit": "為每個標籤設定任意顏色,包括 SmartStart 系統分類標籤。", |
| | | "pro.prompt.customTagColors": "自訂標籤顏色屬於 Pro 功能。解鎖 Pro 後可為每個標籤設定任意顏色,讓分類更容易辨識。", |
| | | "settings.proStatus.freeUser": "您目前是免費版使用者", |
| | | "settings.proStatus.proUser": "您目前是尊貴的 👑Pro版使用者", |
| | | "settings.proStatus.proUser": "您目前是尊貴的 Pro 使用者", |
| | | "settings.proStatus.lockedListTitle": "待解鎖的 Pro 功能", |
| | | "settings.proStatus.unlockedListTitle": "已解鎖的功能", |
| | | "settings.proStatus.lockedFeature": "✅支援", |
| | |
| | | Color(red: 0.56, green: 0.35, blue: 0.03) |
| | | } |
| | | |
| | | @ViewBuilder |
| | | private func proHeaderStatusLabel(compact: Bool = false) -> some View { |
| | | if proEntitlement.accessState == .free && !proEntitlement.isPreviewingProAppearance { |
| | | Text(tr("settings.proStatus.freeUser")) |
| | | .font(.system(size: compact ? 12 : 13, weight: .semibold)) |
| | | .foregroundStyle(.secondary) |
| | | .lineLimit(1) |
| | | .minimumScaleFactor(0.82) |
| | | } else { |
| | | ProStatusPill( |
| | | text: tr(proEntitlement.compactStatusTextKey), |
| | | style: proStatusPillStyle, |
| | | compact: compact |
| | | ) |
| | | } |
| | | } |
| | | |
| | | private func centeredSettingsScrollContent<Content: View>( |
| | | width: CGFloat, |
| | | @ViewBuilder content: @escaping () -> Content |
| | |
| | | compact: Bool = false |
| | | ) -> some View { |
| | | HStack(spacing: compact ? 8 : 12) { |
| | | ProStatusPill( |
| | | text: tr(proEntitlement.compactStatusTextKey), |
| | | style: proStatusPillStyle |
| | | ) |
| | | proHeaderStatusLabel(compact: compact) |
| | | .layoutPriority(1) |
| | | |
| | | Text(tr(textKey)) |
| | |
| | | } |
| | | |
| | | switch selectedTab { |
| | | case .general, .language, .about: |
| | | case .language, .about: |
| | | return "" |
| | | case .general: |
| | | return tr(proEntitlement.isUnlocked ? "settings.proBenefit.general" : "settings.proGuide.general") |
| | | case .theme: |
| | | return themeStatusSummary |
| | |
| | | } |
| | | |
| | | private var shouldShowSettingsFixedProHeader: Bool { |
| | | selectedTab != .language && selectedTab != .about |
| | | true |
| | | } |
| | | |
| | | private var shouldCenterUnlockedIdentityHeader: Bool { |
| | | guard proEntitlement.isUnlocked else { return false } |
| | | switch selectedTab { |
| | | case .language, .pro, .about: |
| | | return true |
| | | case .general, .theme, .hotkeys, .tags, .data: |
| | | return false |
| | | } |
| | | } |
| | | |
| | | private var settingsFixedProHeader: some View { |
| | | HStack { |
| | | HStack(spacing: 12) { |
| | | if selectedTab != .pro { |
| | | if shouldCenterUnlockedIdentityHeader { |
| | | Spacer(minLength: 0) |
| | | |
| | | ProStatusPill( |
| | | text: tr(proEntitlement.compactStatusTextKey), |
| | | style: proStatusPillStyle |
| | | text: tr("pro.status.unlocked"), |
| | | style: .unlocked, |
| | | compact: true |
| | | ) |
| | | .layoutPriority(1) |
| | | } |
| | | |
| | | Text(settingsProHeaderText) |
| | | .font(.system(size: 13, weight: .medium)) |
| | | .foregroundStyle(.secondary) |
| | | .lineLimit(2) |
| | | .fixedSize(horizontal: false, vertical: true) |
| | | .layoutPriority(2) |
| | | Text(tr("settings.proStatus.proUser")) |
| | | .font(.system(size: 13, weight: .medium)) |
| | | .foregroundStyle(.secondary) |
| | | .lineLimit(1) |
| | | .fixedSize(horizontal: false, vertical: true) |
| | | .layoutPriority(2) |
| | | |
| | | Spacer(minLength: 8) |
| | | |
| | | if !proEntitlement.isUnlocked { |
| | | Button(unlockButtonTitle()) { |
| | | presentSettingsProPrompt(for: settingsProHeaderFeature) |
| | | Spacer(minLength: 0) |
| | | } else { |
| | | if selectedTab != .pro { |
| | | proHeaderStatusLabel(compact: true) |
| | | .layoutPriority(1) |
| | | } |
| | | .buttonStyle(.borderedProminent) |
| | | .controlSize(.small) |
| | | .layoutPriority(3) |
| | | |
| | | Button(tr("pro.card.restore")) { |
| | | proEntitlement.restorePurchases() |
| | | if !settingsProHeaderText.isEmpty { |
| | | Text(settingsProHeaderText) |
| | | .font(.system(size: 13, weight: .medium)) |
| | | .foregroundStyle(.secondary) |
| | | .lineLimit(2) |
| | | .fixedSize(horizontal: false, vertical: true) |
| | | .layoutPriority(2) |
| | | } |
| | | .buttonStyle(.bordered) |
| | | .controlSize(.small) |
| | | .layoutPriority(3) |
| | | |
| | | Spacer(minLength: 8) |
| | | |
| | | if !proEntitlement.isUnlocked { |
| | | Button(unlockButtonTitle()) { |
| | | presentSettingsProPrompt(for: settingsProHeaderFeature) |
| | | } |
| | | .buttonStyle(.borderedProminent) |
| | | .controlSize(.small) |
| | | .layoutPriority(3) |
| | | |
| | | Button(tr("pro.card.restore")) { |
| | | proEntitlement.restorePurchases() |
| | | } |
| | | .buttonStyle(.bordered) |
| | | .controlSize(.small) |
| | | .layoutPriority(3) |
| | | } |
| | | } |
| | | } |
| | | .padding(.horizontal, 16) |
| | |
| | | Text(tr("settings.proCompare.free")) |
| | | .font(.system(size: 12, weight: .semibold)) |
| | | .foregroundStyle(.secondary) |
| | | .frame(width: 118, alignment: .center) |
| | | .frame(width: 118, alignment: .leading) |
| | | HStack(spacing: 4) { |
| | | Image(systemName: "crown") |
| | | .font(.system(size: 12, weight: .semibold)) |
| | |
| | | .foregroundStyle(proAccentColor) |
| | | .lineLimit(1) |
| | | .minimumScaleFactor(0.82) |
| | | .frame(width: 118, alignment: .center) |
| | | .frame(width: 118, alignment: .leading) |
| | | } |
| | | |
| | | ForEach(proTabComparisonFeatures) { feature in |
| | |
| | | style: feature.freeStyle, |
| | | compact: true |
| | | ) |
| | | .frame(width: 118, alignment: .center) |
| | | .frame(width: 118, alignment: .leading) |
| | | |
| | | ProStatusPill( |
| | | text: tr(proStatusKey), |
| | | style: proStyle, |
| | | compact: true |
| | | ) |
| | | .frame(width: 118, alignment: .center) |
| | | .frame(width: 118, alignment: .leading) |
| | | } |
| | | .padding(.horizontal, 10) |
| | | .padding(.vertical, 8) |
| | |
| | | proUnlockedBenefitLine("pro.theme.status.unlocked", bottomPadding: 0) |
| | | } else { |
| | | HStack(spacing: 12) { |
| | | ProStatusPill( |
| | | text: tr(proEntitlement.compactStatusTextKey), |
| | | style: proStatusPillStyle |
| | | ) |
| | | proHeaderStatusLabel() |
| | | |
| | | Text(themeStatusSummary) |
| | | .font(.system(size: 13, weight: .medium)) |
| | |
| | | |
| | | ## [Unreleased] |
| | | |
| | | ## [8.2.9] — 2026-06-30 |
| | | |
| | | - 统一已解锁 Pro 用户在设置页“语言 / Pro / 关于”顶部状态行:居中显示 `Pro 已解锁` 胶囊和“您当前是尊贵的 Pro 用户” |
| | | - 移除该 Pro 用户身份文案内的重复皇冠符号,皇冠只由前置胶囊图标承载;同步更新 29 个语种 |
| | | - 扩展 Pro / 本地化 QA 门禁,防止该状态行回退为非居中、重复皇冠或错误页签范围 |
| | | - 版本号更新为 `8.2.9`,Build 更新为 `20260630.1617` |
| | | |
| | | ## [8.2.8] — 2026-06-30 |
| | | |
| | | - 修复 Quick Search 候选列表触摸板 / 鼠标点击仍无法启动应用的问题:结果面板保留原 `hitTest` 路径,并增加按窗口坐标递归命中结果行的几何兜底,复用回车同一启动路径 |
| | |
| | | require(preferences, "private var settingsFixedProHeader: some View", "Settings pages must share one fixed-position Pro guidance header") |
| | | require(preferences, "private var settingsProHeaderText: String", "fixed Pro guidance header must switch copy by selected tab") |
| | | require(preferences, "private var settingsProHeaderFeature: ProFeature", "fixed Pro guidance header must route unlock prompts by selected tab") |
| | | require(preferences, "private var shouldShowSettingsFixedProHeader: Bool", "Language/About tabs must be able to hide the fixed Pro header") |
| | | require(preferences, "selectedTab != .language && selectedTab != .about", "fixed Pro header must be hidden on Language and About tabs") |
| | | require(preferences, "private var shouldCenterUnlockedIdentityHeader: Bool", "Language/Pro/About tabs need the centered unlocked Pro identity header") |
| | | center_identity_body = function_body(preferences, "private var shouldCenterUnlockedIdentityHeader: Bool") |
| | | require(center_identity_body, "guard proEntitlement.isUnlocked else { return false }", "centered Pro identity header must only apply after Pro unlock") |
| | | require(center_identity_body, "case .language, .pro, .about:", "centered Pro identity header must apply to Language, Pro, and About tabs") |
| | | require(center_identity_body, "case .general, .theme, .hotkeys, .tags, .data:", "centered Pro identity header must not affect the feature-specific settings tabs") |
| | | settings_header_text_body = function_body(preferences, "private var settingsProHeaderText: String") |
| | | require(settings_header_text_body, "case .language, .about:", "Language/About tabs must have an explicit fixed-header text branch") |
| | | require(settings_header_text_body, 'return ""', "Language/About tabs must not show the general Pro guidance sentence") |
| | | if "case .general, .language, .about:" in settings_header_text_body: |
| | | fail("Language/About tabs must not reuse the General tab Pro guidance sentence") |
| | | require(preferences, "private func proHeaderStatusLabel(compact: Bool = false) -> some View", "fixed Pro guidance header must render the free status as plain text") |
| | | require(preferences, 'Text(tr("settings.proStatus.freeUser"))', "Free status must render as the full current-user sentence instead of a Free pill") |
| | | require(preferences, "private var shouldShowSettingsFixedProHeader: Bool", "all settings tabs must use the fixed Pro header gate") |
| | | require(function_body(preferences, "private var shouldShowSettingsFixedProHeader: Bool"), "true", "fixed Pro header must be shown on Language and About tabs too") |
| | | if "selectedTab != .language && selectedTab != .about" in preferences: |
| | | fail("fixed Pro header must no longer be hidden on Language and About tabs") |
| | | require(preferences, "if shouldShowSettingsFixedProHeader", "Settings body must conditionally render the fixed Pro header") |
| | | fixed_header_body = function_body(preferences, "private var settingsFixedProHeader: some View") |
| | | require(fixed_header_body, "if shouldCenterUnlockedIdentityHeader", "fixed Pro header must use the centered unlocked identity branch") |
| | | require(fixed_header_body, 'text: tr("pro.status.unlocked")', "centered Pro identity header must start with the Pro unlocked pill") |
| | | require(fixed_header_body, "style: .unlocked", "centered Pro identity pill must use the unlocked style") |
| | | require(fixed_header_body, 'Text(tr("settings.proStatus.proUser"))', "centered Pro identity header must render the current Pro user sentence") |
| | | if fixed_header_body.find("if shouldCenterUnlockedIdentityHeader") > fixed_header_body.find('Text(tr("settings.proStatus.proUser"))'): |
| | | fail("centered Pro identity sentence must be inside the centered branch") |
| | | if fixed_header_body.count("Spacer(minLength: 0)") < 2: |
| | | fail("centered Pro identity header must be horizontally centered with leading and trailing spacers") |
| | | require(fixed_header_body, "if !proEntitlement.isUnlocked", "fixed Pro header must branch on unlocked state") |
| | | require(fixed_header_body, 'Button(tr("pro.card.restore"))', "fixed Pro header must keep restore purchase for free users") |
| | | if fixed_header_body.find("if !proEntitlement.isUnlocked") > fixed_header_body.find('Button(tr("pro.card.restore"))'): |
| | |
| | | require(preferences, 'selectedTab == .pro', "fixed Pro header must render the Pro tab user status state") |
| | | require(preferences, "proTabComparisonTable(width: dataPanelWidth)", "Pro tab must render the Free-vs-Pro comparison table") |
| | | require(preferences, "private struct ProTabComparisonFeature", "Pro tab comparison row model is missing") |
| | | comparison_body = function_body(preferences, "private func proTabComparisonTable(width: CGFloat)") |
| | | if comparison_body.count(".frame(width: 118, alignment: .leading)") < 4: |
| | | fail("Pro comparison Free/Pro columns and status chips must be left-aligned") |
| | | if ".frame(width: 118, alignment: .center)" in comparison_body: |
| | | fail("Pro comparison status columns must not be centered") |
| | | if 'Text(tr("settings.proCompare.title"))' in preferences: |
| | | fail("Pro tab comparison table must not render the removed title") |
| | | require(preferences, 'Text(tr("settings.proCompare.free"))', "Pro tab comparison table free column is missing") |
| | |
| | | fail("en.json Pro comparison unlimited notes status must include the leading checkmark") |
| | | if english.get("settings.proStatus.unlockedFeature") != "✅ Unlocked": |
| | | fail("en.json Pro comparison unlocked status must be '✅ Unlocked'") |
| | | if english.get("settings.proStatus.proUser") != "You are currently a valued Pro user": |
| | | fail("en.json settings.proStatus.proUser must not duplicate the crown icon in text") |
| | | |
| | | zh_hans = load_json(localization_dir / "zh-Hans.json") |
| | | if zh_hans.get("settings.proStatus.lockedFeature") != "✅支持": |
| | |
| | | fail("zh-Hans.json Pro comparison unlimited notes status must be '✅无限备注'") |
| | | if zh_hans.get("settings.proStatus.unlockedFeature") != "✅已解锁": |
| | | fail("zh-Hans.json Pro comparison unlocked status must be '✅已解锁'") |
| | | if zh_hans.get("settings.proStatus.proUser") != "您当前是尊贵的 Pro 用户": |
| | | fail("zh-Hans.json settings.proStatus.proUser must be the approved centered Pro identity sentence") |
| | | |
| | | ko = load_json(localization_dir / "ko.json") |
| | | if ko.get("quickSearch.hotkeys") != "키보드 단축키": |
| | |
| | | if copied_english: |
| | | fail(f"{code}.json copies English Pro copy: {', '.join(copied_english)}") |
| | | |
| | | if "👑" in data.get("settings.proStatus.proUser", ""): |
| | | fail(f"{code}.json settings.proStatus.proUser must not duplicate the crown icon") |
| | | |
| | | print( |
| | | "PASS Pro localization QA: " |
| | | f"{len(language_codes)} languages, {len(pro_keys) + len(REQUIRED_NON_PRO_KEYS) + len(REQUIRED_VISIBLE_SETTINGS_KEYS)} Pro/settings keys, " |