Files
xianyan/lib/core/layout/app_shell.dart
Developer 85d856f0ed chore: 完成多模块迭代优化与依赖更新
本次提交包含多项更新:
1. 更新file_picker依赖到11.0.0-ohos.1版本
2. 清理SecureStorage、Catcher2配置冗余代码
3. 优化鸿蒙系统下HomeWidget调用方式
4. 重构编辑器导航栏图标与页面路由引用
5. 修复边框样式、简化空值判断逻辑
6. 移除冗余系统UI样式配置
7. 新增共享组件导出与自适应返回按钮
8. 批量替换路由引用为app_routes
9. 标记过时通知服务并补充注释
10. 新增引导页扫一扫功能卡片
11. 完善沉浸式状态栏配置逻辑
12. 为大量页面添加统一自适应返回按钮
2026-05-22 23:14:38 +08:00

219 lines
8.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================
// 闲言APP — 应用布局壳
// 创建时间: 2026-04-20
// 更新时间: 2026-05-18
// 作用: ShellRoute 布局壳,包含底部 GlassBottomBar 导航 + 发现小红点
// 上次更新: 恢复鸿蒙端液态玻璃效果统一使用GlassBottomBar
// ============================================================
import 'package:badges/badges.dart' as badges;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:xianyan/core/utils/platform_utils.dart' as pu;
import 'package:go_router/go_router.dart';
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
import '../theme/app_theme.dart';
import '../utils/interaction_animations.dart';
import '../utils/logger.dart';
import '../../features/tool_center/inspiration/providers/chat_provider.dart';
import '../../features/mine/settings/providers/theme_settings_provider.dart';
import '../../l10n/translations.dart';
import '../../shared/widgets/tab_icon_sprite.dart';
import '../../main.dart' show liquidGlassReady;
import '../../shared/widgets/glass_bottom_nav_bar.dart';
class AppShell extends ConsumerWidget {
const AppShell({super.key, required this.child});
final StatefulNavigationShell child;
static bool get _isOhos => pu.isOhos;
@override
Widget build(BuildContext context, WidgetRef ref) {
final ext = AppTheme.ext(context);
final int currentIndex = child.currentIndex;
if (_isOhos) {
Log.i(
'🟢 [OHOS] AppShell.build() — currentIndex=$currentIndex isDark=${ext.isDark}',
);
}
final unreadCount = ref.watch(chatProvider).unreadCount;
final settings = ref.watch(themeSettingsProvider);
final expressionStyle = settings.tabExpressionStyle;
final characterId = settings.tabCharacterStyleId;
final animIntensity = settings.animationIntensity.durationMultiplier;
int adjacentFor(int index) {
if (index == currentIndex) return 0;
if (index < currentIndex) return -1;
return 1;
}
Widget buildSpriteIcon(TabSpriteType type, int index, String label) {
return TabIconSprite(
type: type,
label: label,
isSelected: index == currentIndex,
adjacentDirection: adjacentFor(index),
animationIntensity: animIntensity,
characterId: characterId,
eyeScale: expressionStyle.eyeScale,
mouthCurve: expressionStyle.mouthCurve,
bounceMultiplier: expressionStyle.bounceMultiplier,
);
}
final Widget bottomBar = (_isOhos && !liquidGlassReady)
? _buildFallbackNavBar(context, currentIndex, ext, settings, ref)
: GlassBottomBar(
tabs: [
GlassBottomBarTab(
label: '',
icon: buildSpriteIcon(TabSpriteType.home, 0, '闲言'),
activeIcon: buildSpriteIcon(TabSpriteType.home, 0, '闲言'),
glowColor: const Color(0xFFE8E8ED),
),
GlassBottomBarTab(
label: '',
icon: badges.Badge(
showBadge: unreadCount > 0,
badgeContent: const Text(
'',
style: TextStyle(
color: Colors.white,
fontSize: 9,
fontWeight: FontWeight.bold,
),
),
badgeStyle: const badges.BadgeStyle(
badgeColor: CupertinoColors.systemRed,
padding: EdgeInsets.all(3),
),
position: badges.BadgePosition.topEnd(top: -4, end: -6),
child: buildSpriteIcon(TabSpriteType.discover, 1, '发现'),
),
activeIcon: badges.Badge(
showBadge: unreadCount > 0,
badgeContent: const Text(
'',
style: TextStyle(
color: Colors.white,
fontSize: 9,
fontWeight: FontWeight.bold,
),
),
badgeStyle: const badges.BadgeStyle(
badgeColor: CupertinoColors.systemRed,
padding: EdgeInsets.all(3),
),
position: badges.BadgePosition.topEnd(top: -4, end: -6),
child: buildSpriteIcon(TabSpriteType.discover, 1, '发现'),
),
glowColor: const Color(0xFFE8E8ED),
),
GlassBottomBarTab(
label: '',
icon: buildSpriteIcon(TabSpriteType.profile, 2, '我的'),
activeIcon: buildSpriteIcon(TabSpriteType.profile, 2, '我的'),
glowColor: const Color(0xFFE8E8ED),
),
],
selectedIndex: currentIndex,
onTabSelected: (index) => _onTabTap(context, index),
quality: GlassQuality.premium,
selectedIconColor: ext.isDark ? Colors.white : ext.accent,
unselectedIconColor: ext.isDark
? Colors.white38
: const Color(0xFFAEAEB2),
barHeight: 68,
barBorderRadius: 34,
horizontalPadding: 16,
verticalPadding: 16,
indicatorColor: ext.isDark
? Colors.white.withValues(alpha: 0.08)
: Colors.black.withValues(alpha: 0.04),
indicatorSettings: LiquidGlassSettings(
thickness: 40,
blur: 25,
refractiveIndex: 1.8,
chromaticAberration: 1.2,
lightIntensity: 3.5,
ambientStrength: 1.2,
glassColor: ext.isDark
? const Color.from(alpha: 0.18, red: 1, green: 1, blue: 1)
: const Color.from(alpha: 0.12, red: 1, green: 1, blue: 1),
),
glassSettings: LiquidGlassSettings(
thickness: 30,
blur: 1.5,
refractiveIndex: 1.5,
chromaticAberration: 0.8,
lightIntensity: 1.2,
saturation: 1.0,
ambientStrength: 0.6,
glassColor: ext.isDark
? const Color.from(alpha: 0.08, red: 1, green: 1, blue: 1)
: const Color.from(alpha: 0.05, red: 1, green: 1, blue: 1),
),
magnification: 1.12,
innerBlur: 1.5,
glowOpacity: 0.4,
glowBlurRadius: 24,
glowSpreadRadius: 4,
);
return CelebrationOverlay(
child: PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, _) {
if (didPop) return;
},
child: Scaffold(
extendBody: true,
body: Stack(children: [child]),
bottomNavigationBar: bottomBar,
),
),
);
}
void _onTabTap(BuildContext context, int index) {
child.goBranch(index, initialLocation: index == child.currentIndex);
}
Widget _buildFallbackNavBar(
BuildContext context,
int currentIndex,
AppThemeExtension ext,
ThemeSettingsState settings,
WidgetRef ref,
) {
final expressionStyle = settings.tabExpressionStyle;
final characterId = settings.tabCharacterStyleId;
final animIntensity = settings.animationIntensity.durationMultiplier;
final unreadCount = ref.watch(chatProvider).unreadCount;
final t = ref.watch(translationsProvider);
return GlassBottomNavBar(
items: [
GlassBottomNavBarItem(spriteType: TabSpriteType.home, label: t.navHome),
GlassBottomNavBarItem(
spriteType: TabSpriteType.discover,
label: t.navDiscover,
badgeCount: unreadCount,
),
GlassBottomNavBarItem(spriteType: TabSpriteType.profile, label: t.navProfile),
],
selectedIndex: currentIndex,
onTabSelected: (index) => _onTabTap(context, index),
ext: ext,
animationIntensity: animIntensity,
expressionStyle: expressionStyle,
characterId: characterId,
);
}
}