snap_wish/lib/presentation/app_widget.dart
2025-09-12 18:17:35 +08:00

283 lines
8.1 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.

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/foundation.dart';
import '../core/constants/app_constants.dart';
import '../core/theme/app_theme.dart';
import '../core/utils/logger.dart';
/// 主应用组件
/// 负责配置MaterialApp和全局设置
class AppWidget extends ConsumerWidget {
const AppWidget({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
Logger.debug('构建AppWidget');
return MaterialApp(
// 应用基础配置
title: AppConstants.appName,
debugShowCheckedModeBanner: false,
// 主题配置
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: ThemeMode.system,
// 本地化配置
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('zh', 'CN'), // 简体中文
Locale('zh', 'TW'), // 繁体中文
Locale('en', 'US'), // English
],
// 主页配置
home: const AppHomePage(),
// 导航观察者
navigatorObservers: [
_AppNavigatorObserver(),
],
// 构建器配置(用于全局错误处理)
builder: (context, child) {
// 配置文字缩放因子,确保文字大小一致性
final mediaQueryData = MediaQuery.of(context);
final textScaler = MediaQuery.of(context).textScaler;
final scaleFactor = textScaler.scale(1.0).clamp(0.8, 1.2);
return MediaQuery(
data: mediaQueryData.copyWith(
textScaler: TextScaler.linear(scaleFactor),
),
child: child ?? const SizedBox.shrink(),
);
},
// 滚动行为配置
scrollBehavior: const MaterialScrollBehavior().copyWith(
physics: const ClampingScrollPhysics(),
),
);
}
}
/// 应用主页组件
/// 作为占位符,后续会替换为实际的主页
class AppHomePage extends StatefulWidget {
const AppHomePage({super.key});
@override
State<AppHomePage> createState() => _AppHomePageState();
}
class _AppHomePageState extends State<AppHomePage> {
@override
void initState() {
super.initState();
Logger.debug('AppHomePage初始化');
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
Logger.debug('构建AppHomePage');
return Scaffold(
appBar: AppBar(
title: const Text('想拍'),
centerTitle: true,
elevation: 0,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 应用Logo占位符
Icon(
Icons.photo_library,
size: 120,
color: theme.colorScheme.primary.withOpacity(0.8),
),
const SizedBox(height: 32),
// 欢迎文字
Text(
'欢迎使用想拍',
style: theme.textTheme.headlineMedium?.copyWith(
color: theme.colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
// 副标题
Text(
'Shoot What Inspires You',
style: theme.textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.onSurface.withOpacity(0.7),
),
textAlign: TextAlign.center,
),
const SizedBox(height: 48),
// 功能说明
Text(
'从其他应用分享图片到这里,\n开始收集你的灵感吧!',
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurface.withOpacity(0.6),
),
textAlign: TextAlign.center,
),
const SizedBox(height: 48),
// 开始使用按钮
ElevatedButton.icon(
onPressed: () {
// TODO: 导航到图库页面
Logger.debug('点击开始使用按钮');
},
icon: const Icon(Icons.arrow_forward),
label: const Text('开始使用'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
),
),
],
),
),
// 底部导航栏(占位符)
bottomNavigationBar: NavigationBar(
destinations: const [
NavigationDestination(
icon: Icon(Icons.photo_library),
label: '图库',
),
NavigationDestination(
icon: Icon(Icons.folder),
label: '文件夹',
),
NavigationDestination(
icon: Icon(Icons.label),
label: '标签',
),
NavigationDestination(
icon: Icon(Icons.settings),
label: '设置',
),
],
onDestinationSelected: (index) {
Logger.debug('底部导航选择: $index');
// TODO: 实现页面切换逻辑
},
),
);
}
}
/// 导航观察者
/// 用于记录页面导航事件
class _AppNavigatorObserver extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
if (route.settings.name != null) {
Logger.debug('页面进入: ${route.settings.name}');
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
if (route.settings.name != null) {
Logger.debug('页面退出: ${route.settings.name}');
}
}
@override
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
if (route.settings.name != null) {
Logger.debug('页面移除: ${route.settings.name}');
}
}
@override
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
if (newRoute?.settings.name != null) {
Logger.debug('页面替换: ${newRoute!.settings.name}');
}
}
}
/// 应用配置混入
mixin AppConfigMixin {
/// 获取应用名称
String get appName => AppConstants.appName;
/// 获取应用版本
String get appVersion => AppConstants.appVersion;
/// 获取应用描述
String get appDescription => AppConstants.appDescription;
/// 检查是否为调试模式
bool get isDebugMode => kDebugMode;
/// 检查是否为发布模式
bool get isReleaseMode => kReleaseMode;
/// 获取当前时间戳
int get currentTimestamp => DateTime.now().millisecondsSinceEpoch;
/// 格式化文件大小
String formatFileSize(int bytes) {
if (bytes <= 0) return '0 B';
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
int unitIndex = 0;
double size = bytes.toDouble();
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return '${size.toStringAsFixed(2)} ${units[unitIndex]}';
}
/// 格式化日期
String formatDate(DateTime date) {
return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
}
/// 计算时间差(友好显示)
String formatTimeDifference(DateTime from, DateTime to) {
final difference = to.difference(from);
if (difference.inDays > 0) {
return '${difference.inDays}天前';
} else if (difference.inHours > 0) {
return '${difference.inHours}小时前';
} else if (difference.inMinutes > 0) {
return '${difference.inMinutes}分钟前';
} else {
return '刚刚';
}
}
}
/// 应用混入
/// 组合所有应用相关的混入
mixin AppMixin on AppConfigMixin, LoggerMixin {
// 可以在这里添加更多通用的应用功能
}