feat: 发布v5.3.0正式版本,完善跨平台适配与功能优化
本次更新包含多项核心改进: 1. 新增统一跨平台导航扩展,替换原有GoRouter调用,适配鸿蒙平台路由逻辑 2. 重构状态初始化逻辑,使用Future.microtask避免BuildContext异常 3. 完善Linux桌面端支持,添加桌面文件、AppData配置与WSL构建脚本 4. 修复鸿蒙平台动画渲染异常问题,移除平台特判逻辑 5. 优化NFC配对扫描参数,精简不必要的配置项 6. 更新依赖版本与项目版本号 7. 修复Drift数据库缓存问题,移除冗余的表检测逻辑 8. 添加路由观察者日志,优化鸿蒙端路由调试体验 9. 完善签到与文章发布后的用户数据刷新逻辑 10. 删除冗余的子模块与日志文件,清理项目结构
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
// ============================================================
|
||||
// 闲言APP — 应用布局壳
|
||||
// 创建时间: 2026-04-20
|
||||
// 更新时间: 2026-05-17
|
||||
// 更新时间: 2026-05-18
|
||||
// 作用: ShellRoute 布局壳,包含底部 GlassBottomBar 导航 + 发现小红点
|
||||
// 上次更新: 鸿蒙白屏调试 — 恢复GlassBottomBar+CupertinoTabBar鸿蒙降级方案
|
||||
// 上次更新: 恢复鸿蒙端液态玻璃效果,统一使用GlassBottomBar
|
||||
// ============================================================
|
||||
|
||||
import 'package:badges/badges.dart' as badges;
|
||||
@@ -17,9 +17,12 @@ 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/inspiration/providers/chat_provider.dart';
|
||||
import '../../features/settings/providers/theme_settings_provider.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});
|
||||
@@ -32,6 +35,11 @@ class AppShell extends ConsumerWidget {
|
||||
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;
|
||||
@@ -58,8 +66,8 @@ class AppShell extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget bottomBar = _isOhos
|
||||
? _buildCupertinoNavBar(context, currentIndex, ext)
|
||||
final Widget bottomBar = (_isOhos && !liquidGlassReady)
|
||||
? _buildFallbackNavBar(context, currentIndex, ext, settings, ref)
|
||||
: GlassBottomBar(
|
||||
tabs: [
|
||||
GlassBottomBarTab(
|
||||
@@ -164,9 +172,7 @@ class AppShell extends ConsumerWidget {
|
||||
statusBarIconBrightness: ext.isDark
|
||||
? Brightness.light
|
||||
: Brightness.dark,
|
||||
statusBarBrightness: ext.isDark
|
||||
? Brightness.dark
|
||||
: Brightness.light,
|
||||
statusBarBrightness: ext.isDark ? Brightness.dark : Brightness.light,
|
||||
systemNavigationBarColor: Colors.transparent,
|
||||
systemNavigationBarIconBrightness: ext.isDark
|
||||
? Brightness.light
|
||||
@@ -192,32 +198,34 @@ class AppShell extends ConsumerWidget {
|
||||
child.goBranch(index, initialLocation: index == child.currentIndex);
|
||||
}
|
||||
|
||||
Widget _buildCupertinoNavBar(
|
||||
Widget _buildFallbackNavBar(
|
||||
BuildContext context,
|
||||
int currentIndex,
|
||||
AppThemeExtension ext,
|
||||
ThemeSettingsState settings,
|
||||
WidgetRef ref,
|
||||
) {
|
||||
return CupertinoTabBar(
|
||||
items: const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.house_fill),
|
||||
label: '闲言',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.compass_fill),
|
||||
final expressionStyle = settings.tabExpressionStyle;
|
||||
final characterId = settings.tabCharacterStyleId;
|
||||
final animIntensity = settings.animationIntensity.durationMultiplier;
|
||||
final unreadCount = ref.watch(chatProvider).unreadCount;
|
||||
|
||||
return GlassBottomNavBar(
|
||||
items: [
|
||||
const GlassBottomNavBarItem(spriteType: TabSpriteType.home, label: '闲言'),
|
||||
GlassBottomNavBarItem(
|
||||
spriteType: TabSpriteType.discover,
|
||||
label: '发现',
|
||||
badgeCount: unreadCount,
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(CupertinoIcons.person_fill),
|
||||
label: '我的',
|
||||
),
|
||||
const GlassBottomNavBarItem(spriteType: TabSpriteType.profile, label: '我的'),
|
||||
],
|
||||
currentIndex: currentIndex,
|
||||
onTap: (index) => _onTabTap(context, index),
|
||||
activeColor: ext.accent,
|
||||
backgroundColor: ext.isDark
|
||||
? const Color(0xFF1C1C1E)
|
||||
: CupertinoColors.systemBackground,
|
||||
selectedIndex: currentIndex,
|
||||
onTabSelected: (index) => _onTabTap(context, index),
|
||||
ext: ext,
|
||||
animationIntensity: animIntensity,
|
||||
expressionStyle: expressionStyle,
|
||||
characterId: characterId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
254
lib/core/layout/ohos_app_shell.dart
Normal file
254
lib/core/layout/ohos_app_shell.dart
Normal file
@@ -0,0 +1,254 @@
|
||||
/// ============================================================
|
||||
/// 闲言APP — 鸿蒙端专用布局壳
|
||||
/// 创建时间: 2026-05-18
|
||||
/// 更新时间: 2026-05-18
|
||||
/// 作用: 鸿蒙端使用 Scaffold+GlassBottomBar 替代 GoRouter+StatefulShellRoute
|
||||
/// 上次更新: 恢复液态玻璃效果+TabIconSprite精灵动画,仅阉割路由
|
||||
/// ============================================================
|
||||
///
|
||||
/// 根因: 鸿蒙端 Flutter 引擎中 MaterialApp.router + 额外包导入 = 白屏
|
||||
/// 方案: 鸿蒙端仅阉割路由(GoRouter),保留液态玻璃效果
|
||||
|
||||
import 'package:badges/badges.dart' as badges;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
|
||||
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../core/utils/interaction_animations.dart';
|
||||
import '../../core/utils/logger.dart';
|
||||
import '../../core/utils/platform_utils.dart' show OhosDeviceCapabilities;
|
||||
import '../../features/inspiration/providers/chat_provider.dart';
|
||||
import '../../features/inspiration/presentation/pages/home/inspiration_page.dart';
|
||||
import '../../features/home/presentation/home_page.dart';
|
||||
import '../../features/profile/presentation/profile_page.dart';
|
||||
import '../../features/settings/providers/theme_settings_provider.dart';
|
||||
import '../../main.dart' show liquidGlassReady;
|
||||
import '../../shared/widgets/glass_bottom_nav_bar.dart';
|
||||
import '../../shared/widgets/tab_icon_sprite.dart';
|
||||
|
||||
class OhosAppShell extends ConsumerStatefulWidget {
|
||||
const OhosAppShell({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<OhosAppShell> createState() => _OhosAppShellState();
|
||||
}
|
||||
|
||||
class _OhosAppShellState extends ConsumerState<OhosAppShell> {
|
||||
int _currentIndex = 0;
|
||||
|
||||
static const List<Widget> _tabPages = [
|
||||
HomePage(),
|
||||
InspirationPage(),
|
||||
ProfilePage(),
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
OhosDeviceCapabilities.init(context);
|
||||
|
||||
final ext = AppTheme.ext(context);
|
||||
final unreadCount = ref.watch(chatProvider).unreadCount;
|
||||
final settings = ref.watch(themeSettingsProvider);
|
||||
final expressionStyle = settings.tabExpressionStyle;
|
||||
final characterId = settings.tabCharacterStyleId;
|
||||
final animIntensity = settings.animationIntensity.durationMultiplier;
|
||||
|
||||
Log.i(
|
||||
'🟢 [OHOS] OhosAppShell.build() — currentIndex=$_currentIndex liquidGlass=$liquidGlassReady',
|
||||
);
|
||||
|
||||
final Widget bottomBar = liquidGlassReady
|
||||
? _buildGlassBottomBar(
|
||||
ext: ext,
|
||||
unreadCount: unreadCount,
|
||||
expressionStyle: expressionStyle,
|
||||
characterId: characterId,
|
||||
animIntensity: animIntensity,
|
||||
)
|
||||
: _buildFallbackNavBar(
|
||||
ext: ext,
|
||||
unreadCount: unreadCount,
|
||||
expressionStyle: expressionStyle,
|
||||
characterId: characterId,
|
||||
animIntensity: animIntensity,
|
||||
);
|
||||
|
||||
return CelebrationOverlay(
|
||||
child: AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: ext.isDark
|
||||
? Brightness.light
|
||||
: Brightness.dark,
|
||||
statusBarBrightness: ext.isDark ? Brightness.dark : Brightness.light,
|
||||
systemNavigationBarColor: Colors.transparent,
|
||||
systemNavigationBarIconBrightness: ext.isDark
|
||||
? Brightness.light
|
||||
: Brightness.dark,
|
||||
systemNavigationBarDividerColor: Colors.transparent,
|
||||
),
|
||||
child: PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
if (didPop) return;
|
||||
},
|
||||
child: Scaffold(
|
||||
extendBody: true,
|
||||
body: IndexedStack(index: _currentIndex, children: _tabPages),
|
||||
bottomNavigationBar: bottomBar,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// GPU Shader 液态玻璃底部导航栏 (LiquidGlassWidgets 可用时)
|
||||
Widget _buildGlassBottomBar({
|
||||
required AppThemeExtension ext,
|
||||
required int unreadCount,
|
||||
required TabExpressionStyleOption expressionStyle,
|
||||
required String characterId,
|
||||
required double animIntensity,
|
||||
}) {
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
return GlassBottomBar(
|
||||
tabs: [
|
||||
GlassBottomBarTab(
|
||||
label: '',
|
||||
icon: buildSpriteIcon(TabSpriteType.home, 0, '闲言'),
|
||||
activeIcon: buildSpriteIcon(TabSpriteType.home, 0, '闲言'),
|
||||
glowColor: const Color(0xFFE8E8ED),
|
||||
),
|
||||
GlassBottomBarTab(
|
||||
label: '',
|
||||
icon: _buildBadgeIcon(
|
||||
unreadCount: unreadCount,
|
||||
child: buildSpriteIcon(TabSpriteType.discover, 1, '发现'),
|
||||
),
|
||||
activeIcon: _buildBadgeIcon(
|
||||
unreadCount: unreadCount,
|
||||
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) => setState(() => _currentIndex = 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,
|
||||
);
|
||||
}
|
||||
|
||||
/// 纯Dart BackdropFilter 液态玻璃底部导航栏 (降级方案)
|
||||
Widget _buildFallbackNavBar({
|
||||
required AppThemeExtension ext,
|
||||
required int unreadCount,
|
||||
required TabExpressionStyleOption expressionStyle,
|
||||
required String characterId,
|
||||
required double animIntensity,
|
||||
}) {
|
||||
return GlassBottomNavBar(
|
||||
items: [
|
||||
const GlassBottomNavBarItem(spriteType: TabSpriteType.home, label: '闲言'),
|
||||
GlassBottomNavBarItem(
|
||||
spriteType: TabSpriteType.discover,
|
||||
label: '发现',
|
||||
badgeCount: unreadCount,
|
||||
),
|
||||
const GlassBottomNavBarItem(spriteType: TabSpriteType.profile, label: '我的'),
|
||||
],
|
||||
selectedIndex: _currentIndex,
|
||||
onTabSelected: (index) => setState(() => _currentIndex = index),
|
||||
ext: ext,
|
||||
animationIntensity: animIntensity,
|
||||
expressionStyle: expressionStyle,
|
||||
characterId: characterId,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBadgeIcon({required int unreadCount, required Widget child}) {
|
||||
if (unreadCount <= 0) return child;
|
||||
return badges.Badge(
|
||||
badgeContent: Text(
|
||||
'$unreadCount',
|
||||
style: const 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: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user