feat:增加图表组件

This commit is contained in:
2025-07-13 22:00:55 +08:00
parent 55ca36cba2
commit 8a1b507166
14 changed files with 464 additions and 218 deletions

132
lib/layout/index.dart Normal file
View File

@@ -0,0 +1,132 @@
import 'package:flutter/material.dart';
class NavBar extends StatelessWidget {
final int currentIndex;
final Function(int) onTap;
static const List<BottomNavigationBarItem> navItems = [
BottomNavigationBarItem(
icon: Icon(Icons.home_outlined),
activeIcon: Icon(Icons.home),
label: "记录",
),
BottomNavigationBarItem(
icon: Icon(Icons.pie_chart_outline),
activeIcon: Icon(Icons.pie_chart),
label: "统计",
),
BottomNavigationBarItem(
icon: Icon(Icons.group_outlined),
activeIcon: Icon(Icons.group),
label: "朋友圈",
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle_outlined),
activeIcon: Icon(Icons.account_circle),
label: "我的",
),
];
const NavBar({super.key, required this.currentIndex, required this.onTap});
@override
Widget build(BuildContext context) {
return BottomNavigationBar(
currentIndex: currentIndex,
iconSize: 25,
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.white,
items: navItems,
onTap: onTap,
);
}
}
class SettingsDrawer extends StatelessWidget {
const SettingsDrawer({super.key});
@override
Widget build(BuildContext context) {
// final themeProvider = Provider.of<ThemeProvider>(context);
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 100),
child: DrawerHeader(
decoration: BoxDecoration(color: Theme.of(context).primaryColor),
child: const Text(
'设置',
style: TextStyle(color: Colors.white, fontSize: 24),
),
),
),
ListTile(
leading: const Icon(Icons.brightness_4),
title: const Text('夜间模式'),
// trailing: Switch(
// value: themeProvider.isDarkMode,
// onChanged: (bool value) {
// themeProvider.toggleTheme();
// },
// ),
// onTap: () => themeProvider.toggleTheme(),
),
// 其他设置选项
ListTile(
leading: const Icon(Icons.notifications),
title: const Text('通知设置'),
onTap: () {
Navigator.pop(context); // 关闭抽屉
// 跳转到通知设置页面
},
),
ListTile(
leading: const Icon(Icons.language),
title: const Text('语言'),
onTap: () {
Navigator.pop(context); // 关闭抽屉
// 跳转到语言设置页面
},
),
// 底部关于
const Divider(),
ListTile(
leading: const Icon(Icons.info),
title: const Text('关于我们'),
onTap: () {
Navigator.pop(context); // 关闭抽屉
// 跳转到关于页面
},
),
],
),
);
}
}
List<StatelessWidget> homeActions() {
return [
IconButton(
icon: Icon(Icons.search, color: Colors.white),
onPressed: () {
// 搜索功能
},
),
Builder(
builder: (BuildContext context) {
return IconButton(
icon: Icon(Icons.settings, color: Colors.white),
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
);
},
),
];
}

View File

@@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:food_hub_app/profile.dart'; import 'package:food_hub_app/views/home.dart';
import 'package:food_hub_app/record.dart';
import 'package:food_hub_app/views/login.dart'; import 'package:food_hub_app/views/login.dart';
import 'package:food_hub_app/views/recordForm.dart'; import 'package:food_hub_app/views/recordForm.dart';
import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:form_builder_validators/form_builder_validators.dart';
@@ -19,7 +18,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
theme: ThemeData(fontFamily: 'CustomFont', primaryColor: Colors.green), theme: ThemeData(fontFamily: 'CustomFont'),
supportedLocales: const [ supportedLocales: const [
Locale('en', 'US'), // 英语 Locale('en', 'US'), // 英语
Locale('zh', 'CN'), // 中文 Locale('zh', 'CN'), // 中文
@@ -41,89 +40,9 @@ class MyApp extends StatelessWidget {
}, },
home: LoginPage(), home: LoginPage(),
routes: { routes: {
'/home': (context) => MainPage(), '/home': (context) => HomePage(),
'/recordForm': (context) => RecordFormPage(), '/recordForm': (context) => RecordFormPage(),
}, },
); );
} }
} }
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
State<StatefulWidget> createState() => _MainPage();
}
class _MainPage extends State<MainPage> {
int _currentIndex = 0;
final List<Widget> _tabPages = const [RecordPage(), ProfilePage()];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Food Hub'),
backgroundColor: Colors.green,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () {
// 打开侧边栏或菜单
},
),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {
// 搜索功能
},
),
IconButton(
icon: Icon(Icons.more_vert),
onPressed: () {
// 更多选项
},
),
],
),
backgroundColor: Color(0xFFF5F5F5),
body: _tabPages[_currentIndex],
floatingActionButton:
_currentIndex == _tabPages.length - 1 ? null : addItemButton(context),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
iconSize: 25,
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.white,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: "记录"),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
label: "我的",
),
],
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
);
}
}
Widget addItemButton(BuildContext context) {
void onAddItemClick(BuildContext context) {
Navigator.pushNamed(context, '/recordForm');
}
return FloatingActionButton(
mini: true,
onPressed: () => onAddItemClick(context),
backgroundColor: Colors.green,
shape: const CircleBorder(),
child: Icon(Icons.add, color: Colors.white),
);
}

View File

@@ -8,14 +8,23 @@ class Recipe {
final int commentCount; final int commentCount;
Recipe( Recipe(
this.name, this.name,
this.category, this.category,
this.date, this.date,
this.imageUrl, this.imageUrl,
this.likeCount, this.likeCount,
this.favoriteCount, this.favoriteCount,
this.commentCount, this.commentCount,
); );
}
class Record {
final String name;
final String category;
final String date;
final String imageUrl;
Record(this.name, this.category, this.date, this.imageUrl);
} }
enum ViewType { recipe, calendar, timeline } enum ViewType { recipe, calendar, timeline }

17
lib/utils/index.dart Normal file
View File

@@ -0,0 +1,17 @@
import 'package:intl/intl.dart';
/// 解析日期选择器
String parseDatePickerSelected(Map<String, int> selected) {
final String year = selected['year'].toString().padLeft(4, '0');
final String month = selected['month'].toString().padLeft(2, '0');
final String day = selected['day'].toString().padLeft(2, '0');
return '$year-$month-$day';
}
/// 格式化时间
String formatDateTime(DateTime dateTime, [String format = 'yyyy-MM-dd']) {
final DateFormat formatter = DateFormat(format);
// return formatter.format(dateTime);
return Intl.withLocale('zh_CN', () => formatter.format(dateTime));
}

73
lib/views/home.dart Normal file
View File

@@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:food_hub_app/layout/index.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';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePage();
}
class _HomePage extends State<HomePage> {
int _currentIndex = 0;
final List<Widget> _tabPages = const [
RecordPage(),
StatsPage(),
MomentPage(),
ProfilePage(),
];
bool isShow(int index) {
return index == 0 || index == 2;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Food Hub', style: TextStyle(color: Colors.white)),
backgroundColor: Theme.of(context).primaryColor,
leading: IconButton(
icon: Icon(Icons.menu, color: Colors.white),
onPressed: () {
// 打开侧边栏或菜单
},
),
actions: homeActions(),
),
backgroundColor: Color(0xFFF5F5F5),
endDrawer: const SettingsDrawer(),
body: _tabPages[_currentIndex],
floatingActionButton:
isShow(_currentIndex) ? addItemButton(context) : null,
bottomNavigationBar: NavBar(
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
);
}
}
Widget addItemButton(BuildContext context) {
void onAddItemClick(BuildContext context) {
Navigator.pushNamed(context, '/recordForm');
}
return FloatingActionButton(
mini: true,
onPressed: () => onAddItemClick(context),
backgroundColor: Theme.of(context).primaryColor,
shape: const CircleBorder(),
child: Icon(Icons.add, color: Colors.white),
);
}

View File

@@ -24,12 +24,30 @@ class _LoginPage extends State<LoginPage> {
]; ];
void loginClick(BuildContext context) { void loginClick(BuildContext context) {
Navigator.pushNamed(context, '/home');
return;
// 表单校验通过才会继续执行 // 表单校验通过才会继续执行
if ((_formKey.currentState as FormState).validate()) { if ((_formKey.currentState as FormState).validate()) {
(_formKey.currentState as FormState).save(); (_formKey.currentState as FormState).save();
TDMessage.showMessage(
context: context,
visible: true,
icon: true,
content: "登录成功",
theme: MessageTheme.success,
duration: 3000,
);
Navigator.pushNamed(context, '/home'); Navigator.pushNamed(context, '/home');
} else { } else {
// showErrorToast("请先输入信息"); TDMessage.showMessage(
context: context,
visible: true,
icon: true,
content: "请先输入信息",
theme: MessageTheme.error,
duration: 3000,
);
} }
} }

15
lib/views/moment.dart Normal file
View File

@@ -0,0 +1,15 @@
import 'package:flutter/material.dart';
class MomentPage extends StatefulWidget {
const MomentPage({super.key});
@override
State<MomentPage> createState() => _MomentPage();
}
class _MomentPage extends State<MomentPage>{
@override
Widget build(BuildContext context) {
return const Center(child: Text("朋友圈"));
}
}

View File

@@ -4,7 +4,7 @@ import 'package:food_hub_app/widgets/recipe/recipe_list.dart';
import 'package:food_hub_app/widgets/recipe/recipe_timeline.dart'; import 'package:food_hub_app/widgets/recipe/recipe_timeline.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart';
import 'models/recipe.dart'; import '../models/recipe.dart';
class RecordPage extends StatefulWidget { class RecordPage extends StatefulWidget {
const RecordPage({super.key}); const RecordPage({super.key});
@@ -20,6 +20,11 @@ class _RecordPageState extends State<RecordPage>
Recipe("红烧肉", "家常菜", "2025-05-05", "https://picsum.photos/200", 12, 4, 7), Recipe("红烧肉", "家常菜", "2025-05-05", "https://picsum.photos/200", 12, 4, 7),
]; ];
final List<Record> recordList = [
Record("韭菜炒鸡蛋", "家常菜", "2025-05-04", "https://picsum.photos/200"),
Record("红烧肉", "家常菜", "2025-05-05", "https://picsum.photos/200"),
];
late final TabController _tabController = TabController( late final TabController _tabController = TabController(
length: 3, length: 3,
vsync: this, vsync: this,
@@ -39,7 +44,7 @@ class _RecordPageState extends State<RecordPage>
// //
final List<TDTab> tabs = [ final List<TDTab> tabs = [
const TDTab(text: '菜谱', icon: Icon(Icons.book)), const TDTab(text: '菜谱', icon: Icon(Icons.book)),
const TDTab(text: '日历', icon: Icon(Icons.calendar_today)), const TDTab(text: '日历', icon: Icon(Icons.calendar_month)),
const TDTab(text: '时间轴', icon: Icon(Icons.timeline)), const TDTab(text: '时间轴', icon: Icon(Icons.timeline)),
]; ];
@@ -49,7 +54,6 @@ class _RecordPageState extends State<RecordPage>
padding: EdgeInsets.all(0), padding: EdgeInsets.all(0),
child: Column( child: Column(
children: [ children: [
//
TDTabBar( TDTabBar(
tabs: tabs, tabs: tabs,
controller: _tabController, controller: _tabController,

View File

@@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:food_hub_app/utils/index.dart';
import 'package:food_hub_app/widgets/common/index.dart'; import 'package:food_hub_app/widgets/common/index.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart';
@@ -28,29 +29,7 @@ class _RecordFormPage extends State<RecordFormPage> {
XFile? _selectedImage; XFile? _selectedImage;
/// 整个表单存放的数据 /// 整个表单存放的数据
Map<String, dynamic> _formData = { Map<String, dynamic> _formData = {"name": '', "date": '', "photo": ''};
"name": '',
"date": '',
"gender": '',
"birth": '',
"place": '',
"age": "2",
"description": "2",
"resume": '',
"photo": '',
};
Map<String, dynamic> _formItemNotifier = {
"name": '',
"password": '',
"gender": '',
"birth": '',
"place": '',
"age": '2',
"description": '',
"resume": '',
"photo": "",
};
/// 定义整个校验规则 /// 定义整个校验规则
final Map<String, TDFormValidation> _validationRules = { final Map<String, TDFormValidation> _validationRules = {
@@ -71,14 +50,6 @@ class _RecordFormPage extends State<RecordFormPage> {
), ),
}; };
void confirmClick(BuildContext context) {
if (_formKey.currentState?.saveAndValidate() ?? false) {
// showSuccessToast("新增记录成功");
} else {
// showErrorToast("请先提交信息");
}
}
List<TDUploadFile> files = []; List<TDUploadFile> files = [];
List<TDUploadFile> _onValueChanged( List<TDUploadFile> _onValueChanged(
@@ -108,28 +79,28 @@ class _RecordFormPage extends State<RecordFormPage> {
@override @override
void initState() { void initState() {
/// 三个文本型的表格单元
for (var i = 0; i < 4; i++) {
_controller.add(TextEditingController());
}
_formData.forEach((key, value) {
_formItemNotifier[key] = FormItemNotifier();
});
super.initState(); super.initState();
} }
@override @override
void dispose() { void dispose() {
// TODO: implement dispose
super.dispose(); super.dispose();
} }
String parseDatePickerSelected(Map<String, int> selected) { void _confirmClick(BuildContext context) {
final String year = selected['year'].toString().padLeft(4, '0'); if (_formKey.currentState?.saveAndValidate() ?? false) {
final String month = selected['month'].toString().padLeft(2, '0'); // showSuccessToast("新增记录成功");
final String day = selected['day'].toString().padLeft(2, '0'); print(_formData);
} else {
return '$year-$month-$day'; TDMessage.showMessage(
context: context,
visible: true,
icon: true,
content: "请先输入信息",
theme: MessageTheme.error,
duration: 3000,
);
}
} }
TDFormItem buildNameItem() { TDFormItem buildNameItem() {
@@ -150,8 +121,8 @@ class _RecordFormPage extends State<RecordFormPage> {
backgroundColor: Colors.white, backgroundColor: Colors.white,
additionInfoColor: TDTheme.of(context).errorColor6, additionInfoColor: TDTheme.of(context).errorColor6,
showBottomDivider: false, showBottomDivider: false,
onChanged: (val) { onChanged: (value) {
_formData['name'] = val; _formData['name'] = value;
}, },
), ),
); );
@@ -168,21 +139,19 @@ class _RecordFormPage extends State<RecordFormPage> {
hintText: '请选择完成时间', hintText: '请选择完成时间',
select: _formData['date'], select: _formData['date'],
selectFn: (BuildContext context) { selectFn: (BuildContext context) {
DateTime now = DateTime.now();
TDPicker.showDatePicker( TDPicker.showDatePicker(
context, context,
title: '选择时间', title: '选择时间',
onConfirm: (selected) { onConfirm: (selected) {
setState(() { setState(() {
print(selected); _formData['date'] = parseDatePickerSelected(selected);
_selected_1 =
'${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}';
_formItemNotifier['birth']?.upDataForm(_selected_1);
}); });
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
dateStart: [1999, 01, 01], dateStart: [2000, 01, 01],
dateEnd: [2050, 12, 31], dateEnd: [2100, 12, 31],
initialDate: [2012, 1, 1], initialDate: [now.year, now.month, now.day],
); );
}, },
); );
@@ -194,7 +163,6 @@ class _RecordFormPage extends State<RecordFormPage> {
name: 'photo', name: 'photo',
labelWidth: 82.0, labelWidth: 82.0,
type: TDFormItemType.upLoadImg, type: TDFormItemType.upLoadImg,
formItemNotifier: _formItemNotifier['photo'],
child: TDUpload( child: TDUpload(
files: files, files: files,
onError: print, onError: print,
@@ -202,9 +170,7 @@ class _RecordFormPage extends State<RecordFormPage> {
onChange: ((imgList, type) { onChange: ((imgList, type) {
files = _onValueChanged(files ?? [], imgList, type); files = _onValueChanged(files ?? [], imgList, type);
List imgs = files.map((e) => e.remotePath ?? e.assetPath).toList(); List imgs = files.map((e) => e.remotePath ?? e.assetPath).toList();
setState(() { setState(() {});
_formItemNotifier['photo'].upDataForm(imgs.join(','));
});
}), }),
), ),
); );
@@ -214,21 +180,16 @@ class _RecordFormPage extends State<RecordFormPage> {
return Container( return Container(
decoration: BoxDecoration(color: TDTheme.of(context).whiteColor1), decoration: BoxDecoration(color: TDTheme.of(context).whiteColor1),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(10),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
child: TDButton( child: TDButton(
text: '重置', text: '取消',
type: TDButtonType.fill, type: TDButtonType.fill,
theme: TDButtonTheme.light, theme: TDButtonTheme.light,
shape: TDButtonShape.rectangle, shape: TDButtonShape.rectangle,
onTap: () { onTap: () => Navigator.pop(context),
//用户名称
_controller[0].clear();
//密码
_controller[1].clear();
},
), ),
), ),
SizedBox(width: 20), SizedBox(width: 20),
@@ -238,7 +199,7 @@ class _RecordFormPage extends State<RecordFormPage> {
type: TDButtonType.fill, type: TDButtonType.fill,
theme: TDButtonTheme.primary, theme: TDButtonTheme.primary,
shape: TDButtonShape.rectangle, shape: TDButtonShape.rectangle,
onTap: () => {}, onTap: () => _confirmClick(context),
), ),
), ),
], ],
@@ -250,7 +211,14 @@ class _RecordFormPage extends State<RecordFormPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar(title: Text('新增记录'), backgroundColor: Colors.white), appBar: AppBar(
title: Text('新增记录', style: TextStyle(color: Colors.white)),
backgroundColor: Theme.of(context).primaryColor,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context)
),
),
backgroundColor: Color(0xFFF5F5F5), backgroundColor: Color(0xFFF5F5F5),
body: Padding( body: Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),

35
lib/views/stats.dart Normal file
View File

@@ -0,0 +1,35 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
class StatsPage extends StatefulWidget {
const StatsPage({super.key});
@override
State<StatsPage> createState() => _StatsPage();
}
class _StatsPage extends State<StatsPage>{
@override
Widget build(BuildContext context) {
// 月度做菜次数数据
final List<FlSpot> spots = [
FlSpot(0, 13), FlSpot(1, 32), FlSpot(2, 121),
FlSpot(3, 31), FlSpot(4, 34), FlSpot(5, 45)
];
// 月份标签
final List<String> months = [
'1月', '2月', '3月', '4月', '5月', '6月'
];
return LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
spots: spots,
),
],
),
);
}
}

View File

@@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:food_hub_app/utils/index.dart';
import 'package:table_calendar/table_calendar.dart'; import 'package:table_calendar/table_calendar.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
class RecipeCalendar extends StatefulWidget { class RecipeCalendar extends StatefulWidget {
const RecipeCalendar({super.key}); const RecipeCalendar({super.key});
@@ -9,50 +11,104 @@ class RecipeCalendar extends StatefulWidget {
} }
class _RecipeCalendarState extends State<RecipeCalendar> { class _RecipeCalendarState extends State<RecipeCalendar> {
// 当前选中的日期
DateTime _selectedDay = DateTime.now(); DateTime _selectedDay = DateTime.now();
// 当前显示的月份
DateTime _focusedDay = DateTime.now(); DateTime _focusedDay = DateTime.now();
TableCalendar recipeCalendar() {
return TableCalendar(
locale: 'zh_CN',
headerStyle: const HeaderStyle(
formatButtonVisible: false,
titleCentered: true,
),
firstDay: DateTime.utc(2010, 1, 1),
lastDay: DateTime.utc(2100, 12, 31),
focusedDay: _focusedDay,
selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
onDaySelected: (selectedDay, focusedDay) {
if (!isSameDay(_selectedDay, selectedDay)) {
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
}
},
onPageChanged: (focusedDay) {
print("cxx");
_focusedDay = focusedDay;
},
);
}
Widget dailyItem() {
return Card(
elevation: 0,
color: Colors.white,
child: Padding(
padding: EdgeInsets.all(5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(formatDateTime(_selectedDay, 'MM月dd日 EEEE')),
recipeRecordItem(),
],
),
),
);
}
Widget recipeRecordItem() {
return Card(
elevation: 0,
color: Colors.limeAccent.shade100,
child: Padding(
padding: EdgeInsets.all(10),
child: Row(
children: [
TDAvatar(
size: TDAvatarSize.medium,
type: TDAvatarType.customText,
text: 'A',
),
SizedBox(width: 10),
Expanded(
// 使用Expanded让文本区域占据剩余空间
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"青椒土豆丝",
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: 5),
Text("家常菜", style: TextStyle(color: Colors.grey)),
],
),
),
SizedBox(width: 10),
TDButton(
icon: TDIcons.arrow_right,
type: TDButtonType.fill,
shape: TDButtonShape.circle,
theme: TDButtonTheme.primary,
),
],
),
),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
children: [ children: [
Card( Card(elevation: 0, color: Colors.white, child: recipeCalendar()),
elevation: 0, const SizedBox(height: 10),
color: Colors.white, dailyItem(),
child: TableCalendar(
locale: 'zh_CN',
headerStyle: const HeaderStyle(
formatButtonVisible: false,
titleCentered: true,
),
firstDay: DateTime.utc(2010, 1, 1),
lastDay: DateTime.utc(2100, 12, 31),
focusedDay: _focusedDay,
selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
onDaySelected: (selectedDay, focusedDay) {
if (!isSameDay(_selectedDay, selectedDay)) {
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
}
},
onPageChanged: (focusedDay) {
print("cxx");
_focusedDay = focusedDay;
},
),
),
// 显示选中的日期
const SizedBox(height: 16),
Text(
'选中的日期: ${_selectedDay.year}-${_selectedDay.month}-${_selectedDay.day}',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
], ],
); );
} }
} }

View File

@@ -65,6 +65,14 @@ 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: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.7"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@@ -105,27 +113,19 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.9.3+4" version: "0.9.3+4"
fl_chart:
dependency: "direct main"
description:
name: fl_chart
sha256: "577aeac8ca414c25333334d7c4bb246775234c0e44b38b10a82b559dd4d764e7"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_date_pickers:
dependency: "direct main"
description:
name: flutter_date_pickers
sha256: "302b1200d8859ec0bfe51c4eaea5f4911d1dbfc3c3f7d256dcf32d99fec219ee"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.4.3"
flutter_datetime_picker_plus:
dependency: "direct main"
description:
name: flutter_datetime_picker_plus
sha256: "7d82da02c4e070bb28a9107de119ad195e2319b45c786fecc13482a9ffcc51da"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.0"
flutter_form_builder: flutter_form_builder:
dependency: "direct main" dependency: "direct main"
description: description:

View File

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