feat:重构模块

This commit is contained in:
2026-06-27 17:12:38 +08:00
parent a5e788eee6
commit a340ba424e
31 changed files with 919 additions and 623 deletions

View File

@@ -27,7 +27,7 @@ pluginManagement {
plugins { plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.0" apply false 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") include(":app")

View File

@@ -1,15 +1,13 @@
/// 应用信息 /// 应用信息
class AppConfig { 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.4:8083";
// static const String baseApiUrl = "http://192.168.1.103:8083"; static const String baseApiUrl = "https://cxx0822.s.3q.hair/food-api";
static const String rustfsIp = '14.103.235.151'; static const String rustfsIp = '43.248.188.28';
static const String rustfsFileUrl = 'http://14.103.235.151:9100'; 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 bucketName = 'food';
static const String imageBaseUrl = '$rustfsFileUrl/$bucketName/'; static const String imageBaseUrl = '$rustfsFileUrl/$bucketName/';
// static const String imageBaseUrl = '$baseApiUrl/'; // static const String imageBaseUrl = '$baseApiUrl/';

View File

@@ -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<StatefulWidget> createState() => AppNavbarState();
}
class AppNavbarState extends State<AppNavbar> {
@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,
);
}
}

View File

@@ -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<PageInfo> 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<BottomNavigationBarItem> bottomNavItems =
pages.map((page) {
return BottomNavigationBarItem(icon: Icon(page.icon), label: page.label);
}).toList();
final List<Widget> tabPages = pages.map((item) => item.page).toList();

View File

@@ -16,6 +16,7 @@ import 'package:food_hub_app/views/recipe_form.dart';
import 'package:food_hub_app/views/record_form.dart'; import 'package:food_hub_app/views/record_form.dart';
import 'package:food_hub_app/views/recipe_detail.dart'; import 'package:food_hub_app/views/recipe_detail.dart';
import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:liquid_glass_widgets/liquid_glass_setup.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
void main() async { void main() async {
@@ -23,17 +24,22 @@ void main() async {
FormBuilderLocalizations.delegate.load(const Locale('zh', 'CN')); FormBuilderLocalizations.delegate.load(const Locale('zh', 'CN'));
await SPUtil.init(); await SPUtil.init();
await initLogger(); // await initLogger();
// 预编译 shader防止首帧白闪
await LiquidGlassWidgets.initialize();
// wrap() 安装无障碍桥接、全局主题、自适应质量
runApp( runApp(
MultiProvider( LiquidGlassWidgets.wrap(
child: MultiProvider(
providers: [ providers: [
ChangeNotifierProvider(create: (context) => FoodProvider()), ChangeNotifierProvider(create: (context) => FoodProvider()),
ChangeNotifierProvider(create: (context) => ThemeProvider()), ChangeNotifierProvider(create: (context) => ThemeProvider()),
ChangeNotifierProvider(create: (context) => UserProvider()), ChangeNotifierProvider(create: (context) => UserProvider()),
ChangeNotifierProvider(create: (context) => AppProvider()), ChangeNotifierProvider(create: (context) => AppProvider()),
], ],
child: MyApp(), child: const MyApp(),
),
), ),
); );
} }
@@ -45,10 +51,52 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final themeProvider = context.watch<ThemeProvider>(); final themeProvider = context.watch<ThemeProvider>();
final brightness = MediaQuery.of(context).platformBrightness;
themeProvider.isDarkMode = brightness == Brightness.dark;
return MaterialApp( return MaterialApp(
debugShowCheckedModeBanner: false, 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 [ supportedLocales: const [
Locale('en', 'US'), // 英语 Locale('en', 'US'), // 英语
Locale('zh', 'CN'), // 中文 Locale('zh', 'CN'), // 中文
@@ -71,13 +119,13 @@ class MyApp extends StatelessWidget {
home: LoginPage(), home: LoginPage(),
routes: { routes: {
'/home': (context) => HomePage(), '/home': (context) => HomePage(),
'/recordForm': (context) => RecordFormPage(), '/recordForm': (context) => RecordForm(),
'/recipeForm': (context) => RecipeFormPage(), '/recipeForm': (context) => RecipeFormPage(),
'/recipeDetail': (context) => RecipeDetailPage(), '/recipeDetail': (context) => RecipeDetailPage(),
'/momentForm': (context) => MomentFormPage(), '/momentForm': (context) => MomentForm(),
'/moment': (context) => MomentPage(), '/moment': (context) => MomentPage(),
'/momentUser': (context) => MomentUserPage(), '/momentUser': (context) => MomentUserPage(),
'/ProfileUser': (context) => ProfileUserPage() '/ProfileUser': (context) => ProfileUserPage(),
}, },
); );
} }

View File

@@ -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<String> 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');
}
}
}

View File

@@ -1,8 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:food_hub_app/layout/app_actions.dart'; import 'package:food_hub_app/views/profile.dart';
import 'package:food_hub_app/layout/app_drawer.dart'; import 'package:food_hub_app/views/record.dart';
import 'package:food_hub_app/layout/app_navbar.dart'; import 'package:food_hub_app/views/stats.dart';
import 'package:food_hub_app/layout/menu.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 { class HomePage extends StatefulWidget {
const HomePage({super.key}); const HomePage({super.key});
@@ -14,38 +20,52 @@ class HomePage extends StatefulWidget {
class _HomePage extends State<HomePage> { class _HomePage extends State<HomePage> {
int _currentIndex = 0; int _currentIndex = 0;
final _pages = [
const RecordPage(),
const StatsPage(),
const MomentPage(),
const ProfilePage(),
];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( final colors = Theme.of(context).colorScheme;
appBar: AppBar(
centerTitle: true, return GlassScaffold(
title: Text('食光集', style: TextStyle(color: Colors.white)), statusBarStyle: GlassStatusBarStyle.auto,
backgroundColor: Theme.of(context).colorScheme.primary, bottomBar: GlassBottomBar(
leading: Builder( settings: LiquidGlassSettings(
builder: (context) { glassColor: colors.surface
return IconButton(
icon: const Icon(Icons.menu),
color: Colors.white,
onPressed: () => Scaffold.of(context).openDrawer(),
);
},
), ),
actions: [AppActions(pageIndex: _currentIndex)], 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: '记录',
), ),
// backgroundColor: Color(0xFFF5F5F5), GlassBottomBarTab(
drawer: AppDrawer(), icon: Icon(Icons.pie_chart_outline),
body: Padding( activeIcon: Icon(Icons.pie_chart),
padding: EdgeInsets.all(10), label: '统计',
child: tabPages[_currentIndex],
), ),
bottomNavigationBar: AppNavbar( GlassBottomBarTab(
currentPageIndex: _currentIndex, icon: Icon(Icons.group_outlined),
onTapNavbarItem: (index) { activeIcon: Icon(Icons.group),
setState(() { label: '朋友圈',
_currentIndex = index;
});
},
), ),
GlassBottomBarTab(
icon: Icon(Icons.account_circle_outlined),
activeIcon: Icon(Icons.account_circle),
label: '我的',
),
],
),
body: _pages[_currentIndex],
); );
} }
} }

View File

@@ -104,12 +104,12 @@ class _LoginPage extends State<LoginPage> {
key: _formKey, key: _formKey,
child: Column( child: Column(
children: [ children: [
Expanded(child: buildLoginForm()), Expanded(child: buildLoginForm(context)),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 50), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 50),
child: Column( child: Column(
children: [ children: [
buildOtherLoginText(), buildOtherLoginText(context),
const SizedBox(height: 15), const SizedBox(height: 15),
buildOtherMethod(context), buildOtherMethod(context),
const SizedBox(height: 20), const SizedBox(height: 20),
@@ -131,29 +131,29 @@ class _LoginPage extends State<LoginPage> {
); );
} }
Widget buildLoginForm() { Widget buildLoginForm(BuildContext context) {
return ListView( return ListView(
padding: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 20),
children: [ children: [
const SizedBox(height: kToolbarHeight), const SizedBox(height: kToolbarHeight),
buildTitle(), buildTitle(),
const SizedBox(height: 60), const SizedBox(height: 60),
buildUsernameTextField(), buildUsernameTextField(context),
const SizedBox(height: 20), const SizedBox(height: 20),
buildPasswordTextField(), buildPasswordTextField(context),
const SizedBox(height: 10), const SizedBox(height: 10),
buildRememberPasswordCheckbox(), buildRememberPasswordCheckbox(context),
const SizedBox(height: 20), const SizedBox(height: 20),
buildLoginButton(), buildLoginButton(context),
], ],
); );
} }
Widget buildUsernameTextField() { Widget buildUsernameTextField(BuildContext context) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
formLabelText(labelText: "账号:"), Text("账号:", style: Theme.of(context).textTheme.bodyLarge),
const SizedBox(height: 10), const SizedBox(height: 10),
FormBuilderTextField( FormBuilderTextField(
name: 'username', name: 'username',
@@ -171,11 +171,11 @@ class _LoginPage extends State<LoginPage> {
); );
} }
Widget buildPasswordTextField() { Widget buildPasswordTextField(BuildContext context) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
formLabelText(labelText: "密码:"), Text("密码:", style: Theme.of(context).textTheme.bodyLarge),
const SizedBox(height: 10), const SizedBox(height: 10),
FormBuilderTextField( FormBuilderTextField(
name: 'password', name: 'password',
@@ -205,7 +205,7 @@ class _LoginPage extends State<LoginPage> {
); );
} }
Widget buildRememberPasswordCheckbox() { Widget buildRememberPasswordCheckbox(BuildContext context) {
return Row( return Row(
children: [ children: [
Checkbox( Checkbox(
@@ -218,12 +218,12 @@ class _LoginPage extends State<LoginPage> {
}); });
}, },
), ),
const Text('记住密码', style: TextStyle(color: Colors.grey, fontSize: 14)), Text('记住密码', style: Theme.of(context).textTheme.bodyMedium),
], ],
); );
} }
Widget buildLoginButton() { Widget buildLoginButton(BuildContext context) {
return SizedBox( return SizedBox(
height: 45, height: 45,
width: double.infinity, width: double.infinity,
@@ -243,23 +243,20 @@ class _LoginPage extends State<LoginPage> {
); );
} }
Widget buildOtherLoginText() { Widget buildOtherLoginText(BuildContext context) {
return Row( return Row(
children: [ children: [
Expanded(child: Divider(color: Colors.grey[300], thickness: 1)), Expanded(child: Divider(color: Colors.grey[300], thickness: 1)),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text( child: Text('其他方式登录', style: Theme.of(context).textTheme.bodyMedium),
'其他方式登录',
style: TextStyle(color: Colors.grey, fontSize: 14),
),
), ),
Expanded(child: Divider(color: Colors.grey[300], thickness: 1)), Expanded(child: Divider(color: Colors.grey[300], thickness: 1)),
], ],
); );
} }
Widget buildOtherMethod(context) { Widget buildOtherMethod(BuildContext context) {
return OverflowBar( return OverflowBar(
alignment: MainAxisAlignment.center, alignment: MainAxisAlignment.center,
children: children:
@@ -292,16 +289,19 @@ class _LoginPage extends State<LoginPage> {
); );
} }
Widget buildRegisterText(context) { Widget buildRegisterText(BuildContext context) {
return Center( return Center(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const Text('没有账号?', style: TextStyle(fontSize: 18)), Text('没有账号?', style: Theme.of(context).textTheme.bodyMedium),
GestureDetector( GestureDetector(
child: const Text( child: Text(
'点击注册', '点击注册',
style: TextStyle(fontSize: 18, color: Colors.green), style: TextStyle(
fontSize: 14,
color: Theme.of(context).colorScheme.primary,
),
), ),
onTap: () { onTap: () {
print("点击注册"); print("点击注册");

View File

@@ -59,8 +59,8 @@ class _MomentPageState extends State<MomentPage> {
} }
void _onScroll() { void _onScroll() {
// 当滚动距离超过300时显示返回顶部按钮 // 当滚动距离超过时显示返回顶部按钮
if (_scrollController.offset > 300) { if (_scrollController.offset > 100) {
if (!_showScrollToTop) { if (!_showScrollToTop) {
setState(() { setState(() {
_showScrollToTop = true; _showScrollToTop = true;
@@ -99,7 +99,17 @@ class _MomentPageState extends State<MomentPage> {
} }
// 有数据时显示列表 // 有数据时显示列表
return Stack( 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: [ children: [
buildEasyRefresh( buildEasyRefresh(
freshController: _freshController, freshController: _freshController,
@@ -119,6 +129,8 @@ class _MomentPageState extends State<MomentPage> {
if (_showScrollToTop) if (_showScrollToTop)
buildScrollToTop(context: context, scrollToTop: _scrollToTop), buildScrollToTop(context: context, scrollToTop: _scrollToTop),
], ],
),
),
); );
} }
} }

View File

@@ -1,26 +1,27 @@
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_common/utils/log_utils.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/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/dialog_widget.dart';
import 'package:flutter_common/widget/loading_widget.dart'; import 'package:flutter_common/widget/loading_widget.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:food_hub_app/config/app_config.dart'; import 'package:food_hub_app/config/app_config.dart';
import 'package:food_hub_app/provider/food_provider.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/form.dart';
import 'package:food_hub_app/widgets/common/image.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'; import 'package:provider/provider.dart';
class MomentFormPage extends StatefulWidget { class MomentForm extends StatefulWidget {
const MomentFormPage({super.key}); const MomentForm({super.key});
@override @override
State<MomentFormPage> createState() => _MomentFormPageState(); State<MomentForm> createState() => _MomentFormState();
} }
class _MomentFormPageState extends State<MomentFormPage> { class _MomentFormState extends State<MomentForm> {
final _formKey = GlobalKey<FormBuilderState>(); final _formKey = GlobalKey<FormBuilderState>();
final _focusNode = FocusNode(); final _focusNode = FocusNode();
static const String _contentField = 'content'; static const String _contentField = 'content';
@@ -34,8 +35,8 @@ class _MomentFormPageState extends State<MomentFormPage> {
name: _contentField, name: _contentField,
initialValue: provider.momentFormItem.content, initialValue: provider.momentFormItem.content,
focusNode: _focusNode, focusNode: _focusNode,
maxLines: 5, maxLines: 8,
minLines: 3, minLines: 5,
maxLength: maxContentLength, maxLength: maxContentLength,
buildCounter: ( buildCounter: (
context, { context, {
@@ -75,7 +76,7 @@ class _MomentFormPageState extends State<MomentFormPage> {
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, crossAxisCount: 2,
crossAxisSpacing: 8, crossAxisSpacing: 8,
mainAxisSpacing: 8, mainAxisSpacing: 8,
childAspectRatio: 4 / 3, childAspectRatio: 4 / 3,
@@ -111,7 +112,11 @@ class _MomentFormPageState extends State<MomentFormPage> {
_buildContentField(provider), _buildContentField(provider),
const SizedBox(height: 8), const SizedBox(height: 8),
buildFormLabel(context: context, text: '上传图片最多9张', isRequired: false), buildFormLabel(
context: context,
text: '上传图片最多9张',
isRequired: false,
),
const SizedBox(height: 8), const SizedBox(height: 8),
_buildImageField(provider), _buildImageField(provider),
const SizedBox(height: 8), const SizedBox(height: 8),
@@ -146,11 +151,10 @@ class _MomentFormPageState extends State<MomentFormPage> {
if (result != null) { if (result != null) {
// 限制选择数量 // 限制选择数量
final filesToUpload = result.files.take(remainingCount).toList(); final filesToUpload = result.files.take(remainingCount).toList();
LoadingDialog.show(context, message: '上传中'); LoadingDialog.show(context, message: '上传中');
try {
final newImageUrls = <String>[]; final newImageUrls = <String>[];
// 逐个上传图片 // 逐个上传图片
for (final file in filesToUpload) { for (final file in filesToUpload) {
final fileName = await MinIOHelper().uploadFile( final fileName = await MinIOHelper().uploadFile(
@@ -162,8 +166,12 @@ class _MomentFormPageState extends State<MomentFormPage> {
} }
// 更新图片列表 // 更新图片列表
LoadingDialog.hide(context);
provider.addMomentFormImage(newImageUrls); provider.addMomentFormImage(newImageUrls);
} catch (e) {
ToastUtil.error(e.toString());
} finally {
LoadingDialog.hide(context);
}
} }
} }
@@ -205,24 +213,17 @@ class _MomentFormPageState extends State<MomentFormPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final colors = Theme.of(context).colorScheme;
final provider = context.watch<FoodProvider>(); final provider = context.watch<FoodProvider>();
final String title = provider.isEditing ? '编辑朋友圈' : '新增朋友圈'; return SingleChildScrollView(
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( child: Padding(
padding: const EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: CommonCard(child: _buildFormBuilder(provider)), child: GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(
glassColor: Theme.of(context).scaffoldBackgroundColor,
),
child: _buildFormBuilder(provider),
), ),
), ),
); );

View File

@@ -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/app_provider.dart';
import 'package:food_hub_app/provider/user_provider.dart'; import 'package:food_hub_app/provider/user_provider.dart';
import 'package:food_hub_app/widgets/profile/basic_info.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'; import 'package:provider/provider.dart';
class ProfilePage extends StatefulWidget { class ProfilePage extends StatefulWidget {
@@ -44,8 +46,13 @@ class ProfilePageState extends State<ProfilePage> {
Navigator.pushNamed(context, '/momentUser'); Navigator.pushNamed(context, '/momentUser');
} }
Widget _buildFunctionButtons() { Widget _buildFunctionButtons(BuildContext context) {
return CommonCard( final colors = Theme.of(context).colorScheme;
return GlassCard(
padding: EdgeInsetsGeometry.symmetric(vertical: 0, horizontal: 10),
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
child: Column( child: Column(
children: [ children: [
_buildFunctionButton( _buildFunctionButton(
@@ -56,13 +63,13 @@ class ProfilePageState extends State<ProfilePage> {
// LogUtils.i('点击编辑资料'); // LogUtils.i('点击编辑资料');
}, },
), ),
const Divider(height: 1), const Divider(height: 1, thickness: 0.2),
_buildFunctionButton( _buildFunctionButton(
icon: Icons.group_outlined, icon: Icons.group_outlined,
text: '朋友圈', text: '朋友圈',
onTap: _onTapMoment, onTap: _onTapMoment,
), ),
const Divider(height: 1), const Divider(height: 1, thickness: 0.2),
_buildFunctionButton( _buildFunctionButton(
icon: Icons.favorite, icon: Icons.favorite,
text: '我的收藏', text: '我的收藏',
@@ -71,7 +78,7 @@ class ProfilePageState extends State<ProfilePage> {
// LogUtils.i('点击浏览历史'); // LogUtils.i('点击浏览历史');
}, },
), ),
const Divider(height: 1), const Divider(height: 1, thickness: 0.2),
_buildFunctionButton( _buildFunctionButton(
icon: Icons.lock, icon: Icons.lock,
text: '更改密码', text: '更改密码',
@@ -80,11 +87,11 @@ class ProfilePageState extends State<ProfilePage> {
// LogUtils.i('点击帮助与反馈'); // LogUtils.i('点击帮助与反馈');
}, },
), ),
const Divider(height: 1), const Divider(height: 1, thickness: 0.2),
_buildFunctionButton(icon: Icons.message, text: '反馈意见', onTap: () {}), _buildFunctionButton(icon: Icons.message, text: '反馈意见', onTap: () {}),
const Divider(height: 1), const Divider(height: 1, thickness: 0.2),
_buildFunctionButton(icon: Icons.refresh, text: '检查更新', onTap: () {}), _buildFunctionButton(icon: Icons.refresh, text: '检查更新', onTap: () {}),
const Divider(height: 1), const Divider(height: 1, thickness: 0.2),
_buildFunctionButton( _buildFunctionButton(
icon: Icons.exit_to_app, icon: Icons.exit_to_app,
text: '退出登录', text: '退出登录',
@@ -117,13 +124,13 @@ class ProfilePageState extends State<ProfilePage> {
); );
} }
Widget _buildContent(UserProvider provider) { Widget _buildContent(UserProvider provider, BuildContext context) {
final user = provider.currentUser; final user = provider.currentUser;
return Column( return Column(
children: [ children: [
SizedBox(width: double.infinity, child: ProfileInfo(user: user)), SizedBox(width: double.infinity, child: ProfileInfo(user: user)),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildFunctionButtons(), _buildFunctionButtons(context),
const SizedBox(height: 8), const SizedBox(height: 8),
_buildVersionInfo(), _buildVersionInfo(),
], ],
@@ -134,15 +141,27 @@ class ProfilePageState extends State<ProfilePage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final provider = context.watch<UserProvider>(); final provider = context.watch<UserProvider>();
return Stack( 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: [ children: [
if (provider.isLoading) if (provider.isLoading)
buildLoadingIndicator() buildLoadingIndicator()
else if (provider.error.isNotEmpty) else if (provider.error.isNotEmpty)
Text(provider.error) Text(provider.error)
else else
_buildContent(provider), SingleChildScrollView(child: _buildContent(provider, context)),
], ],
),
),
); );
} }
} }

View File

@@ -1,5 +1,10 @@
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.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/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/common/index.dart';
import 'package:food_hub_app/widgets/recipe/calendar.dart'; import 'package:food_hub_app/widgets/recipe/calendar.dart';
import 'package:food_hub_app/widgets/recipe/list.dart'; import 'package:food_hub_app/widgets/recipe/list.dart';
@@ -24,12 +29,68 @@ class RecordPage extends StatefulWidget {
} }
class _RecordPageState extends State<RecordPage> { class _RecordPageState extends State<RecordPage> {
final EasyRefreshController _freshController = EasyRefreshController(
controlFinishRefresh: true,
controlFinishLoad: true,
);
final ScrollController _scrollController = ScrollController();
bool _showScrollToTop = false;
final List<Widget> _tabPages = [ final List<Widget> _tabPages = [
RecipeList(), RecipeList(),
RecipeCalendar(), RecipeCalendar(),
RecipeTimeline(), RecipeTimeline(),
]; ];
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
}
@override
void dispose() {
_scrollController.removeListener(_onScroll);
_freshController.dispose();
_scrollController.dispose();
super.dispose();
}
// 下拉刷新
Future<void> _onRefresh() async {
_freshController.finishRefresh();
}
// 上拉加载
Future<void> _onLoad() async {
final provider = context.read<FoodProvider>();
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({ Widget _buildTabs({
required BuildContext context, required BuildContext context,
required RecordTab currentTab, required RecordTab currentTab,
@@ -52,24 +113,135 @@ class _RecordPageState extends State<RecordPage> {
provider.onRecordTabChange(); 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final provider = context.watch<FoodProvider>(); final provider = context.watch<FoodProvider>();
return Column( 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: () => {},
),
),
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: [ children: [
_buildTabs( _buildTabs(
context: context, context: context,
currentTab: provider.currentRecordTab, currentTab: provider.currentRecordTab,
onTabChanged: (tab) => _onTabChange(tab, provider), onTabChanged: (tab) => _onTabChange(tab, provider),
), ),
Expanded( Expanded(child: _tabPages[provider.currentRecordTab.index]),
child: IndexedStack(
index: provider.currentRecordTab.index,
children: _tabPages,
),
),
], ],
),
),
); );
} }
} }

View File

@@ -1,28 +1,28 @@
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.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/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/dialog_widget.dart';
import 'package:flutter_common/widget/loading_widget.dart'; import 'package:flutter_common/widget/loading_widget.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:food_hub_app/apis/recipe.dart'; import 'package:food_hub_app/apis/recipe.dart';
import 'package:food_hub_app/config/app_config.dart'; import 'package:food_hub_app/config/app_config.dart';
import 'package:food_hub_app/provider/food_provider.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/form.dart';
import 'package:food_hub_app/widgets/common/image.dart'; import 'package:food_hub_app/widgets/common/image.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class RecordFormPage extends StatefulWidget { class RecordForm extends StatefulWidget {
const RecordFormPage({super.key}); const RecordForm({super.key});
@override @override
State<RecordFormPage> createState() => _RecordFormPageState(); State<RecordForm> createState() => _RecordFormState();
} }
class _RecordFormPageState extends State<RecordFormPage> { class _RecordFormState extends State<RecordForm> {
final _formKey = GlobalKey<FormBuilderState>(); final _formKey = GlobalKey<FormBuilderState>();
static const String _nameField = 'name'; static const String _nameField = 'name';
static const String _dateField = 'date'; static const String _dateField = 'date';
@@ -49,19 +49,19 @@ class _RecordFormPageState extends State<RecordFormPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
buildFormLabel(context: context, text: '菜谱名称', isRequired: true), buildFormLabel(context: context, text: '菜谱名称', isRequired: true),
const SizedBox(height: 8), const SizedBox(height: 12),
_buildRecipeField(provider), _buildRecipeField(provider),
const SizedBox(height: 8), const SizedBox(height: 12),
buildFormLabel(context: context, text: '完成时间', isRequired: true), buildFormLabel(context: context, text: '完成时间', isRequired: true),
const SizedBox(height: 8), const SizedBox(height: 12),
_buildDateField(provider), _buildDateField(provider),
const SizedBox(height: 8), const SizedBox(height: 12),
buildFormLabel(context: context, text: '上传图片', isRequired: true), buildFormLabel(context: context, text: '上传图片', isRequired: true),
const SizedBox(height: 8), const SizedBox(height: 12),
_buildImageField(provider), _buildImageField(provider),
const SizedBox(height: 8), const SizedBox(height: 12),
buildFormButtonGroup( buildFormButtonGroup(
context: context, context: context,
@@ -254,13 +254,18 @@ class _RecordFormPageState extends State<RecordFormPage> {
PlatformFile file = result.files.first; PlatformFile file = result.files.first;
LoadingDialog.show(context, message: '上传中'); LoadingDialog.show(context, message: '上传中');
try {
final fileName = await MinIOHelper().uploadFile( final fileName = await MinIOHelper().uploadFile(
bucketName: AppConfig.bucketName, bucketName: AppConfig.bucketName,
file: file, file: file,
); );
ToastUtil.success('上传成功');
LoadingDialog.hide(context);
provider.updateRecordFormItem(imageUrl: fileName); provider.updateRecordFormItem(imageUrl: fileName);
} catch (e) {
ToastUtil.error(e.toString());
} finally {
LoadingDialog.hide(context);
}
} }
} }
@@ -326,24 +331,17 @@ class _RecordFormPageState extends State<RecordFormPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final colors = Theme.of(context).colorScheme;
final provider = context.watch<FoodProvider>(); final provider = context.watch<FoodProvider>();
final String title = provider.isEditing ? '编辑记录' : '新增记录'; return SingleChildScrollView(
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( child: Padding(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: CommonCard(child: _buildFormBuilder(provider)), child: GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(
glassColor: Theme.of(context).scaffoldBackgroundColor,
),
child: _buildFormBuilder(provider),
), ),
), ),
); );

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_common/widget/chart.dart'; import 'package:flutter_common/widget/chart.dart';
import 'package:flutter_common/widget/common_widget.dart'; import 'package:flutter_common/widget/common_widget.dart';
import 'package:food_hub_app/provider/food_provider.dart'; import 'package:food_hub_app/provider/food_provider.dart';
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class StatsPage extends StatefulWidget { class StatsPage extends StatefulWidget {
@@ -24,7 +25,9 @@ class _StatsPage extends State<StatsPage> {
}); });
} }
Widget _buildSummaryStats(FoodProvider provider) { Widget _buildSummaryStats(BuildContext context, FoodProvider provider) {
final colors = Theme.of(context).colorScheme;
return GridView.count( return GridView.count(
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
@@ -34,42 +37,62 @@ class _StatsPage extends State<StatsPage> {
mainAxisSpacing: 8, mainAxisSpacing: 8,
childAspectRatio: 2, childAspectRatio: 2,
children: [ children: [
StatsCard( GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
child: StatsCard(
icon: Icons.restaurant_menu, icon: Icons.restaurant_menu,
title: '菜谱总数', title: '菜谱总数',
value: provider.summaryStats.recipeCount.toString(), value: provider.summaryStats.recipeCount.toString(),
unit: '', unit: '',
), ),
StatsCard( ),
GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
child: StatsCard(
icon: Icons.grid_view_rounded, icon: Icons.grid_view_rounded,
title: '菜谱类别', title: '菜谱类别',
value: provider.summaryStats.categoryCount.toString(), value: provider.summaryStats.categoryCount.toString(),
unit: '', unit: '',
), ),
StatsCard( ),
GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
child: StatsCard(
icon: Icons.flag, icon: Icons.flag,
title: '做菜次数', title: '做菜次数',
value: provider.summaryStats.workCount.toString(), value: provider.summaryStats.workCount.toString(),
unit: '', unit: '',
), ),
StatsCard( ),
GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
child: StatsCard(
icon: Icons.show_chart, icon: Icons.show_chart,
title: '平均次数', title: '平均次数',
value: provider.averageRecordCount.toStringAsFixed(2), value: provider.averageRecordCount.toStringAsFixed(2),
unit: '次/月', unit: '次/月',
), ),
),
], ],
); );
} }
Widget _buildContent(FoodProvider provider) { Widget _buildContent(BuildContext context, FoodProvider provider) {
final colors = Theme.of(context).colorScheme;
return Column( return Column(
children: [ children: [
_buildSummaryStats(provider), _buildSummaryStats(context, provider),
SizedBox(height: 8), SizedBox(height: 8),
SizedBox( SizedBox(
height: chartHeight, height: chartHeight,
child: CommonCard( child: GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
child: LineChart( child: LineChart(
title: '记录统计', title: '记录统计',
xAxisName: '日期', xAxisName: '日期',
@@ -82,7 +105,9 @@ class _StatsPage extends State<StatsPage> {
SizedBox(height: 8), SizedBox(height: 8),
SizedBox( SizedBox(
height: chartHeight, height: chartHeight,
child: CommonCard( child: GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
child: PieChart( child: PieChart(
title: '菜谱统计', title: '菜谱统计',
unit: '', unit: '',
@@ -93,7 +118,9 @@ class _StatsPage extends State<StatsPage> {
SizedBox(height: 8), SizedBox(height: 8),
SizedBox( SizedBox(
height: chartHeight, height: chartHeight,
child: CommonCard( child: GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
child: RankChart(title: '排行榜', data: provider.rankStats, unit: ''), child: RankChart(title: '排行榜', data: provider.rankStats, unit: ''),
), ),
), ),
@@ -105,13 +132,28 @@ class _StatsPage extends State<StatsPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final provider = context.watch<FoodProvider>(); final provider = context.watch<FoodProvider>();
return Stack( 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: [ children: [
if (provider.isLoading) if (provider.isLoading)
buildLoadingIndicator() buildLoadingIndicator()
else else
SingleChildScrollView(child: _buildContent(provider)), SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 90),
child: _buildContent(context, provider),
),
], ],
),
),
); );
} }
} }

View File

@@ -43,15 +43,17 @@ Widget buildScrollToTop({
required BuildContext context, required BuildContext context,
required VoidCallback scrollToTop, required VoidCallback scrollToTop,
}) { }) {
final colors = Theme.of(context).colorScheme;
return Positioned( return Positioned(
right: 0, right: 0,
bottom: 20, bottom: 80,
child: FloatingActionButton( child: FloatingActionButton(
onPressed: scrollToTop, onPressed: scrollToTop,
backgroundColor: Theme.of(context).colorScheme.primary, backgroundColor: colors.primary,
elevation: 2, elevation: 2,
mini: true, mini: true,
child: const Icon(Icons.arrow_upward, color: Colors.white), child: Icon(Icons.arrow_upward, color: colors.surface),
), ),
); );
} }

View File

@@ -12,26 +12,26 @@ InputDecoration buildInputDecoration({
return InputDecoration( return InputDecoration(
hintText: hintText, hintText: hintText,
hintStyle: TextStyle(color: colors.onSurface.withAlpha(100)), hintStyle: Theme.of(context).textTheme.bodyMedium,
filled: true, filled: true,
fillColor: colors.surface, fillColor: colors.surface,
border: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Color(0xFFE5E7EB)), borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(10),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: colors.primary, width: 2), borderSide: BorderSide(color: colors.primary, width: 2),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(10),
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.red, width: 2), borderSide: const BorderSide(color: Colors.red, width: 2),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(10),
), ),
contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 14), contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 14),
errorStyle: const TextStyle(fontSize: 12, height: 1, color: Colors.red), errorStyle: const TextStyle(fontSize: 12, height: 1, color: Colors.red),
prefixIcon: prefixIcon:
prefixIcon != null prefixIcon != null
? Icon(prefixIcon, size: 20, color: Color(0xFF86909C)) ? Icon(prefixIcon, size: 20, color: colors.primary)
: null, : null,
prefixIconConstraints: const BoxConstraints(minWidth: 40), prefixIconConstraints: const BoxConstraints(minWidth: 40),
isDense: true, isDense: true,

View File

@@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:food_hub_app/config/app_config.dart'; import 'package:food_hub_app/config/app_config.dart';
import 'package:photo_view/photo_view.dart'; import 'package:photo_view/photo_view.dart';
@@ -53,6 +54,8 @@ class _ImagePreviewPageState extends State<ImagePreviewPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final index = '${_currentIndex + 1}/${widget.images.length}';
return Scaffold( return Scaffold(
backgroundColor: Colors.black, backgroundColor: Colors.black,
appBar: AppBar( appBar: AppBar(
@@ -63,10 +66,7 @@ class _ImagePreviewPageState extends State<ImagePreviewPage> {
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
), ),
// 显示实时更新的页码(当前索引+1 / 总数量) // 显示实时更新的页码(当前索引+1 / 总数量)
title: Text( title: Text(index, style: const TextStyle(color: Colors.white)),
'${_currentIndex + 1}/${widget.images.length}',
style: const TextStyle(color: Colors.white),
),
centerTitle: true, centerTitle: true,
), ),
body: PhotoViewGallery( body: PhotoViewGallery(
@@ -95,21 +95,6 @@ class CommonImage extends StatelessWidget {
const CommonImage({super.key, required this.imageUrls, required this.index}); 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() { Widget _buildErrorImage() {
return Container( return Container(
color: Colors.grey[200], color: Colors.grey[200],
@@ -140,14 +125,16 @@ class CommonImage extends StatelessWidget {
onTap: () { onTap: () {
_navigateToImagePreview(context, imageUrls, index); _navigateToImagePreview(context, imageUrls, index);
}, },
child: Image.network( child: CachedNetworkImage(
'${AppConfig.imageBaseUrl}${imageUrls[index]}', imageUrl: '${AppConfig.imageBaseUrl}${imageUrls[index]}',
fit: BoxFit.cover, fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) { progressIndicatorBuilder:
if (loadingProgress == null) return child; (context, url, downloadProgress) => CircularProgressIndicator(
return _buildImageLoadingIndicator(loadingProgress); strokeWidth: 1.5,
}, padding: EdgeInsetsGeometry.all(20),
errorBuilder: (context, error, stackTrace) => _buildErrorImage(), value: downloadProgress.progress,
),
errorWidget: (context, error, stackTrace) => _buildErrorImage(),
), ),
), ),
), ),
@@ -213,19 +200,19 @@ Widget buildImageUploadButton({
onTap: onTap, onTap: onTap,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: Container( child: Container(
width: 96, width: double.infinity,
height: 96, height: 250,
decoration: BoxDecoration( decoration: BoxDecoration(
color: colors.surface, color: colors.surface,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.black), border: Border.all(color: colors.surface),
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(Icons.add, color: colors.onSurface.withAlpha(100)), Icon(Icons.camera_alt, color: colors.onSurface.withAlpha(100)),
SizedBox(height: 6), SizedBox(height: 6),
Text('添加图片', style: TextStyle(color: colors.onSurface.withAlpha(100))), Text('点击上传美食图片', style: Theme.of(context).textTheme.bodyMedium),
], ],
), ),
), ),

View File

@@ -43,8 +43,8 @@ Widget buildToggleSwitch<T extends Enum>({
totalSwitches: tabValues.length, totalSwitches: tabValues.length,
labels: labels, labels: labels,
activeBgColor: [colors.primary], activeBgColor: [colors.primary],
activeFgColor: Colors.white, activeFgColor: colors.surface,
inactiveBgColor: colors.surfaceContainer, inactiveBgColor: colors.surface,
inactiveFgColor: colors.onSurface, inactiveFgColor: colors.onSurface,
cornerRadius: 12.0, cornerRadius: 12.0,
customTextStyles: [TextStyle(fontSize: 12, fontWeight: FontWeight.w500)], customTextStyles: [TextStyle(fontSize: 12, fontWeight: FontWeight.w500)],
@@ -85,10 +85,10 @@ Widget buildTag(BuildContext context, String title) {
return Container( return Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4), padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: colors.primary.withAlpha(60), color: colors.primary,
borderRadius: BorderRadius.circular(10), 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)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
elevation: 0, 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) { Widget errorImageContainer(double height) {
return Container( return Container(

View File

@@ -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/provider/user_provider.dart';
import 'package:food_hub_app/widgets/common/image.dart'; import 'package:food_hub_app/widgets/common/image.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
class MomentCard extends StatefulWidget { class MomentCard extends StatefulWidget {
final Moment moment; final Moment moment;
@@ -26,21 +25,24 @@ class MomentCardState extends State<MomentCard> {
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
InkWell(onTap: () => _onTapUser(context), child: _buildAvatar()), InkWell(
onTap: () => _onTapUser(context),
child: _buildAvatar(context),
),
const SizedBox(width: 12), const SizedBox(width: 12),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildNickname(), _buildNickname(context),
const SizedBox(height: 5), const SizedBox(height: 5),
_buildContent(), _buildContent(context),
if (widget.moment.imageList.isNotEmpty) ...[ if (widget.moment.imageList.isNotEmpty) ...[
const SizedBox(height: 8), const SizedBox(height: 8),
_buildPostImages(), _buildPostImages(),
], ],
const SizedBox(height: 10), const SizedBox(height: 10),
_buildTime(), _buildTime(context),
const SizedBox(height: 5), const SizedBox(height: 5),
_buildActionButtons(), _buildActionButtons(),
if (widget.moment.commentList!.isNotEmpty) ...[ if (widget.moment.commentList!.isNotEmpty) ...[
@@ -69,38 +71,35 @@ class MomentCardState extends State<MomentCard> {
} }
// 构建头像组件 // 构建头像组件
Widget _buildAvatar() { Widget _buildAvatar(BuildContext context) {
if (widget.moment.avatar!.isEmpty) { if (widget.moment.avatar!.isEmpty) {
return TDAvatar( return CircleAvatar(
size: TDAvatarSize.medium, radius: 18,
type: TDAvatarType.customText,
shape: TDAvatarShape.circle,
backgroundColor: Theme.of(context).colorScheme.primary, 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 { } else {
return TDAvatar( return CircleAvatar(
size: TDAvatarSize.medium, radius: 18,
type: TDAvatarType.normal, backgroundImage: NetworkImage('${AppConfig.imageBaseUrl}/${widget.moment.avatar}')
fit: BoxFit.contain,
avatarUrl: '${AppConfig.imageBaseUrl}/${widget.moment.avatar}',
); );
} }
} }
// 构建昵称组件 // 构建昵称组件
Widget _buildNickname() { Widget _buildNickname(BuildContext context) {
return Text( return Text(
widget.moment.username ?? "", 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( return Text(
widget.moment.content, 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<MomentCard> {
} }
// 构建时间组件 // 构建时间组件
Widget _buildTime() { Widget _buildTime(BuildContext context) {
return Text( return Text(
widget.moment.date ?? "", 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<MomentCard> {
alignment: Alignment.bottomLeft, alignment: Alignment.bottomLeft,
children: [ children: [
Icon(Icons.thumb_up_alt_outlined), Icon(Icons.thumb_up_alt_outlined),
Positioned( // Positioned(
left: 20, // left: 20,
bottom: 15, // bottom: 15,
child: TDBadge( // child: TDBadge(
TDBadgeType.message, // TDBadgeType.message,
count: (widget.moment.likeList?.length ?? 0).toString(), // count: (widget.moment.likeList?.length ?? 0).toString(),
), // ),
), // ),
], ],
), ),
), ),
@@ -196,14 +195,14 @@ class MomentCardState extends State<MomentCard> {
alignment: Alignment.bottomLeft, alignment: Alignment.bottomLeft,
children: [ children: [
Icon(Icons.comment_outlined), Icon(Icons.comment_outlined),
Positioned( // Positioned(
left: 20, // left: 20,
bottom: 15, // bottom: 15,
child: TDBadge( // child: TDBadge(
TDBadgeType.message, // TDBadgeType.message,
count: (widget.moment.commentList?.length ?? 0).toString(), // count: (widget.moment.commentList?.length ?? 0).toString(),
), // ),
), // ),
], ],
), ),
), ),

View File

@@ -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/config/app_config.dart';
import 'package:food_hub_app/models/session.dart'; import 'package:food_hub_app/models/session.dart';
import 'package:food_hub_app/widgets/common/index.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 { class ProfileInfo extends StatelessWidget {
final User user; final User user;
@@ -13,19 +14,21 @@ class ProfileInfo extends StatelessWidget {
Widget _buildAvatar(BuildContext context, User user) { Widget _buildAvatar(BuildContext context, User user) {
if (user.avatar == null) { if (user.avatar == null) {
return TDAvatar( return CircleAvatar(
size: TDAvatarSize.large, radius: 24,
type: TDAvatarType.customText,
shape: TDAvatarShape.circle,
backgroundColor: Theme.of(context).colorScheme.primary, 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 { } else {
return TDAvatar( return CircleAvatar(
size: TDAvatarSize.large, radius: 24,
type: TDAvatarType.normal, backgroundImage: NetworkImage(
fit: BoxFit.contain, '${AppConfig.imageBaseUrl}/${user.avatar}',
avatarUrl: '${AppConfig.imageBaseUrl}/${user.avatar}', ),
); );
} }
} }
@@ -41,22 +44,24 @@ class ProfileInfo extends StatelessWidget {
children: [ children: [
Icon(icon, size: 16, color: colors.primary), Icon(icon, size: 16, color: colors.primary),
const SizedBox(width: 6), const SizedBox(width: 6),
Text(text), Text(text, style: Theme.of(context).textTheme.bodyMedium),
], ],
); );
} }
@override @override
Widget build(BuildContext context) { 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( child: Column(
children: [ children: [
_buildAvatar(context, user), _buildAvatar(context, user),
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(user.username, style: Theme.of(context).textTheme.titleMedium),
user.username,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8), const SizedBox(height: 8),
if (user.tags != null && user.tags!.isNotEmpty) if (user.tags != null && user.tags!.isNotEmpty)
Row( Row(

View File

@@ -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/models/recipe.dart';
import 'package:food_hub_app/provider/food_provider.dart'; import 'package:food_hub_app/provider/food_provider.dart';
import 'package:food_hub_app/utils/index.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:food_hub_app/widgets/common/index.dart';
import 'package:table_calendar/table_calendar.dart'; import 'package:table_calendar/table_calendar.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -62,19 +63,16 @@ class _RecipeCalendarState extends State<RecipeCalendar> {
Text(formatDateTime(provider.selectedDay, 'MM月dd日 EEEE')), Text(formatDateTime(provider.selectedDay, 'MM月dd日 EEEE')),
SizedBox(height: 4), SizedBox(height: 4),
if (provider.selectRecordList.isEmpty) if (provider.selectRecordList.isEmpty)
buildEmptyData() SizedBox(height: 100, child: buildEmptyData())
else else
Expanded( Column(
child: ListView.separated( children:
itemCount: provider.selectRecordList.length, provider.selectRecordList.map((record) {
separatorBuilder: (context, index) => SizedBox(height: 8), return Padding(
itemBuilder: (context, index) { padding: const EdgeInsets.only(bottom: 8),
return _buildRecordItem( child: _buildRecordItem(context, record),
context,
provider.selectRecordList[index],
); );
}, }).toList(),
),
), ),
], ],
); );
@@ -112,7 +110,15 @@ class _RecipeCalendarState extends State<RecipeCalendar> {
provider.initRecordForm(record); provider.initRecordForm(record);
provider.isEditing = true; 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) { Widget _buildRecordItem(BuildContext context, FoodRecord record) {
@@ -195,12 +201,15 @@ class _RecipeCalendarState extends State<RecipeCalendar> {
} }
Widget _buildContent(FoodProvider provider) { Widget _buildContent(FoodProvider provider) {
return Column( return SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 80),
child: Column(
children: [ children: [
CommonCard(child: _recipeCalendar(provider)), CommonCard(child: _recipeCalendar(provider)),
SizedBox(height: 8), const SizedBox(height: 8),
Expanded(child: CommonCard(child: _dailyItem(context, provider))), CommonCard(child: _dailyItem(context, provider)),
], ],
),
); );
} }
@@ -208,13 +217,10 @@ class _RecipeCalendarState extends State<RecipeCalendar> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final provider = context.watch<FoodProvider>(); final provider = context.watch<FoodProvider>();
return Stack( if (provider.isLoading) {
children: [ return buildLoadingIndicator();
if (provider.isLoading) }
buildLoadingIndicator()
else return _buildContent(provider);
_buildContent(provider),
],
);
} }
} }

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_common/widget/common_widget.dart'; import 'package:flutter_common/widget/common_widget.dart';
import 'package:food_hub_app/models/recipe.dart'; import 'package:food_hub_app/models/recipe.dart';
import 'package:food_hub_app/widgets/common/image.dart'; import 'package:food_hub_app/widgets/common/image.dart';
import 'package:liquid_glass_widgets/liquid_glass_widgets.dart';
class RecipeCard extends StatelessWidget { class RecipeCard extends StatelessWidget {
final RecipeSummary recipe; final RecipeSummary recipe;
@@ -17,14 +18,22 @@ class RecipeCard extends StatelessWidget {
final List<String> imageUrls = final List<String> imageUrls =
recipe.recordList.reversed.map((record) => record.imageUrl).toList(); 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( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
CommonImage(imageUrls: imageUrls, index: 0), CommonImage(imageUrls: imageUrls, index: 0),
SizedBox(height: 8), SizedBox(height: 8),
_buildRecipeContent(context), InkWell(
onTap: () => navigatorToRecipeDetail(context),
child: _buildRecipeContent(context),
),
], ],
), ),
); );
@@ -32,6 +41,7 @@ class RecipeCard extends StatelessWidget {
Widget _buildRecipeContent(BuildContext context) { Widget _buildRecipeContent(BuildContext context) {
final colors = Theme.of(context).colorScheme; final colors = Theme.of(context).colorScheme;
final textTheme = Theme.of(context).textTheme;
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@@ -42,17 +52,10 @@ class RecipeCard extends StatelessWidget {
children: [ children: [
Text( Text(
recipe.name, recipe.name,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), style: textTheme.titleMedium,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
InkWell(
onTap: () => navigatorToRecipeDetail(context),
child: Icon(
Icons.arrow_circle_right_sharp,
color: colors.secondary,
),
),
], ],
), ),
SizedBox(height: 5), SizedBox(height: 5),
@@ -62,19 +65,13 @@ class RecipeCard extends StatelessWidget {
_buildIconText( _buildIconText(
icon: Icons.food_bank, icon: Icons.food_bank,
text: recipe.category, text: recipe.category,
color: Color(0xFF6A5ACD), color: colors.primary,
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
_buildIconText( _buildIconText(
icon: Icons.thumb_up_alt_outlined, icon: Icons.note_add,
text: recipe.likeCount.toString(), text: recipe.recordList.length.toString(),
color: Color(0xFFDC143C), color: colors.primary,
),
const SizedBox(width: 12),
_buildIconText(
icon: Icons.star_outline,
text: recipe.favouriteCount.toString(),
color: Color(0xFF20B2AA),
), ),
], ],
), ),

View File

@@ -23,55 +23,9 @@ class _RecipeListState extends State<RecipeList> {
}); });
} }
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<String>(
value: provider.queryCategory,
isExpanded: true,
borderRadius: BorderRadius.circular(12),
dropdownColor: colors.surfaceContainer,
elevation: 6,
underline: Container(),
items:
provider.categoryList.map((String value) {
return DropdownMenuItem<String>(
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) { Widget _buildRecipeList(FoodProvider provider) {
return GridView.builder( return GridView.builder(
padding: const EdgeInsets.only(bottom: 80),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, crossAxisCount: 2,
crossAxisSpacing: 8, crossAxisSpacing: 8,
@@ -91,8 +45,6 @@ class _RecipeListState extends State<RecipeList> {
} else { } else {
return Column( return Column(
children: [ children: [
_buildSelectCategory(provider),
SizedBox(height: 5),
Expanded(child: _buildRecipeList(provider)), Expanded(child: _buildRecipeList(provider)),
], ],
); );

View File

@@ -28,26 +28,24 @@ class _RecipeTimeline extends State<RecipeTimeline> {
SizedBox(width: 5), SizedBox(width: 5),
Text( Text(
record.date, record.date,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), style: Theme.of(context).textTheme.titleMedium,
), ),
], ],
), ),
SizedBox(height: 6), SizedBox(height: 8),
Padding( CommonCard(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 0),
child: CommonCard(
child: Column( child: Column(
children: [ children: [
Text( Text(
record.name, record.name,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), style: Theme.of(context).textTheme.titleMedium,
), ),
const SizedBox(height: 5), const SizedBox(height: 5),
CommonImage(imageUrls: [record.imageUrl], index: 0), CommonImage(imageUrls: [record.imageUrl], index: 0),
], ],
), ),
), ),
), SizedBox(height: 20)
], ],
); );
} }
@@ -59,6 +57,7 @@ class _RecipeTimeline extends State<RecipeTimeline> {
final colors = Theme.of(context).colorScheme; final colors = Theme.of(context).colorScheme;
return Timeline.tileBuilder( return Timeline.tileBuilder(
padding: const EdgeInsets.only(bottom: 80),
theme: TimelineThemeData(nodePosition: 0, indicatorPosition: 0), theme: TimelineThemeData(nodePosition: 0, indicatorPosition: 0),
builder: TimelineTileBuilder.connected( builder: TimelineTileBuilder.connected(
itemCount: recordList.length, itemCount: recordList.length,

View File

@@ -6,14 +6,10 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <rive_native/rive_native_plugin.h> #include <rive_native/rive_native_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { 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 = g_autoptr(FlPluginRegistrar) rive_native_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "RiveNativePlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "RiveNativePlugin");
rive_native_plugin_register_with_registrar(rive_native_registrar); rive_native_plugin_register_with_registrar(rive_native_registrar);

View File

@@ -3,7 +3,6 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
rive_native rive_native
url_launcher_linux url_launcher_linux
) )

View File

@@ -6,19 +6,19 @@ import FlutterMacOS
import Foundation import Foundation
import file_picker import file_picker
import file_selector_macos
import flutter_image_compress_macos import flutter_image_compress_macos
import path_provider_foundation import path_provider_foundation
import rive_native import rive_native
import share_plus import share_plus
import shared_preferences_foundation import shared_preferences_foundation
import sqflite_darwin
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin")) FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
RiveNativePlugin.register(with: registry.registrar(forPlugin: "RiveNativePlugin")) RiveNativePlugin.register(with: registry.registrar(forPlugin: "RiveNativePlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
} }

View File

@@ -121,6 +121,30 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "8.10.1" 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: characters:
dependency: transitive dependency: transitive
description: description:
@@ -213,18 +237,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: dio name: dio
sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "5.8.0+1" version: "5.9.2"
dio_web_adapter: dio_web_adapter:
dependency: transitive dependency: transitive
description: description:
name: dio_web_adapter name: dio_web_adapter
sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
easy_refresh: easy_refresh:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -233,14 +257,22 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.4.0" 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: fake_async:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.2" version: "1.3.3"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
@@ -310,6 +342,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" 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: flutter_carousel_widget:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -402,22 +442,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.28" version: "2.0.28"
flutter_slidable: flutter_shaders:
dependency: transitive dependency: transitive
description: description:
name: flutter_slidable name: flutter_shaders
sha256: a857de7ea701f276fd6a6c4c67ae885b60729a3449e42766bb0e655171042801 sha256: "34794acadd8275d971e02df03afee3dee0f98dbfb8c4837082ad0034f612a3e2"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.1.2" version: "0.1.3"
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"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@@ -432,10 +464,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: fluttertoast name: fluttertoast
sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1" sha256: "90778fe0497fe3a09166e8cf2e0867310ff434b794526589e77ec03cf08ba8e8"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "8.2.12" version: "8.2.14"
form_builder_validators: form_builder_validators:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -560,10 +592,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.19.0" version: "0.20.2"
io: io:
dependency: transitive dependency: transitive
description: description:
@@ -600,26 +632,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "10.0.8" version: "11.0.2"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.9" version: "3.0.10"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.1" version: "3.0.2"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@@ -628,6 +660,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "5.1.1" 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: logger:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -664,10 +704,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.16.0" version: "1.17.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@@ -692,6 +732,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.0" 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: package_config:
dependency: transitive dependency: transitive
description: description:
@@ -840,18 +888,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: rive name: rive
sha256: fc0abf65d03d1c9afaeb35be9e71c7cf04d2d1f76e94e69d2af1b3ba413cddf9 sha256: "84a640f48122679e48397935ed1b971db19ef2e44bfcbae60e42fb5ce29a0a4e"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.14.0-dev.14" version: "0.14.9"
rive_native: rive_native:
dependency: transitive dependency: transitive
description: description:
name: rive_native name: rive_native
sha256: e9c7d36f19eb6d32f563825d4e9d5032b19a36d3ca3341641431035bca022d19 sha256: "85dc8413398f7540eab9b73c6d704ecd5051ab9c57e539eed85ccd2a69f119aa"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted 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: share_plus:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -872,26 +928,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences name: shared_preferences
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.5.3" version: "2.5.5"
shared_preferences_android: shared_preferences_android:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.4.10" version: "2.4.23"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_foundation name: shared_preferences_foundation
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.5.4" version: "2.5.6"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
@@ -904,10 +960,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_platform_interface name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.4.1" version: "2.4.2"
shared_preferences_web: shared_preferences_web:
dependency: transitive dependency: transitive
description: description:
@@ -977,6 +1033,46 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.10.1" 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: stack_trace:
dependency: transitive dependency: transitive
description: description:
@@ -1013,34 +1109,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: syncfusion_flutter_charts name: syncfusion_flutter_charts
sha256: c58ca79e072680af6f0554f7c4b91886c1d8808f2522b49d557f16fb5cb3bb04 sha256: "68fdb029dad34a46e4c9cfad8ad66fe29db7b303bd96849261ab2b23a168d0e8"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "30.1.41" version: "30.2.7"
syncfusion_flutter_core: syncfusion_flutter_core:
dependency: transitive dependency: transitive
description: description:
name: syncfusion_flutter_core name: syncfusion_flutter_core
sha256: "536753489e168f49659261d0abd02b101b34c0b1bde27898f2869aab05f1cbb6" sha256: bfd026c0f9822b49ff26fed11cd3334519acb6a6ad4b0c81d9cd18df6af1c4c0
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted 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: table_calendar:
dependency: "direct main" dependency: "direct main"
description: description:
name: table_calendar name: table_calendar
sha256: b2896b7c86adf3a4d9c911d860120fe3dbe03c85db43b22fd61f14ee78cdbb63 sha256: "0c0c6219878b363a2d5f40c7afb159d845f253d061dc3c822aa0d5fe0f721982"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.1.3" version: "3.2.0"
tdesign_flutter:
dependency: "direct main"
description:
name: tdesign_flutter
sha256: b36b6f939f7a585184665202b6b3acf1922728962312b65182dbbff64c3b62f2
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.3"
tdesign_flutter_adaptation: tdesign_flutter_adaptation:
dependency: "direct overridden" dependency: "direct overridden"
description: description:
@@ -1061,10 +1157,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.7.4" version: "0.7.7"
timelines_plus: timelines_plus:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -1141,10 +1237,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.4" version: "2.2.0"
vm_service: vm_service:
dependency: transitive dependency: transitive
description: description:
@@ -1218,5 +1314,5 @@ packages:
source: hosted source: hosted
version: "3.1.3" version: "3.1.3"
sdks: sdks:
dart: ">=3.7.0 <4.0.0" dart: ">=3.10.0 <4.0.0"
flutter: ">=3.29.0" flutter: ">=3.38.0"

View File

@@ -1 +1 @@
name: food_hub_app name: food_hub_app

View File

@@ -6,14 +6,11 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
#include <rive_native/rive_native_plugin.h> #include <rive_native/rive_native_plugin.h>
#include <share_plus/share_plus_windows_plugin_c_api.h> #include <share_plus/share_plus_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
RiveNativePluginRegisterWithRegistrar( RiveNativePluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("RiveNativePlugin")); registry->GetRegistrarForPlugin("RiveNativePlugin"));
SharePlusWindowsPluginCApiRegisterWithRegistrar( SharePlusWindowsPluginCApiRegisterWithRegistrar(

View File

@@ -3,7 +3,6 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
rive_native rive_native
share_plus share_plus
url_launcher_windows url_launcher_windows