diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 7aeb05c..386d34a 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -27,7 +27,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "1.8.22" apply false + id("org.jetbrains.kotlin.android") version "1.9.22" apply false } include(":app") diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index ebe193c..3270721 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -1,15 +1,13 @@ /// 应用信息 class AppConfig { // 网络配置 - // http://192.168.1.3:8100 - // http://14.103.235.151:81/food-service - // static const String baseApiUrl = "http://14.103.235.151:81/food-service"; - // static const String baseApiUrl = "http://192.168.1.3:8100"; - static const String baseApiUrl = "https://cxx0822.iepose.cn/food-api"; // static const String baseApiUrl = "http://192.168.1.4:8083"; - // static const String baseApiUrl = "http://192.168.1.103:8083"; - static const String rustfsIp = '14.103.235.151'; - static const String rustfsFileUrl = 'http://14.103.235.151:9100'; + static const String baseApiUrl = "https://cxx0822.s.3q.hair/food-api"; + static const String rustfsIp = '43.248.188.28'; + static const int rustfsPort = 23125; + static const String rustfsAccessKey = 'sZuAg1WCo5i4kD936Tqh'; + static const String rustfsSecretKey = 'g2fEyk6bslGrHepBvjhu0OLNF4qCRziPJIx1KAS8'; + static const String rustfsFileUrl = 'http://$rustfsIp:$rustfsPort'; static const String bucketName = 'food'; static const String imageBaseUrl = '$rustfsFileUrl/$bucketName/'; // static const String imageBaseUrl = '$baseApiUrl/'; diff --git a/lib/layout/app_navbar.dart b/lib/layout/app_navbar.dart deleted file mode 100644 index e6727ff..0000000 --- a/lib/layout/app_navbar.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:flutter/material.dart'; -import 'menu.dart'; - -class AppNavbar extends StatefulWidget { - final int currentPageIndex; - final Function(int) onTapNavbarItem; - - const AppNavbar({ - super.key, - required this.currentPageIndex, - required this.onTapNavbarItem, - }); - - @override - State createState() => AppNavbarState(); -} - -class AppNavbarState extends State { - - @override - Widget build(BuildContext context) { - final colors = Theme.of(context).colorScheme; - - return BottomNavigationBar( - currentIndex: widget.currentPageIndex, - onTap: widget.onTapNavbarItem, - items: bottomNavItems, - type: BottomNavigationBarType.fixed, - selectedItemColor: colors.primary, - unselectedItemColor: colors.onSurface.withAlpha(150), - showSelectedLabels: true, - showUnselectedLabels: true, - backgroundColor: colors.surface, - elevation: 8, - ); - } -} diff --git a/lib/layout/menu.dart b/lib/layout/menu.dart deleted file mode 100644 index 9890044..0000000 --- a/lib/layout/menu.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:food_hub_app/models/layout.dart'; -import 'package:food_hub_app/views/moment.dart'; -import 'package:food_hub_app/views/profile.dart'; -import 'package:food_hub_app/views/record.dart'; -import 'package:food_hub_app/views/stats.dart'; - -final List pages = [ - PageInfo( - label: "记录", - icon: Icons.home_outlined, - activeIcon: Icons.home, - page: RecordPage(), - ), - PageInfo( - label: "统计", - icon: Icons.pie_chart_outline, - activeIcon: Icons.pie_chart, - page: StatsPage(), - ), - PageInfo( - label: "朋友圈", - icon: Icons.group_outlined, - activeIcon: Icons.group, - page: MomentPage(), - ), - PageInfo( - label: "我的", - icon: Icons.account_circle_outlined, - activeIcon: Icons.account_circle, - page: ProfilePage(), - ), -]; - -final List bottomNavItems = - pages.map((page) { - return BottomNavigationBarItem(icon: Icon(page.icon), label: page.label); - }).toList(); - -final List tabPages = pages.map((item) => item.page).toList(); diff --git a/lib/main.dart b/lib/main.dart index 29e1cd3..d23dc0d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,24 +16,30 @@ import 'package:food_hub_app/views/recipe_form.dart'; import 'package:food_hub_app/views/record_form.dart'; import 'package:food_hub_app/views/recipe_detail.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; +import 'package:liquid_glass_widgets/liquid_glass_setup.dart'; import 'package:provider/provider.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - + FormBuilderLocalizations.delegate.load(const Locale('zh', 'CN')); await SPUtil.init(); - await initLogger(); - + // await initLogger(); + + // 预编译 shader,防止首帧白闪 + await LiquidGlassWidgets.initialize(); + // wrap() 安装无障碍桥接、全局主题、自适应质量 runApp( - MultiProvider( - providers: [ - ChangeNotifierProvider(create: (context) => FoodProvider()), - ChangeNotifierProvider(create: (context) => ThemeProvider()), - ChangeNotifierProvider(create: (context) => UserProvider()), - ChangeNotifierProvider(create: (context) => AppProvider()), - ], - child: MyApp(), + LiquidGlassWidgets.wrap( + child: MultiProvider( + providers: [ + ChangeNotifierProvider(create: (context) => FoodProvider()), + ChangeNotifierProvider(create: (context) => ThemeProvider()), + ChangeNotifierProvider(create: (context) => UserProvider()), + ChangeNotifierProvider(create: (context) => AppProvider()), + ], + child: const MyApp(), + ), ), ); } @@ -45,10 +51,52 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { final themeProvider = context.watch(); + final brightness = MediaQuery.of(context).platformBrightness; + themeProvider.isDarkMode = brightness == Brightness.dark; return MaterialApp( debugShowCheckedModeBanner: false, - theme: themeProvider.currentThemeData, + theme: ThemeData( + scaffoldBackgroundColor: const Color(0xFFFAF6F0), + colorScheme: ColorScheme( + brightness: Brightness.light, + primary: const Color(0xFFE89F71), + secondary: const Color(0xFFE89F71), + surface: const Color(0xFFFFFFFF), + error: const Color(0xFFE76F51), + + onPrimary: Colors.white, + onSecondary: Colors.white, + onSurface: const Color(0xFF3A332C), + onError: Colors.white, + ), + textTheme: TextTheme( + titleLarge: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: const Color(0xFF3A332C), + ), + titleMedium: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: const Color(0xFF3A332C), + ), + bodyLarge: TextStyle( + fontSize: 15, + color: const Color(0xFF3A332C), + ), + bodyMedium: TextStyle( + fontSize: 14, + color: const Color(0xFF8C8379), + ), + bodySmall: TextStyle( + fontSize: 12, + color: const Color(0xFF8C8379), + ), + ), + fontFamily: 'CustomFont', + useMaterial3: true, + ), supportedLocales: const [ Locale('en', 'US'), // 英语 Locale('zh', 'CN'), // 中文 @@ -71,13 +119,13 @@ class MyApp extends StatelessWidget { home: LoginPage(), routes: { '/home': (context) => HomePage(), - '/recordForm': (context) => RecordFormPage(), + '/recordForm': (context) => RecordForm(), '/recipeForm': (context) => RecipeFormPage(), '/recipeDetail': (context) => RecipeDetailPage(), - '/momentForm': (context) => MomentFormPage(), + '/momentForm': (context) => MomentForm(), '/moment': (context) => MomentPage(), '/momentUser': (context) => MomentUserPage(), - '/ProfileUser': (context) => ProfileUserPage() + '/ProfileUser': (context) => ProfileUserPage(), }, ); } diff --git a/lib/utils/minio_utils.dart b/lib/utils/minio_utils.dart new file mode 100644 index 0000000..7875642 --- /dev/null +++ b/lib/utils/minio_utils.dart @@ -0,0 +1,43 @@ +import 'package:file_picker/file_picker.dart'; +import 'package:flutter_common/utils/file_utils.dart'; +import 'package:food_hub_app/config/app_config.dart'; +import 'package:minio/io.dart'; +import 'package:minio/minio.dart'; + + +class MinIOHelper { + static final MinIOHelper _instance = MinIOHelper._internal(); + + factory MinIOHelper() => _instance; + + final String ip = AppConfig.rustfsIp; + + MinIOHelper._internal() { + _minio = Minio( + endPoint: AppConfig.rustfsIp, + port: AppConfig.rustfsPort, + accessKey: AppConfig.rustfsAccessKey, + secretKey: AppConfig.rustfsSecretKey, + useSSL: false, + ); + } + + late Minio _minio; + + Future uploadFile({ + required PlatformFile file, + required String bucketName, + Function(double)? onProgress, + }) async { + try { + String hashName = await generateMD5HashName(file.path!); + String fileName = '$hashName${getFileExtension(file.name)}'; + + await _minio.fPutObject(bucketName, fileName, file.path!); + + return fileName; + } catch (e) { + throw Exception('文件上传失败: $e'); + } + } +} diff --git a/lib/views/home.dart b/lib/views/home.dart index 5ecbcc6..6dc3da7 100644 --- a/lib/views/home.dart +++ b/lib/views/home.dart @@ -1,8 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:food_hub_app/layout/app_actions.dart'; -import 'package:food_hub_app/layout/app_drawer.dart'; -import 'package:food_hub_app/layout/app_navbar.dart'; -import 'package:food_hub_app/layout/menu.dart'; +import 'package:food_hub_app/views/profile.dart'; +import 'package:food_hub_app/views/record.dart'; +import 'package:food_hub_app/views/stats.dart'; +import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; +import 'package:liquid_glass_widgets/widgets/shared/glass_page.dart'; +import 'package:liquid_glass_widgets/widgets/surfaces/glass_app_bar.dart'; +import 'package:liquid_glass_widgets/widgets/surfaces/glass_bottom_bar.dart'; +import 'package:liquid_glass_widgets/widgets/surfaces/glass_scaffold.dart'; + +import 'moment.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @@ -14,38 +20,52 @@ class HomePage extends StatefulWidget { class _HomePage extends State { int _currentIndex = 0; + final _pages = [ + const RecordPage(), + const StatsPage(), + const MomentPage(), + const ProfilePage(), + ]; + @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - centerTitle: true, - title: Text('食光集', style: TextStyle(color: Colors.white)), - backgroundColor: Theme.of(context).colorScheme.primary, - leading: Builder( - builder: (context) { - return IconButton( - icon: const Icon(Icons.menu), - color: Colors.white, - onPressed: () => Scaffold.of(context).openDrawer(), - ); - }, + final colors = Theme.of(context).colorScheme; + + return GlassScaffold( + statusBarStyle: GlassStatusBarStyle.auto, + bottomBar: GlassBottomBar( + settings: LiquidGlassSettings( + glassColor: colors.surface ), - actions: [AppActions(pageIndex: _currentIndex)], - ), - // backgroundColor: Color(0xFFF5F5F5), - drawer: AppDrawer(), - body: Padding( - padding: EdgeInsets.all(10), - child: tabPages[_currentIndex], - ), - bottomNavigationBar: AppNavbar( - currentPageIndex: _currentIndex, - onTapNavbarItem: (index) { - setState(() { - _currentIndex = index; - }); - }, + selectedIndex: _currentIndex, + onTabSelected: (i) => setState(() => _currentIndex = i), + indicatorColor: colors.primary, + selectedIconColor: colors.surface, + unselectedIconColor: Color(0xFF000000), + tabs: const [ + GlassBottomBarTab( + icon: Icon(Icons.home_outlined), + activeIcon: Icon(Icons.home), + label: '记录', + ), + GlassBottomBarTab( + icon: Icon(Icons.pie_chart_outline), + activeIcon: Icon(Icons.pie_chart), + label: '统计', + ), + GlassBottomBarTab( + icon: Icon(Icons.group_outlined), + activeIcon: Icon(Icons.group), + label: '朋友圈', + ), + GlassBottomBarTab( + icon: Icon(Icons.account_circle_outlined), + activeIcon: Icon(Icons.account_circle), + label: '我的', + ), + ], ), + body: _pages[_currentIndex], ); } } diff --git a/lib/views/login.dart b/lib/views/login.dart index fc6b2c4..af40d2b 100644 --- a/lib/views/login.dart +++ b/lib/views/login.dart @@ -83,7 +83,7 @@ class _LoginPage extends State { handleRememberState(); handleTokenState(session.saToken.tokenValue); handleUserInfo(session.userInfo); - + LoadingDialog.hide(context); Navigator.pushNamed(context, '/home'); } catch (e) { @@ -104,12 +104,12 @@ class _LoginPage extends State { key: _formKey, child: Column( children: [ - Expanded(child: buildLoginForm()), + Expanded(child: buildLoginForm(context)), Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 50), child: Column( children: [ - buildOtherLoginText(), + buildOtherLoginText(context), const SizedBox(height: 15), buildOtherMethod(context), const SizedBox(height: 20), @@ -131,29 +131,29 @@ class _LoginPage extends State { ); } - Widget buildLoginForm() { + Widget buildLoginForm(BuildContext context) { return ListView( padding: const EdgeInsets.symmetric(horizontal: 20), children: [ const SizedBox(height: kToolbarHeight), buildTitle(), const SizedBox(height: 60), - buildUsernameTextField(), + buildUsernameTextField(context), const SizedBox(height: 20), - buildPasswordTextField(), + buildPasswordTextField(context), const SizedBox(height: 10), - buildRememberPasswordCheckbox(), + buildRememberPasswordCheckbox(context), const SizedBox(height: 20), - buildLoginButton(), + buildLoginButton(context), ], ); } - Widget buildUsernameTextField() { + Widget buildUsernameTextField(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - formLabelText(labelText: "账号:"), + Text("账号:", style: Theme.of(context).textTheme.bodyLarge), const SizedBox(height: 10), FormBuilderTextField( name: 'username', @@ -171,11 +171,11 @@ class _LoginPage extends State { ); } - Widget buildPasswordTextField() { + Widget buildPasswordTextField(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - formLabelText(labelText: "密码:"), + Text("密码:", style: Theme.of(context).textTheme.bodyLarge), const SizedBox(height: 10), FormBuilderTextField( name: 'password', @@ -205,7 +205,7 @@ class _LoginPage extends State { ); } - Widget buildRememberPasswordCheckbox() { + Widget buildRememberPasswordCheckbox(BuildContext context) { return Row( children: [ Checkbox( @@ -218,12 +218,12 @@ class _LoginPage extends State { }); }, ), - const Text('记住密码', style: TextStyle(color: Colors.grey, fontSize: 14)), + Text('记住密码', style: Theme.of(context).textTheme.bodyMedium), ], ); } - Widget buildLoginButton() { + Widget buildLoginButton(BuildContext context) { return SizedBox( height: 45, width: double.infinity, @@ -243,23 +243,20 @@ class _LoginPage extends State { ); } - Widget buildOtherLoginText() { + Widget buildOtherLoginText(BuildContext context) { return Row( children: [ Expanded(child: Divider(color: Colors.grey[300], thickness: 1)), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), - child: Text( - '其他方式登录', - style: TextStyle(color: Colors.grey, fontSize: 14), - ), + child: Text('其他方式登录', style: Theme.of(context).textTheme.bodyMedium), ), Expanded(child: Divider(color: Colors.grey[300], thickness: 1)), ], ); } - Widget buildOtherMethod(context) { + Widget buildOtherMethod(BuildContext context) { return OverflowBar( alignment: MainAxisAlignment.center, children: @@ -292,16 +289,19 @@ class _LoginPage extends State { ); } - Widget buildRegisterText(context) { + Widget buildRegisterText(BuildContext context) { return Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Text('没有账号?', style: TextStyle(fontSize: 18)), + Text('没有账号?', style: Theme.of(context).textTheme.bodyMedium), GestureDetector( - child: const Text( + child: Text( '点击注册', - style: TextStyle(fontSize: 18, color: Colors.green), + style: TextStyle( + fontSize: 14, + color: Theme.of(context).colorScheme.primary, + ), ), onTap: () { print("点击注册"); diff --git a/lib/views/moment.dart b/lib/views/moment.dart index 6e48a39..9a63a56 100644 --- a/lib/views/moment.dart +++ b/lib/views/moment.dart @@ -59,8 +59,8 @@ class _MomentPageState extends State { } void _onScroll() { - // 当滚动距离超过300时显示返回顶部按钮 - if (_scrollController.offset > 300) { + // 当滚动距离超过时显示返回顶部按钮 + if (_scrollController.offset > 100) { if (!_showScrollToTop) { setState(() { _showScrollToTop = true; @@ -99,26 +99,38 @@ class _MomentPageState extends State { } // 有数据时显示列表 - return Stack( - children: [ - buildEasyRefresh( - freshController: _freshController, - onRefresh: _onRefresh, - onLoad: _onLoad, - body: Stack( - children: [ - if (provider.isLoading) - buildLoadingIndicator() - else - _buildMomentList(provider), - ], - ), - ), + return Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + title: Text('朋友圈', style: Theme.of(context).textTheme.titleLarge), + centerTitle: true, + automaticallyImplyLeading: false, + ), + body: Padding( + padding: EdgeInsetsGeometry.all(10), + child: Stack( + children: [ + buildEasyRefresh( + freshController: _freshController, + onRefresh: _onRefresh, + onLoad: _onLoad, + body: Stack( + children: [ + if (provider.isLoading) + buildLoadingIndicator() + else + _buildMomentList(provider), + ], + ), + ), - // 返回顶部按钮 - if (_showScrollToTop) - buildScrollToTop(context: context, scrollToTop: _scrollToTop), - ], + // 返回顶部按钮 + if (_showScrollToTop) + buildScrollToTop(context: context, scrollToTop: _scrollToTop), + ], + ), + ), ); } } diff --git a/lib/views/moment_form.dart b/lib/views/moment_form.dart index 5e14117..5ec4aa3 100644 --- a/lib/views/moment_form.dart +++ b/lib/views/moment_form.dart @@ -1,26 +1,27 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_common/utils/log_utils.dart'; -import 'package:flutter_common/utils/minio_utils.dart'; import 'package:flutter_common/utils/toast_util.dart'; -import 'package:flutter_common/widget/common_widget.dart'; import 'package:flutter_common/widget/dialog_widget.dart'; import 'package:flutter_common/widget/loading_widget.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:food_hub_app/config/app_config.dart'; import 'package:food_hub_app/provider/food_provider.dart'; +import 'package:food_hub_app/utils/minio_utils.dart'; import 'package:food_hub_app/widgets/common/form.dart'; import 'package:food_hub_app/widgets/common/image.dart'; +import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; +import 'package:liquid_glass_widgets/widgets/containers/glass_card.dart'; import 'package:provider/provider.dart'; -class MomentFormPage extends StatefulWidget { - const MomentFormPage({super.key}); +class MomentForm extends StatefulWidget { + const MomentForm({super.key}); @override - State createState() => _MomentFormPageState(); + State createState() => _MomentFormState(); } -class _MomentFormPageState extends State { +class _MomentFormState extends State { final _formKey = GlobalKey(); final _focusNode = FocusNode(); static const String _contentField = 'content'; @@ -34,8 +35,8 @@ class _MomentFormPageState extends State { name: _contentField, initialValue: provider.momentFormItem.content, focusNode: _focusNode, - maxLines: 5, - minLines: 3, + maxLines: 8, + minLines: 5, maxLength: maxContentLength, buildCounter: ( context, { @@ -75,10 +76,10 @@ class _MomentFormPageState extends State { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, + crossAxisCount: 2, crossAxisSpacing: 8, mainAxisSpacing: 8, - childAspectRatio: 4/3, + childAspectRatio: 4 / 3, ), itemCount: totalItems, itemBuilder: (context, index) { @@ -111,7 +112,11 @@ class _MomentFormPageState extends State { _buildContentField(provider), const SizedBox(height: 8), - buildFormLabel(context: context, text: '上传图片(最多9张)', isRequired: false), + buildFormLabel( + context: context, + text: '上传图片(最多9张)', + isRequired: false, + ), const SizedBox(height: 8), _buildImageField(provider), const SizedBox(height: 8), @@ -146,24 +151,27 @@ class _MomentFormPageState extends State { if (result != null) { // 限制选择数量 final filesToUpload = result.files.take(remainingCount).toList(); - LoadingDialog.show(context, message: '上传中'); + + try { + final newImageUrls = []; + // 逐个上传图片 + for (final file in filesToUpload) { + final fileName = await MinIOHelper().uploadFile( + bucketName: AppConfig.bucketName, + file: file, + ); + logger.i('图片名称:$fileName'); + newImageUrls.add(fileName); + } - final newImageUrls = []; - - // 逐个上传图片 - for (final file in filesToUpload) { - final fileName = await MinIOHelper().uploadFile( - bucketName: AppConfig.bucketName, - file: file, - ); - logger.i('图片名称:$fileName'); - newImageUrls.add(fileName); + // 更新图片列表 + provider.addMomentFormImage(newImageUrls); + } catch (e) { + ToastUtil.error(e.toString()); + } finally { + LoadingDialog.hide(context); } - - // 更新图片列表 - LoadingDialog.hide(context); - provider.addMomentFormImage(newImageUrls); } } @@ -173,7 +181,7 @@ class _MomentFormPageState extends State { } /// 提交表单 - void _submitForm(FoodProvider provider) async{ + void _submitForm(FoodProvider provider) async { if (_formKey.currentState?.saveAndValidate() ?? false) { LoadingDialog.show(context, message: '提交中'); final result = await provider.handleMoment(); @@ -205,24 +213,17 @@ class _MomentFormPageState extends State { @override Widget build(BuildContext context) { - final colors = Theme.of(context).colorScheme; final provider = context.watch(); - final String title = provider.isEditing ? '编辑朋友圈' : '新增朋友圈'; - - return Scaffold( - appBar: AppBar( - title: Text(title, style: const TextStyle(color: Colors.white)), - backgroundColor: colors.primary, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () => Navigator.pop(context), - ), - ), - body: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(10), - child: CommonCard(child: _buildFormBuilder(provider)), + return SingleChildScrollView( + child: Padding( + padding: EdgeInsets.all(10), + child: GlassCard( + useOwnLayer: true, + settings: LiquidGlassSettings( + glassColor: Theme.of(context).scaffoldBackgroundColor, + ), + child: _buildFormBuilder(provider), ), ), ); diff --git a/lib/views/profile.dart b/lib/views/profile.dart index 87fb3b0..d602c0a 100644 --- a/lib/views/profile.dart +++ b/lib/views/profile.dart @@ -5,6 +5,8 @@ import 'package:flutter_common/widget/dialog_widget.dart'; import 'package:food_hub_app/provider/app_provider.dart'; import 'package:food_hub_app/provider/user_provider.dart'; import 'package:food_hub_app/widgets/profile/basic_info.dart'; +import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; +import 'package:liquid_glass_widgets/widgets/containers/glass_card.dart'; import 'package:provider/provider.dart'; class ProfilePage extends StatefulWidget { @@ -44,8 +46,13 @@ class ProfilePageState extends State { Navigator.pushNamed(context, '/momentUser'); } - Widget _buildFunctionButtons() { - return CommonCard( + Widget _buildFunctionButtons(BuildContext context) { + final colors = Theme.of(context).colorScheme; + + return GlassCard( + padding: EdgeInsetsGeometry.symmetric(vertical: 0, horizontal: 10), + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), child: Column( children: [ _buildFunctionButton( @@ -56,13 +63,13 @@ class ProfilePageState extends State { // LogUtils.i('点击编辑资料'); }, ), - const Divider(height: 1), + const Divider(height: 1, thickness: 0.2), _buildFunctionButton( icon: Icons.group_outlined, text: '朋友圈', onTap: _onTapMoment, ), - const Divider(height: 1), + const Divider(height: 1, thickness: 0.2), _buildFunctionButton( icon: Icons.favorite, text: '我的收藏', @@ -71,7 +78,7 @@ class ProfilePageState extends State { // LogUtils.i('点击浏览历史'); }, ), - const Divider(height: 1), + const Divider(height: 1, thickness: 0.2), _buildFunctionButton( icon: Icons.lock, text: '更改密码', @@ -80,11 +87,11 @@ class ProfilePageState extends State { // LogUtils.i('点击帮助与反馈'); }, ), - const Divider(height: 1), + const Divider(height: 1, thickness: 0.2), _buildFunctionButton(icon: Icons.message, text: '反馈意见', onTap: () {}), - const Divider(height: 1), + const Divider(height: 1, thickness: 0.2), _buildFunctionButton(icon: Icons.refresh, text: '检查更新', onTap: () {}), - const Divider(height: 1), + const Divider(height: 1, thickness: 0.2), _buildFunctionButton( icon: Icons.exit_to_app, text: '退出登录', @@ -117,13 +124,13 @@ class ProfilePageState extends State { ); } - Widget _buildContent(UserProvider provider) { + Widget _buildContent(UserProvider provider, BuildContext context) { final user = provider.currentUser; return Column( children: [ SizedBox(width: double.infinity, child: ProfileInfo(user: user)), const SizedBox(height: 16), - _buildFunctionButtons(), + _buildFunctionButtons(context), const SizedBox(height: 8), _buildVersionInfo(), ], @@ -134,15 +141,27 @@ class ProfilePageState extends State { Widget build(BuildContext context) { final provider = context.watch(); - return Stack( - children: [ - if (provider.isLoading) - buildLoadingIndicator() - else if (provider.error.isNotEmpty) - Text(provider.error) - else - _buildContent(provider), - ], + return Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + title: Text('我的', style: Theme.of(context).textTheme.titleLarge), + centerTitle: true, + automaticallyImplyLeading: false, + ), + body: Padding( + padding: EdgeInsetsGeometry.all(10), + child: Stack( + children: [ + if (provider.isLoading) + buildLoadingIndicator() + else if (provider.error.isNotEmpty) + Text(provider.error) + else + SingleChildScrollView(child: _buildContent(provider, context)), + ], + ), + ), ); } } diff --git a/lib/views/record.dart b/lib/views/record.dart index caaa3c1..d1243a2 100644 --- a/lib/views/record.dart +++ b/lib/views/record.dart @@ -1,5 +1,10 @@ +import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_common/widget/common_widget.dart'; import 'package:food_hub_app/provider/food_provider.dart'; +import 'package:food_hub_app/views/moment_form.dart'; +import 'package:food_hub_app/views/record_form.dart'; +import 'package:food_hub_app/widgets/common/easy_refresh.dart'; import 'package:food_hub_app/widgets/common/index.dart'; import 'package:food_hub_app/widgets/recipe/calendar.dart'; import 'package:food_hub_app/widgets/recipe/list.dart'; @@ -24,12 +29,68 @@ class RecordPage extends StatefulWidget { } class _RecordPageState extends State { + final EasyRefreshController _freshController = EasyRefreshController( + controlFinishRefresh: true, + controlFinishLoad: true, + ); + final ScrollController _scrollController = ScrollController(); + bool _showScrollToTop = false; final List _tabPages = [ RecipeList(), RecipeCalendar(), RecipeTimeline(), ]; + @override + void initState() { + super.initState(); + _scrollController.addListener(_onScroll); + } + + @override + void dispose() { + _scrollController.removeListener(_onScroll); + _freshController.dispose(); + _scrollController.dispose(); + super.dispose(); + } + + // 下拉刷新 + Future _onRefresh() async { + _freshController.finishRefresh(); + } + + // 上拉加载 + Future _onLoad() async { + final provider = context.read(); + if (provider.hasMore) { + await provider.refreshFoodStats(); + _freshController.finishLoad(IndicatorResult.success); + } else { + _freshController.finishLoad(IndicatorResult.noMore); + } + } + + void _onScroll() { + // 当滚动距离超过时显示返回顶部按钮 + if (_scrollController.offset > 100) { + if (!_showScrollToTop) { + setState(() { + _showScrollToTop = true; + }); + } + } else { + if (_showScrollToTop) { + setState(() { + _showScrollToTop = false; + }); + } + } + } + + // 滚动到顶部 + void _scrollToTop() => scrollToTopAnimateTo(_scrollController); + Widget _buildTabs({ required BuildContext context, required RecordTab currentTab, @@ -52,24 +113,135 @@ class _RecordPageState extends State { provider.onRecordTabChange(); } + void _handleAddRecord(FoodProvider provider) { + provider.resetRecordForm(); + provider.isEditing = false; + Navigator.pop(context); + + showModalBottomSheet( + context: context, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (context) => RecordForm(), + ); + } + + void _handleAddMoment(FoodProvider provider) { + provider.resetMomentForm(); + provider.isEditing = false; + Navigator.pop(context); + + showModalBottomSheet( + context: context, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (context) => MomentForm(), + ); + } + + void _onPressAdd(FoodProvider provider) { + showModalBottomSheet( + context: context, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: + (context) => Padding( + padding: EdgeInsetsGeometry.symmetric(horizontal: 0, vertical: 8), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 8), + Text('请选择操作', style: Theme.of(context).textTheme.titleLarge), + const SizedBox(height: 10), + ListTile( + leading: Icon( + Icons.book, + color: Theme.of(context).colorScheme.primary, + ), + title: Text( + '新增菜谱', + style: Theme.of(context).textTheme.bodyLarge, + ), + onTap: () => {}, + ), + ListTile( + leading: Icon( + Icons.note_add, + color: Theme.of(context).colorScheme.primary, + ), + title: Text( + '新增记录', + style: Theme.of(context).textTheme.bodyLarge, + ), + onTap: () => _handleAddRecord(provider), + ), + ListTile( + leading: Icon( + Icons.group, + color: Theme.of(context).colorScheme.primary, + ), + title: Text( + '发布朋友圈', + style: Theme.of(context).textTheme.bodyLarge, + ), + onTap: () => _handleAddMoment(provider), + ), + ], + ), + ), + ); + } + @override Widget build(BuildContext context) { final provider = context.watch(); - return Column( - children: [ - _buildTabs( - context: context, - currentTab: provider.currentRecordTab, - onTabChanged: (tab) => _onTabChange(tab, provider), + return Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + elevation: 0, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + title: Text('记录', style: Theme.of(context).textTheme.titleLarge), + centerTitle: true, + leading: Builder( + builder: + (context) => IconButton( + icon: Icon(Icons.menu, color: Theme.of(context).primaryColor), + onPressed: () => {}, + ), ), - Expanded( - child: IndexedStack( - index: provider.currentRecordTab.index, - children: _tabPages, + actions: [ + IconButton( + icon: Icon(Icons.search, color: Theme.of(context).primaryColor), + onPressed: () {}, ), + IconButton( + icon: Icon(Icons.add, color: Theme.of(context).primaryColor), + onPressed: () => _onPressAdd(provider), + ), + ], + ), + body: Padding( + padding: const EdgeInsets.all(10), + child: Column( + children: [ + _buildTabs( + context: context, + currentTab: provider.currentRecordTab, + onTabChanged: (tab) => _onTabChange(tab, provider), + ), + Expanded(child: _tabPages[provider.currentRecordTab.index]), + ], ), - ], + ), ); } } diff --git a/lib/views/record_form.dart b/lib/views/record_form.dart index 23147c8..2ab6786 100644 --- a/lib/views/record_form.dart +++ b/lib/views/record_form.dart @@ -1,28 +1,28 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_common/utils/minio_utils.dart'; import 'package:flutter_common/utils/toast_util.dart'; -import 'package:flutter_common/widget/common_widget.dart'; import 'package:flutter_common/widget/dialog_widget.dart'; import 'package:flutter_common/widget/loading_widget.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:food_hub_app/apis/recipe.dart'; import 'package:food_hub_app/config/app_config.dart'; import 'package:food_hub_app/provider/food_provider.dart'; +import 'package:food_hub_app/utils/minio_utils.dart'; import 'package:food_hub_app/widgets/common/form.dart'; import 'package:food_hub_app/widgets/common/image.dart'; import 'package:intl/intl.dart'; +import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; import 'package:provider/provider.dart'; -class RecordFormPage extends StatefulWidget { - const RecordFormPage({super.key}); +class RecordForm extends StatefulWidget { + const RecordForm({super.key}); @override - State createState() => _RecordFormPageState(); + State createState() => _RecordFormState(); } -class _RecordFormPageState extends State { +class _RecordFormState extends State { final _formKey = GlobalKey(); static const String _nameField = 'name'; static const String _dateField = 'date'; @@ -49,19 +49,19 @@ class _RecordFormPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ buildFormLabel(context: context, text: '菜谱名称', isRequired: true), - const SizedBox(height: 8), + const SizedBox(height: 12), _buildRecipeField(provider), - const SizedBox(height: 8), + const SizedBox(height: 12), buildFormLabel(context: context, text: '完成时间', isRequired: true), - const SizedBox(height: 8), + const SizedBox(height: 12), _buildDateField(provider), - const SizedBox(height: 8), + const SizedBox(height: 12), buildFormLabel(context: context, text: '上传图片', isRequired: true), - const SizedBox(height: 8), + const SizedBox(height: 12), _buildImageField(provider), - const SizedBox(height: 8), + const SizedBox(height: 12), buildFormButtonGroup( context: context, @@ -254,13 +254,18 @@ class _RecordFormPageState extends State { PlatformFile file = result.files.first; LoadingDialog.show(context, message: '上传中'); - final fileName = await MinIOHelper().uploadFile( - bucketName: AppConfig.bucketName, - file: file, - ); - - LoadingDialog.hide(context); - provider.updateRecordFormItem(imageUrl: fileName); + try { + final fileName = await MinIOHelper().uploadFile( + bucketName: AppConfig.bucketName, + file: file, + ); + ToastUtil.success('上传成功'); + provider.updateRecordFormItem(imageUrl: fileName); + } catch (e) { + ToastUtil.error(e.toString()); + } finally { + LoadingDialog.hide(context); + } } } @@ -326,24 +331,17 @@ class _RecordFormPageState extends State { @override Widget build(BuildContext context) { - final colors = Theme.of(context).colorScheme; final provider = context.watch(); - final String title = provider.isEditing ? '编辑记录' : '新增记录'; - - return Scaffold( - appBar: AppBar( - title: Text(title, style: TextStyle(color: Colors.white)), - backgroundColor: colors.primary, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () => Navigator.pop(context), - ), - ), - body: SingleChildScrollView( - child: Padding( - padding: EdgeInsets.all(10), - child: CommonCard(child: _buildFormBuilder(provider)), + return SingleChildScrollView( + child: Padding( + padding: EdgeInsets.all(10), + child: GlassCard( + useOwnLayer: true, + settings: LiquidGlassSettings( + glassColor: Theme.of(context).scaffoldBackgroundColor, + ), + child: _buildFormBuilder(provider), ), ), ); diff --git a/lib/views/stats.dart b/lib/views/stats.dart index 57ef760..c79dba8 100644 --- a/lib/views/stats.dart +++ b/lib/views/stats.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_common/widget/chart.dart'; import 'package:flutter_common/widget/common_widget.dart'; import 'package:food_hub_app/provider/food_provider.dart'; +import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; import 'package:provider/provider.dart'; class StatsPage extends StatefulWidget { @@ -24,7 +25,9 @@ class _StatsPage extends State { }); } - Widget _buildSummaryStats(FoodProvider provider) { + Widget _buildSummaryStats(BuildContext context, FoodProvider provider) { + final colors = Theme.of(context).colorScheme; + return GridView.count( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -34,42 +37,62 @@ class _StatsPage extends State { mainAxisSpacing: 8, childAspectRatio: 2, children: [ - StatsCard( - icon: Icons.restaurant_menu, - title: '菜谱总数', - value: provider.summaryStats.recipeCount.toString(), - unit: '个', + GlassCard( + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), + child: StatsCard( + icon: Icons.restaurant_menu, + title: '菜谱总数', + value: provider.summaryStats.recipeCount.toString(), + unit: '个', + ), ), - StatsCard( - icon: Icons.grid_view_rounded, - title: '菜谱类别', - value: provider.summaryStats.categoryCount.toString(), - unit: '种', + GlassCard( + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), + child: StatsCard( + icon: Icons.grid_view_rounded, + title: '菜谱类别', + value: provider.summaryStats.categoryCount.toString(), + unit: '种', + ), ), - StatsCard( - icon: Icons.flag, - title: '做菜次数', - value: provider.summaryStats.workCount.toString(), - unit: '个', + GlassCard( + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), + child: StatsCard( + icon: Icons.flag, + title: '做菜次数', + value: provider.summaryStats.workCount.toString(), + unit: '个', + ), ), - StatsCard( - icon: Icons.show_chart, - title: '平均次数', - value: provider.averageRecordCount.toStringAsFixed(2), - unit: '次/月', + GlassCard( + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), + child: StatsCard( + icon: Icons.show_chart, + title: '平均次数', + value: provider.averageRecordCount.toStringAsFixed(2), + unit: '次/月', + ), ), ], ); } - Widget _buildContent(FoodProvider provider) { + Widget _buildContent(BuildContext context, FoodProvider provider) { + final colors = Theme.of(context).colorScheme; + return Column( children: [ - _buildSummaryStats(provider), + _buildSummaryStats(context, provider), SizedBox(height: 8), SizedBox( height: chartHeight, - child: CommonCard( + child: GlassCard( + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), child: LineChart( title: '记录统计', xAxisName: '日期', @@ -82,7 +105,9 @@ class _StatsPage extends State { SizedBox(height: 8), SizedBox( height: chartHeight, - child: CommonCard( + child: GlassCard( + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), child: PieChart( title: '菜谱统计', unit: '个', @@ -93,7 +118,9 @@ class _StatsPage extends State { SizedBox(height: 8), SizedBox( height: chartHeight, - child: CommonCard( + child: GlassCard( + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), child: RankChart(title: '排行榜', data: provider.rankStats, unit: '次'), ), ), @@ -105,13 +132,28 @@ class _StatsPage extends State { Widget build(BuildContext context) { final provider = context.watch(); - return Stack( - children: [ - if (provider.isLoading) - buildLoadingIndicator() - else - SingleChildScrollView(child: _buildContent(provider)), - ], + return Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + title: Text('统计', style: Theme.of(context).textTheme.titleLarge), + centerTitle: true, + automaticallyImplyLeading: false, + ), + body: Padding( + padding: EdgeInsetsGeometry.all(10), + child: Stack( + children: [ + if (provider.isLoading) + buildLoadingIndicator() + else + SingleChildScrollView( + padding: const EdgeInsets.only(bottom: 90), + child: _buildContent(context, provider), + ), + ], + ), + ), ); } } diff --git a/lib/widgets/common/easy_refresh.dart b/lib/widgets/common/easy_refresh.dart index fc42b24..5d14123 100644 --- a/lib/widgets/common/easy_refresh.dart +++ b/lib/widgets/common/easy_refresh.dart @@ -43,15 +43,17 @@ Widget buildScrollToTop({ required BuildContext context, required VoidCallback scrollToTop, }) { + final colors = Theme.of(context).colorScheme; + return Positioned( right: 0, - bottom: 20, + bottom: 80, child: FloatingActionButton( onPressed: scrollToTop, - backgroundColor: Theme.of(context).colorScheme.primary, + backgroundColor: colors.primary, elevation: 2, mini: true, - child: const Icon(Icons.arrow_upward, color: Colors.white), + child: Icon(Icons.arrow_upward, color: colors.surface), ), ); } diff --git a/lib/widgets/common/form.dart b/lib/widgets/common/form.dart index eb3da4f..99de2f1 100644 --- a/lib/widgets/common/form.dart +++ b/lib/widgets/common/form.dart @@ -12,26 +12,26 @@ InputDecoration buildInputDecoration({ return InputDecoration( hintText: hintText, - hintStyle: TextStyle(color: colors.onSurface.withAlpha(100)), + hintStyle: Theme.of(context).textTheme.bodyMedium, filled: true, fillColor: colors.surface, - border: OutlineInputBorder( - borderSide: const BorderSide(color: Color(0xFFE5E7EB)), - borderRadius: BorderRadius.circular(8), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(10), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: colors.primary, width: 2), - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(10), ), errorBorder: OutlineInputBorder( borderSide: const BorderSide(color: Colors.red, width: 2), - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(10), ), contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 14), errorStyle: const TextStyle(fontSize: 12, height: 1, color: Colors.red), prefixIcon: prefixIcon != null - ? Icon(prefixIcon, size: 20, color: Color(0xFF86909C)) + ? Icon(prefixIcon, size: 20, color: colors.primary) : null, prefixIconConstraints: const BoxConstraints(minWidth: 40), isDense: true, diff --git a/lib/widgets/common/image.dart b/lib/widgets/common/image.dart index 4bb1f8b..b1b8c8e 100644 --- a/lib/widgets/common/image.dart +++ b/lib/widgets/common/image.dart @@ -1,3 +1,4 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:food_hub_app/config/app_config.dart'; import 'package:photo_view/photo_view.dart'; @@ -53,6 +54,8 @@ class _ImagePreviewPageState extends State { @override Widget build(BuildContext context) { + final index = '${_currentIndex + 1}/${widget.images.length}'; + return Scaffold( backgroundColor: Colors.black, appBar: AppBar( @@ -63,10 +66,7 @@ class _ImagePreviewPageState extends State { onPressed: () => Navigator.pop(context), ), // 显示实时更新的页码(当前索引+1 / 总数量) - title: Text( - '${_currentIndex + 1}/${widget.images.length}', - style: const TextStyle(color: Colors.white), - ), + title: Text(index, style: const TextStyle(color: Colors.white)), centerTitle: true, ), body: PhotoViewGallery( @@ -95,21 +95,6 @@ class CommonImage extends StatelessWidget { const CommonImage({super.key, required this.imageUrls, required this.index}); - Widget _buildImageLoadingIndicator(ImageChunkEvent? progress) { - final value = - progress?.expectedTotalBytes != null - ? progress!.cumulativeBytesLoaded / progress.expectedTotalBytes! - : null; - - return Center( - child: SizedBox( - width: 30, - height: 30, - child: CircularProgressIndicator(value: value), - ), - ); - } - Widget _buildErrorImage() { return Container( color: Colors.grey[200], @@ -140,14 +125,16 @@ class CommonImage extends StatelessWidget { onTap: () { _navigateToImagePreview(context, imageUrls, index); }, - child: Image.network( - '${AppConfig.imageBaseUrl}${imageUrls[index]}', + child: CachedNetworkImage( + imageUrl: '${AppConfig.imageBaseUrl}${imageUrls[index]}', fit: BoxFit.cover, - loadingBuilder: (context, child, loadingProgress) { - if (loadingProgress == null) return child; - return _buildImageLoadingIndicator(loadingProgress); - }, - errorBuilder: (context, error, stackTrace) => _buildErrorImage(), + progressIndicatorBuilder: + (context, url, downloadProgress) => CircularProgressIndicator( + strokeWidth: 1.5, + padding: EdgeInsetsGeometry.all(20), + value: downloadProgress.progress, + ), + errorWidget: (context, error, stackTrace) => _buildErrorImage(), ), ), ), @@ -213,19 +200,19 @@ Widget buildImageUploadButton({ onTap: onTap, borderRadius: BorderRadius.circular(8), child: Container( - width: 96, - height: 96, + width: double.infinity, + height: 250, decoration: BoxDecoration( color: colors.surface, borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.black), + border: Border.all(color: colors.surface), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.add, color: colors.onSurface.withAlpha(100)), + Icon(Icons.camera_alt, color: colors.onSurface.withAlpha(100)), SizedBox(height: 6), - Text('添加图片', style: TextStyle(color: colors.onSurface.withAlpha(100))), + Text('点击上传美食图片', style: Theme.of(context).textTheme.bodyMedium), ], ), ), diff --git a/lib/widgets/common/index.dart b/lib/widgets/common/index.dart index 3bffd1d..a9541ad 100644 --- a/lib/widgets/common/index.dart +++ b/lib/widgets/common/index.dart @@ -43,8 +43,8 @@ Widget buildToggleSwitch({ totalSwitches: tabValues.length, labels: labels, activeBgColor: [colors.primary], - activeFgColor: Colors.white, - inactiveBgColor: colors.surfaceContainer, + activeFgColor: colors.surface, + inactiveBgColor: colors.surface, inactiveFgColor: colors.onSurface, cornerRadius: 12.0, customTextStyles: [TextStyle(fontSize: 12, fontWeight: FontWeight.w500)], @@ -85,10 +85,10 @@ Widget buildTag(BuildContext context, String title) { return Container( padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( - color: colors.primary.withAlpha(60), + color: colors.primary, borderRadius: BorderRadius.circular(10), ), - child: Text(title, style: TextStyle(color: colors.primary)), + child: Text(title, style: TextStyle(color: colors.surface)), ); } @@ -135,24 +135,10 @@ Widget buildInfoButton({ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), elevation: 0, ), - child: Text(text, style: TextStyle(color: Colors.white)), + child: Text(text), ); } -/// 取消按钮样式 -ButtonStyle cancelButtonStyle() { - return ButtonStyle( - backgroundColor: WidgetStateProperty.all(Colors.grey), - shape: WidgetStateProperty.all( - RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ), - ); -} - -Text buttonText({required String text}) { - return Text(text, style: TextStyle(color: Colors.white)); -} - /// 图片错误显示 Widget errorImageContainer(double height) { return Container( diff --git a/lib/widgets/moment/card.dart b/lib/widgets/moment/card.dart index 123bd5a..9076e91 100644 --- a/lib/widgets/moment/card.dart +++ b/lib/widgets/moment/card.dart @@ -7,7 +7,6 @@ import 'package:food_hub_app/provider/food_provider.dart'; import 'package:food_hub_app/provider/user_provider.dart'; import 'package:food_hub_app/widgets/common/image.dart'; import 'package:provider/provider.dart'; -import 'package:tdesign_flutter/tdesign_flutter.dart'; class MomentCard extends StatefulWidget { final Moment moment; @@ -26,21 +25,24 @@ class MomentCardState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - InkWell(onTap: () => _onTapUser(context), child: _buildAvatar()), + InkWell( + onTap: () => _onTapUser(context), + child: _buildAvatar(context), + ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildNickname(), + _buildNickname(context), const SizedBox(height: 5), - _buildContent(), + _buildContent(context), if (widget.moment.imageList.isNotEmpty) ...[ const SizedBox(height: 8), _buildPostImages(), ], const SizedBox(height: 10), - _buildTime(), + _buildTime(context), const SizedBox(height: 5), _buildActionButtons(), if (widget.moment.commentList!.isNotEmpty) ...[ @@ -69,38 +71,35 @@ class MomentCardState extends State { } // 构建头像组件 - Widget _buildAvatar() { + Widget _buildAvatar(BuildContext context) { if (widget.moment.avatar!.isEmpty) { - return TDAvatar( - size: TDAvatarSize.medium, - type: TDAvatarType.customText, - shape: TDAvatarShape.circle, + return CircleAvatar( + radius: 18, backgroundColor: Theme.of(context).colorScheme.primary, - text: widget.moment.username?[0], + foregroundColor: Theme.of(context).colorScheme.surface, + child: Text(widget.moment.username![0], style: TextStyle(fontSize: 14)), ); } else { - return TDAvatar( - size: TDAvatarSize.medium, - type: TDAvatarType.normal, - fit: BoxFit.contain, - avatarUrl: '${AppConfig.imageBaseUrl}/${widget.moment.avatar}', + return CircleAvatar( + radius: 18, + backgroundImage: NetworkImage('${AppConfig.imageBaseUrl}/${widget.moment.avatar}') ); } } // 构建昵称组件 - Widget _buildNickname() { + Widget _buildNickname(BuildContext context) { return Text( widget.moment.username ?? "", - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600), + style: Theme.of(context).textTheme.titleMedium, ); } // 构建内容组件 - Widget _buildContent() { + Widget _buildContent(BuildContext context) { return Text( widget.moment.content, - style: const TextStyle(fontSize: 15, height: 1.3), + style: Theme.of(context).textTheme.bodyMedium, ); } @@ -142,10 +141,10 @@ class MomentCardState extends State { } // 构建时间组件 - Widget _buildTime() { + Widget _buildTime(BuildContext context) { return Text( widget.moment.date ?? "", - style: TextStyle(fontSize: 12, color: Colors.grey[500]), + style: Theme.of(context).textTheme.bodySmall, ); } @@ -178,14 +177,14 @@ class MomentCardState extends State { alignment: Alignment.bottomLeft, children: [ Icon(Icons.thumb_up_alt_outlined), - Positioned( - left: 20, - bottom: 15, - child: TDBadge( - TDBadgeType.message, - count: (widget.moment.likeList?.length ?? 0).toString(), - ), - ), + // Positioned( + // left: 20, + // bottom: 15, + // child: TDBadge( + // TDBadgeType.message, + // count: (widget.moment.likeList?.length ?? 0).toString(), + // ), + // ), ], ), ), @@ -196,14 +195,14 @@ class MomentCardState extends State { alignment: Alignment.bottomLeft, children: [ Icon(Icons.comment_outlined), - Positioned( - left: 20, - bottom: 15, - child: TDBadge( - TDBadgeType.message, - count: (widget.moment.commentList?.length ?? 0).toString(), - ), - ), + // Positioned( + // left: 20, + // bottom: 15, + // child: TDBadge( + // TDBadgeType.message, + // count: (widget.moment.commentList?.length ?? 0).toString(), + // ), + // ), ], ), ), diff --git a/lib/widgets/profile/basic_info.dart b/lib/widgets/profile/basic_info.dart index efcf4e3..a7ae219 100644 --- a/lib/widgets/profile/basic_info.dart +++ b/lib/widgets/profile/basic_info.dart @@ -4,7 +4,8 @@ import 'package:flutter_common/widget/common_widget.dart'; import 'package:food_hub_app/config/app_config.dart'; import 'package:food_hub_app/models/session.dart'; import 'package:food_hub_app/widgets/common/index.dart'; -import 'package:tdesign_flutter/tdesign_flutter.dart'; +import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; +import 'package:liquid_glass_widgets/widgets/containers/glass_card.dart'; class ProfileInfo extends StatelessWidget { final User user; @@ -13,19 +14,21 @@ class ProfileInfo extends StatelessWidget { Widget _buildAvatar(BuildContext context, User user) { if (user.avatar == null) { - return TDAvatar( - size: TDAvatarSize.large, - type: TDAvatarType.customText, - shape: TDAvatarShape.circle, + return CircleAvatar( + radius: 24, backgroundColor: Theme.of(context).colorScheme.primary, - text: user.username.isNotEmpty ? user.username[0] : '?', + foregroundColor: Theme.of(context).colorScheme.surface, + child: Text( + user.username.isNotEmpty ? user.username[0] : '?', + style: TextStyle(fontSize: 14), + ), ); } else { - return TDAvatar( - size: TDAvatarSize.large, - type: TDAvatarType.normal, - fit: BoxFit.contain, - avatarUrl: '${AppConfig.imageBaseUrl}/${user.avatar}', + return CircleAvatar( + radius: 24, + backgroundImage: NetworkImage( + '${AppConfig.imageBaseUrl}/${user.avatar}', + ), ); } } @@ -41,22 +44,24 @@ class ProfileInfo extends StatelessWidget { children: [ Icon(icon, size: 16, color: colors.primary), const SizedBox(width: 6), - Text(text), + Text(text, style: Theme.of(context).textTheme.bodyMedium), ], ); } @override Widget build(BuildContext context) { - return CommonCard( + final colors = Theme.of(context).colorScheme; + + return GlassCard( + padding: EdgeInsetsGeometry.all(10), + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), child: Column( children: [ _buildAvatar(context, user), const SizedBox(height: 8), - Text( - user.username, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), + Text(user.username, style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), if (user.tags != null && user.tags!.isNotEmpty) Row( diff --git a/lib/widgets/recipe/calendar.dart b/lib/widgets/recipe/calendar.dart index ce8e3d7..3cd3dad 100644 --- a/lib/widgets/recipe/calendar.dart +++ b/lib/widgets/recipe/calendar.dart @@ -3,6 +3,7 @@ import 'package:flutter_common/widget/common_widget.dart'; import 'package:food_hub_app/models/recipe.dart'; import 'package:food_hub_app/provider/food_provider.dart'; import 'package:food_hub_app/utils/index.dart'; +import 'package:food_hub_app/views/record_form.dart'; import 'package:food_hub_app/widgets/common/index.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:provider/provider.dart'; @@ -62,19 +63,16 @@ class _RecipeCalendarState extends State { Text(formatDateTime(provider.selectedDay, 'MM月dd日 EEEE')), SizedBox(height: 4), if (provider.selectRecordList.isEmpty) - buildEmptyData() + SizedBox(height: 100, child: buildEmptyData()) else - Expanded( - child: ListView.separated( - itemCount: provider.selectRecordList.length, - separatorBuilder: (context, index) => SizedBox(height: 8), - itemBuilder: (context, index) { - return _buildRecordItem( - context, - provider.selectRecordList[index], - ); - }, - ), + Column( + children: + provider.selectRecordList.map((record) { + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: _buildRecordItem(context, record), + ); + }).toList(), ), ], ); @@ -112,7 +110,15 @@ class _RecipeCalendarState extends State { provider.initRecordForm(record); provider.isEditing = true; - Navigator.pushNamed(context, "/recordForm"); + + showModalBottomSheet( + context: context, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (context) => RecordForm(), + ); } Widget _buildRecordItem(BuildContext context, FoodRecord record) { @@ -195,12 +201,15 @@ class _RecipeCalendarState extends State { } Widget _buildContent(FoodProvider provider) { - return Column( - children: [ - CommonCard(child: _recipeCalendar(provider)), - SizedBox(height: 8), - Expanded(child: CommonCard(child: _dailyItem(context, provider))), - ], + return SingleChildScrollView( + padding: const EdgeInsets.only(bottom: 80), + child: Column( + children: [ + CommonCard(child: _recipeCalendar(provider)), + const SizedBox(height: 8), + CommonCard(child: _dailyItem(context, provider)), + ], + ), ); } @@ -208,13 +217,10 @@ class _RecipeCalendarState extends State { Widget build(BuildContext context) { final provider = context.watch(); - return Stack( - children: [ - if (provider.isLoading) - buildLoadingIndicator() - else - _buildContent(provider), - ], - ); + if (provider.isLoading) { + return buildLoadingIndicator(); + } + + return _buildContent(provider); } } diff --git a/lib/widgets/recipe/card.dart b/lib/widgets/recipe/card.dart index b67e3cf..196f620 100644 --- a/lib/widgets/recipe/card.dart +++ b/lib/widgets/recipe/card.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_common/widget/common_widget.dart'; import 'package:food_hub_app/models/recipe.dart'; import 'package:food_hub_app/widgets/common/image.dart'; +import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; class RecipeCard extends StatelessWidget { final RecipeSummary recipe; @@ -17,14 +18,22 @@ class RecipeCard extends StatelessWidget { final List imageUrls = recipe.recordList.reversed.map((record) => record.imageUrl).toList(); - return CommonCard( + final colors = Theme.of(context).colorScheme; + + return GlassCard( + padding: EdgeInsetsGeometry.all(10), + useOwnLayer: true, + settings: LiquidGlassSettings(glassColor: colors.surface), child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, children: [ CommonImage(imageUrls: imageUrls, index: 0), SizedBox(height: 8), - _buildRecipeContent(context), + InkWell( + onTap: () => navigatorToRecipeDetail(context), + child: _buildRecipeContent(context), + ), ], ), ); @@ -32,6 +41,7 @@ class RecipeCard extends StatelessWidget { Widget _buildRecipeContent(BuildContext context) { final colors = Theme.of(context).colorScheme; + final textTheme = Theme.of(context).textTheme; return Column( mainAxisAlignment: MainAxisAlignment.center, @@ -42,17 +52,10 @@ class RecipeCard extends StatelessWidget { children: [ Text( recipe.name, - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: textTheme.titleMedium, maxLines: 1, overflow: TextOverflow.ellipsis, ), - InkWell( - onTap: () => navigatorToRecipeDetail(context), - child: Icon( - Icons.arrow_circle_right_sharp, - color: colors.secondary, - ), - ), ], ), SizedBox(height: 5), @@ -62,19 +65,13 @@ class RecipeCard extends StatelessWidget { _buildIconText( icon: Icons.food_bank, text: recipe.category, - color: Color(0xFF6A5ACD), + color: colors.primary, ), const SizedBox(width: 12), _buildIconText( - icon: Icons.thumb_up_alt_outlined, - text: recipe.likeCount.toString(), - color: Color(0xFFDC143C), - ), - const SizedBox(width: 12), - _buildIconText( - icon: Icons.star_outline, - text: recipe.favouriteCount.toString(), - color: Color(0xFF20B2AA), + icon: Icons.note_add, + text: recipe.recordList.length.toString(), + color: colors.primary, ), ], ), diff --git a/lib/widgets/recipe/list.dart b/lib/widgets/recipe/list.dart index f787bf2..a2bbe4e 100644 --- a/lib/widgets/recipe/list.dart +++ b/lib/widgets/recipe/list.dart @@ -22,56 +22,10 @@ class _RecipeListState extends State { context.read().queryCategoryList(); }); } - - Widget _buildSelectCategory(FoodProvider provider) { - final colors = Theme.of(context).colorScheme; - - return Container( - width: 140, - decoration: BoxDecoration( - color: colors.surfaceContainer, - borderRadius: BorderRadius.circular(12), - ), - padding: EdgeInsets.symmetric(horizontal: 16), - child: DropdownButton( - value: provider.queryCategory, - isExpanded: true, - borderRadius: BorderRadius.circular(12), - dropdownColor: colors.surfaceContainer, - elevation: 6, - underline: Container(), - items: - provider.categoryList.map((String value) { - return DropdownMenuItem( - value: value, - child: Row( - children: [ - Container( - width: 8, - height: 8, - decoration: BoxDecoration( - color: colors.primary, - shape: BoxShape.circle, - ), - ), - SizedBox(width: 8), - Expanded( - child: Text(value, style: TextStyle(fontSize: 14)), - ), - ], - ), - ); - }).toList(), - onChanged: (value) { - provider.queryCategory = value!; - provider.refreshRecipeList(); - }, - ), - ); - } - + Widget _buildRecipeList(FoodProvider provider) { return GridView.builder( + padding: const EdgeInsets.only(bottom: 80), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 8, @@ -91,8 +45,6 @@ class _RecipeListState extends State { } else { return Column( children: [ - _buildSelectCategory(provider), - SizedBox(height: 5), Expanded(child: _buildRecipeList(provider)), ], ); diff --git a/lib/widgets/recipe/timeline.dart b/lib/widgets/recipe/timeline.dart index dd80b31..9237a45 100644 --- a/lib/widgets/recipe/timeline.dart +++ b/lib/widgets/recipe/timeline.dart @@ -28,26 +28,24 @@ class _RecipeTimeline extends State { SizedBox(width: 5), Text( record.date, - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: Theme.of(context).textTheme.titleMedium, ), ], ), - SizedBox(height: 6), - Padding( - padding: EdgeInsets.symmetric(vertical: 8, horizontal: 0), - child: CommonCard( - child: Column( - children: [ - Text( - record.name, - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 5), - CommonImage(imageUrls: [record.imageUrl], index: 0), - ], - ), + SizedBox(height: 8), + CommonCard( + child: Column( + children: [ + Text( + record.name, + style: Theme.of(context).textTheme.titleMedium, + ), + const SizedBox(height: 5), + CommonImage(imageUrls: [record.imageUrl], index: 0), + ], ), ), + SizedBox(height: 20) ], ); } @@ -59,6 +57,7 @@ class _RecipeTimeline extends State { final colors = Theme.of(context).colorScheme; return Timeline.tileBuilder( + padding: const EdgeInsets.only(bottom: 80), theme: TimelineThemeData(nodePosition: 0, indicatorPosition: 0), builder: TimelineTileBuilder.connected( itemCount: recordList.length, diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 41d3d2c..08ab439 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,14 +6,10 @@ #include "generated_plugin_registrant.h" -#include #include #include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); - file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) rive_native_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "RiveNativePlugin"); rive_native_plugin_register_with_registrar(rive_native_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index e2b0ef4..c9870b8 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - file_selector_linux rive_native url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index f56d21b..9ce7703 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,19 +6,19 @@ import FlutterMacOS import Foundation import file_picker -import file_selector_macos import flutter_image_compress_macos import path_provider_foundation import rive_native import share_plus import shared_preferences_foundation +import sqflite_darwin func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) - FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) RiveNativePlugin.register(with: registry.registrar(forPlugin: "RiveNativePlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 3abd521..cf4454c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -121,6 +121,30 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "8.10.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.4.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.1" characters: dependency: transitive description: @@ -213,18 +237,18 @@ packages: dependency: transitive description: name: dio - sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" + sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c url: "https://pub.flutter-io.cn" source: hosted - version: "5.8.0+1" + version: "5.9.2" dio_web_adapter: dependency: transitive description: name: dio_web_adapter - sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" + sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340" url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" + version: "2.1.2" easy_refresh: dependency: "direct main" description: @@ -233,14 +257,22 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.4.0" + equatable: + dependency: transitive + description: + name: equatable + sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.8" fake_async: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: transitive description: @@ -310,6 +342,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.4.1" flutter_carousel_widget: dependency: "direct main" description: @@ -402,22 +442,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.0.28" - flutter_slidable: + flutter_shaders: dependency: transitive description: - name: flutter_slidable - sha256: a857de7ea701f276fd6a6c4c67ae885b60729a3449e42766bb0e655171042801 + name: flutter_shaders + sha256: "34794acadd8275d971e02df03afee3dee0f98dbfb8c4837082ad0034f612a3e2" url: "https://pub.flutter-io.cn" source: hosted - version: "3.1.2" - flutter_swiper_null_safety: - dependency: transitive - description: - name: flutter_swiper_null_safety - sha256: "5a855e0080d035c08e82f8b7fd2f106344943a30c9ab483b2584860a2f22eaaf" - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.2" + version: "0.1.3" flutter_test: dependency: "direct dev" description: flutter @@ -432,10 +464,10 @@ packages: dependency: transitive description: name: fluttertoast - sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1" + sha256: "90778fe0497fe3a09166e8cf2e0867310ff434b794526589e77ec03cf08ba8e8" url: "https://pub.flutter-io.cn" source: hosted - version: "8.2.12" + version: "8.2.14" form_builder_validators: dependency: "direct main" description: @@ -560,10 +592,10 @@ packages: dependency: "direct main" description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.flutter-io.cn" source: hosted - version: "0.19.0" + version: "0.20.2" io: dependency: transitive description: @@ -600,26 +632,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.flutter-io.cn" source: hosted - version: "10.0.8" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -628,6 +660,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "5.1.1" + liquid_glass_widgets: + dependency: "direct main" + description: + name: liquid_glass_widgets + sha256: "776adcdb7d48af0b935642425936813074355830eb0a47ecca8b227549d5b057" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.16.3" logger: dependency: "direct main" description: @@ -664,10 +704,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.flutter-io.cn" source: hosted - version: "1.16.0" + version: "1.17.0" mime: dependency: transitive description: @@ -692,6 +732,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" package_config: dependency: transitive description: @@ -840,18 +888,26 @@ packages: dependency: transitive description: name: rive - sha256: fc0abf65d03d1c9afaeb35be9e71c7cf04d2d1f76e94e69d2af1b3ba413cddf9 + sha256: "84a640f48122679e48397935ed1b971db19ef2e44bfcbae60e42fb5ce29a0a4e" url: "https://pub.flutter-io.cn" source: hosted - version: "0.14.0-dev.14" + version: "0.14.9" rive_native: dependency: transitive description: name: rive_native - sha256: e9c7d36f19eb6d32f563825d4e9d5032b19a36d3ca3341641431035bca022d19 + sha256: "85dc8413398f7540eab9b73c6d704ecd5051ab9c57e539eed85ccd2a69f119aa" url: "https://pub.flutter-io.cn" source: hosted - version: "0.0.17" + version: "0.1.9" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.28.0" share_plus: dependency: "direct main" description: @@ -872,26 +928,26 @@ packages: dependency: transitive description: name: shared_preferences - sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf url: "https://pub.flutter-io.cn" source: hosted - version: "2.5.3" + version: "2.5.5" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" + sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.10" + version: "2.4.23" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" url: "https://pub.flutter-io.cn" source: hosted - version: "2.5.4" + version: "2.5.6" shared_preferences_linux: dependency: transitive description: @@ -904,10 +960,10 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_web: dependency: transitive description: @@ -977,6 +1033,46 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.10.1" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: "564cfed0746fe53140c23b70b308e045c3b31f17778f2f326ccb7d804ea0250a" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.2+1" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "881e28efdcc9950fd8e9bb42713dcf1103e62a2e7168f23c9338d82db13dec40" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.2+3" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "1581ffbf7a0e333b380d6a30737d78516b826cb35beb7fb0bf8a3ea0c678b465" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.5.8" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.2" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" stack_trace: dependency: transitive description: @@ -1013,34 +1109,34 @@ packages: dependency: transitive description: name: syncfusion_flutter_charts - sha256: c58ca79e072680af6f0554f7c4b91886c1d8808f2522b49d557f16fb5cb3bb04 + sha256: "68fdb029dad34a46e4c9cfad8ad66fe29db7b303bd96849261ab2b23a168d0e8" url: "https://pub.flutter-io.cn" source: hosted - version: "30.1.41" + version: "30.2.7" syncfusion_flutter_core: dependency: transitive description: name: syncfusion_flutter_core - sha256: "536753489e168f49659261d0abd02b101b34c0b1bde27898f2869aab05f1cbb6" + sha256: bfd026c0f9822b49ff26fed11cd3334519acb6a6ad4b0c81d9cd18df6af1c4c0 url: "https://pub.flutter-io.cn" source: hosted - version: "30.1.41" + version: "30.2.7" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.4.0" table_calendar: dependency: "direct main" description: name: table_calendar - sha256: b2896b7c86adf3a4d9c911d860120fe3dbe03c85db43b22fd61f14ee78cdbb63 + sha256: "0c0c6219878b363a2d5f40c7afb159d845f253d061dc3c822aa0d5fe0f721982" url: "https://pub.flutter-io.cn" source: hosted - version: "3.1.3" - tdesign_flutter: - dependency: "direct main" - description: - name: tdesign_flutter - sha256: b36b6f939f7a585184665202b6b3acf1922728962312b65182dbbff64c3b62f2 - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.3" + version: "3.2.0" tdesign_flutter_adaptation: dependency: "direct overridden" description: @@ -1061,10 +1157,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.flutter-io.cn" source: hosted - version: "0.7.4" + version: "0.7.7" timelines_plus: dependency: "direct main" description: @@ -1141,10 +1237,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -1218,5 +1314,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.7.0 <4.0.0" - flutter: ">=3.29.0" + dart: ">=3.10.0 <4.0.0" + flutter: ">=3.38.0" diff --git a/pubspec.yaml b/pubspec.yaml index dafbf41..b8d6246 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1 +1 @@ -name: food_hub_app description: "A new Flutter project." # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: sdk: ^3.7.0 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, # dependencies can be manually updated by changing the version numbers below to # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter # The following adds the Cupertino Icons fonts to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 provider: ^6.1.1 timelines_plus: ^1.0.7 table_calendar: ^3.1.3 toggle_switch: ^2.3.0 flutter_form_builder: ^10.0.0 form_builder_validators: ^11.1.2 intl: ^0.19.0 tdesign_flutter: ^0.2.3 json_annotation: ^4.9.0 logger: ^2.6.0 photo_view: ^0.15.0 flutter_carousel_widget: ^3.1.0 easy_refresh: ^3.4.0 file_picker: ^10.3.3 share_plus: ^11.0.0 path_provider: ^2.1.5 flutter_common: path: ..\flutter_common dependency_overrides: tdesign_flutter_adaptation: 3.16.0 image_picker: 1.0.8 dev_dependencies: flutter_test: sdk: flutter # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^5.0.0 # flutter pub run build_runner build build_runner: ^2.4.5 json_serializable: ^6.7.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: # The following line ensures that the Material Icons fonts is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images # For details regarding adding assets from package dependencies, see # https://flutter.dev/to/asset-from-package # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the fonts family name, and a "fonts" key with a # list giving the asset and other descriptors for the fonts. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/to/font-from-package fonts: - family: CustomFont fonts: - asset: fonts/custom.ttf \ No newline at end of file +name: food_hub_app description: "A new Flutter project." # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: sdk: ^3.7.0 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, # dependencies can be manually updated by changing the version numbers below to # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter # The following adds the Cupertino Icons fonts to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 liquid_glass_widgets: ^0.16.1 provider: ^6.1.1 timelines_plus: ^1.0.7 table_calendar: ^3.1.3 toggle_switch: ^2.3.0 flutter_form_builder: ^10.0.0 form_builder_validators: ^11.1.2 intl: ^0.20.2 json_annotation: ^4.9.0 logger: ^2.6.0 photo_view: ^0.15.0 flutter_carousel_widget: ^3.1.0 easy_refresh: ^3.4.0 file_picker: ^10.3.3 share_plus: ^11.0.0 path_provider: ^2.1.5 cached_network_image: ^3.4.1 flutter_common: path: ..\flutter_common dependency_overrides: tdesign_flutter_adaptation: 3.16.0 image_picker: 1.0.8 dev_dependencies: flutter_test: sdk: flutter # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^5.0.0 # flutter pub run build_runner build build_runner: ^2.4.5 json_serializable: ^6.7.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: # The following line ensures that the Material Icons fonts is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images # For details regarding adding assets from package dependencies, see # https://flutter.dev/to/asset-from-package # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the fonts family name, and a "fonts" key with a # list giving the asset and other descriptors for the fonts. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/to/font-from-package fonts: - family: CustomFont fonts: - asset: fonts/custom.ttf \ No newline at end of file diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 2beba0f..ec39ef1 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,14 +6,11 @@ #include "generated_plugin_registrant.h" -#include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { - FileSelectorWindowsRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FileSelectorWindows")); RiveNativePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("RiveNativePlugin")); SharePlusWindowsPluginCApiRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 5c160f7..907c56e 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - file_selector_windows rive_native share_plus url_launcher_windows