From 58e615462cbe03b724fc8e061740d6b2b49cc8e2 Mon Sep 17 00:00:00 2001 From: zarzet Date: Fri, 26 Jun 2026 22:16:21 +0700 Subject: [PATCH] feat(ui): add Beta badge to Backup & Restore settings entry Extract the BETA pill into a reusable BetaBadge widget in settings_group.dart and add titleTrailing support to SettingsItem. Show the badge on the Backup & Restore entry in the settings list, and reuse the shared widget in the download settings page (removing the duplicated private badge). --- .../settings/download_settings_page.dart | 25 +---------- lib/screens/settings/settings_tab.dart | 1 + lib/widgets/settings_group.dart | 45 ++++++++++++++++++- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/lib/screens/settings/download_settings_page.dart b/lib/screens/settings/download_settings_page.dart index 924870cb..ba91f0ba 100644 --- a/lib/screens/settings/download_settings_page.dart +++ b/lib/screens/settings/download_settings_page.dart @@ -199,7 +199,7 @@ class _DownloadSettingsPageState extends ConsumerState { SettingsSwitchItem( icon: Icons.downloading_outlined, title: context.l10n.downloadNativeWorker, - titleTrailing: const _BetaBadge(), + titleTrailing: BetaBadge(label: context.l10n.badgeBeta), subtitle: hasDownloadExtensions ? context.l10n.downloadNativeWorkerSubtitle : context.l10n.extensionsNoDownloadProvider, @@ -845,29 +845,6 @@ class _DownloadSettingsPageState extends ConsumerState { } } -class _BetaBadge extends StatelessWidget { - const _BetaBadge(); - - @override - Widget build(BuildContext context) { - final colorScheme = Theme.of(context).colorScheme; - return Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: colorScheme.tertiaryContainer, - borderRadius: BorderRadius.circular(6), - ), - child: Text( - context.l10n.badgeBeta, - style: Theme.of(context).textTheme.labelSmall?.copyWith( - color: colorScheme.onTertiaryContainer, - fontWeight: FontWeight.w700, - ), - ), - ); - } -} - class _QualityOption extends StatelessWidget { final String title; final String subtitle; diff --git a/lib/screens/settings/settings_tab.dart b/lib/screens/settings/settings_tab.dart index c117f3b7..c2703a72 100644 --- a/lib/screens/settings/settings_tab.dart +++ b/lib/screens/settings/settings_tab.dart @@ -164,6 +164,7 @@ class SettingsTab extends ConsumerWidget { SettingsItem( icon: Icons.settings_backup_restore, title: l10n.settingsBackup, + titleTrailing: BetaBadge(label: l10n.badgeBeta), subtitle: l10n.settingsBackupSubtitle, onTap: () => _navigateTo(context, const BackupRestorePage()), diff --git a/lib/widgets/settings_group.dart b/lib/widgets/settings_group.dart index effa9ab3..212020ab 100644 --- a/lib/widgets/settings_group.dart +++ b/lib/widgets/settings_group.dart @@ -49,6 +49,7 @@ class SettingsGroup extends StatelessWidget { class SettingsItem extends StatelessWidget { final IconData? icon; final String title; + final Widget? titleTrailing; final String? subtitle; final Widget? trailing; final VoidCallback? onTap; @@ -58,6 +59,7 @@ class SettingsItem extends StatelessWidget { super.key, this.icon, required this.title, + this.titleTrailing, this.subtitle, this.trailing, this.onTap, @@ -87,7 +89,21 @@ class SettingsItem extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: Theme.of(context).textTheme.bodyLarge), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Text( + title, + style: Theme.of(context).textTheme.bodyLarge, + ), + ), + if (titleTrailing != null) ...[ + const SizedBox(width: 8), + titleTrailing!, + ], + ], + ), if (subtitle != null) ...[ const SizedBox(height: 2), Text( @@ -257,3 +273,30 @@ class SettingsSectionHeader extends StatelessWidget { ); } } + +/// Small "BETA" pill, used as a [SettingsItem.titleTrailing] / +/// [SettingsSwitchItem.titleTrailing] marker for experimental features. +class BetaBadge extends StatelessWidget { + final String label; + + const BetaBadge({super.key, required this.label}); + + @override + Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + return Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: colorScheme.tertiaryContainer, + borderRadius: BorderRadius.circular(6), + ), + child: Text( + label, + style: Theme.of(context).textTheme.labelSmall?.copyWith( + color: colorScheme.onTertiaryContainer, + fontWeight: FontWeight.w700, + ), + ), + ); + } +}