From 7cabfa2e05a47e4a2a47303be7841a1d3f1623d0 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Wed, 11 Mar 2026 15:25:33 +0800 Subject: [PATCH] Refine sidebar language toggle layout --- lib/i18n/app_language.dart | 5 + lib/models/app_models.dart | 2 +- lib/widgets/sidebar_navigation.dart | 181 ++++++++++++++++++++-------- 3 files changed, 135 insertions(+), 53 deletions(-) diff --git a/lib/i18n/app_language.dart b/lib/i18n/app_language.dart index acd81cdb..43da450a 100644 --- a/lib/i18n/app_language.dart +++ b/lib/i18n/app_language.dart @@ -8,6 +8,11 @@ extension AppLanguageCopy on AppLanguage { AppLanguage.en => 'en', }; + String get compactLabel => switch (this) { + AppLanguage.zh => '中', + AppLanguage.en => 'EN', + }; + String get buttonLabel => switch (this) { AppLanguage.zh => '中 / EN', AppLanguage.en => 'EN / 中', diff --git a/lib/models/app_models.dart b/lib/models/app_models.dart index e4aa26f8..6984a719 100644 --- a/lib/models/app_models.dart +++ b/lib/models/app_models.dart @@ -126,7 +126,7 @@ extension SettingsTabCopy on SettingsTab { String get label => switch (this) { SettingsTab.general => appText('通用', 'General'), SettingsTab.workspace => appText('工作区', 'Workspace'), - SettingsTab.gateway => appText('网关', 'Gateway'), + SettingsTab.gateway => appText('集成', 'Integrations'), SettingsTab.appearance => appText('外观', 'Appearance'), SettingsTab.diagnostics => appText('诊断', 'Diagnostics'), SettingsTab.experimental => appText('实验特性', 'Experimental'), diff --git a/lib/widgets/sidebar_navigation.dart b/lib/widgets/sidebar_navigation.dart index aba5ab85..11017651 100644 --- a/lib/widgets/sidebar_navigation.dart +++ b/lib/widgets/sidebar_navigation.dart @@ -270,18 +270,14 @@ class SidebarFooter extends StatelessWidget { @override Widget build(BuildContext context) { + final palette = context.palette; final languageButton = Tooltip( message: appText('切换语言', 'Switch language'), - child: isCollapsed - ? IconButton( - onPressed: onToggleLanguage, - icon: const Icon(Icons.translate_rounded), - ) - : OutlinedButton.icon( - onPressed: onToggleLanguage, - icon: const Icon(Icons.translate_rounded, size: 18), - label: Text(appLanguage.buttonLabel), - ), + child: _SidebarLanguageButton( + appLanguage: appLanguage, + compact: isCollapsed, + onPressed: onToggleLanguage, + ), ); final themeButton = Tooltip( @@ -339,53 +335,134 @@ class SidebarFooter extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [themeButton, settingsButton, collapseButton], ), - if (!isCollapsed) ...[ - const SizedBox(height: 8), - SizedBox(width: double.infinity, child: languageButton), - ], const SizedBox(height: 8), - Tooltip( - message: isCollapsed ? appText('账号', 'Account') : '', - child: InkWell( - borderRadius: BorderRadius.circular(18), - onTap: onOpenAccount, - child: Container( - width: double.infinity, - padding: EdgeInsets.symmetric( - horizontal: isCollapsed ? 0 : 12, - vertical: 10, + if (isCollapsed) + Tooltip( + message: appText('账号', 'Account'), + child: InkWell( + borderRadius: BorderRadius.circular(18), + onTap: onOpenAccount, + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 10), + decoration: BoxDecoration( + color: accountSelected + ? palette.accentMuted + : palette.surfaceSecondary, + borderRadius: BorderRadius.circular(14), + border: Border.all(color: palette.strokeSoft), + ), + child: const Icon(Icons.account_circle_rounded), ), - decoration: BoxDecoration( - color: accountSelected - ? context.palette.accentMuted - : Colors.transparent, - borderRadius: BorderRadius.circular(12), - ), - child: isCollapsed - ? const Icon(Icons.account_circle_rounded) - : Row( - children: [ - const CircleAvatar(radius: 16, child: Text('H')), - const SizedBox(width: 10), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Haitao Pan', - style: Theme.of(context).textTheme.labelLarge, - ), - Text( - appText('账号', 'Account'), - style: Theme.of(context).textTheme.bodySmall, - ), - ], - ), - ], - ), ), + ) + else + Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + languageButton, + const SizedBox(width: 10), + Expanded( + child: Tooltip( + message: '', + child: InkWell( + borderRadius: BorderRadius.circular(18), + onTap: onOpenAccount, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 10, + ), + decoration: BoxDecoration( + color: accountSelected + ? palette.accentMuted + : palette.surfaceSecondary, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: palette.strokeSoft), + ), + child: Row( + children: [ + const CircleAvatar(radius: 18, child: Text('H')), + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Haitao Pan', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.labelLarge, + ), + Text( + appText('账号', 'Account'), + style: Theme.of(context).textTheme.bodySmall, + ), + ], + ), + ), + ], + ), + ), + ), + ), + ), + ], ), - ), ], ); } } + +class _SidebarLanguageButton extends StatefulWidget { + const _SidebarLanguageButton({ + required this.appLanguage, + required this.compact, + required this.onPressed, + }); + + final AppLanguage appLanguage; + final bool compact; + final VoidCallback onPressed; + + @override + State<_SidebarLanguageButton> createState() => _SidebarLanguageButtonState(); +} + +class _SidebarLanguageButtonState extends State<_SidebarLanguageButton> { + bool _hovered = false; + + @override + Widget build(BuildContext context) { + final palette = context.palette; + final size = widget.compact ? 44.0 : 58.0; + + return MouseRegion( + onEnter: (_) => setState(() => _hovered = true), + onExit: (_) => setState(() => _hovered = false), + child: InkWell( + borderRadius: BorderRadius.circular(18), + onTap: widget.onPressed, + child: AnimatedContainer( + duration: const Duration(milliseconds: 160), + width: size, + height: size, + alignment: Alignment.center, + decoration: BoxDecoration( + color: _hovered ? palette.hover : palette.surfaceSecondary, + borderRadius: BorderRadius.circular(18), + border: Border.all(color: palette.strokeSoft), + ), + child: Text( + widget.appLanguage.compactLabel, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: palette.textPrimary, + fontWeight: FontWeight.w700, + ), + ), + ), + ), + ); + } +}