import 'package:flutter/material.dart'; import 'package:food_hub_app/api/recipe.dart'; import 'package:food_hub_app/config/app_config.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/index.dart'; import 'package:food_hub_app/widgets/common/year_selector.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; import 'package:timelines_plus/timelines_plus.dart'; class RecipeTimeline extends StatefulWidget { const RecipeTimeline({super.key}); @override State createState() => _RecipeTimeline(); } class _RecipeTimeline extends State { List recordList = []; @override void initState() { super.initState(); refreshRecord(DateTime.now().year); } Future refreshRecord(int year) async { final result = await queryRecordApi("$year-01-01", "$year-12-31"); setState(() { recordList = result; }); } @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.all(10), child: Column( children: [ YearSelector( initialYear: DateTime.now().year, minYear: 2000, maxYear: 2100, onYearChanged: (year) => refreshRecord(year), ), SizedBox(height: 10), Expanded(child: timelineContainer(recordList)), ], ), ); } } Widget timelineContainer(List recordList) { if (recordList.isEmpty) { return const TDEmpty(type: TDEmptyType.plain, emptyText: '暂无数据'); } else { return Timeline.tileBuilder( theme: TimelineThemeData(nodePosition: 0, indicatorPosition: 0), builder: TimelineTileBuilder.connected( itemCount: recordList.length, connectorBuilder: (context, index, type) => Connector.solidLine( thickness: 2, color: Theme.of(context).primaryColor, ), indicatorBuilder: (context, index) { return Indicator.dot( size: 12.0, color: Theme.of(context).primaryColor, ); }, contentsBuilder: (context, index) { return TimelineCard(record: recordList[index]); }, ), ); } } class TimelineCard extends StatelessWidget { final Record record; const TimelineCard({super.key, required this.record}); Widget cardContent(BuildContext context) { final imageUrls = ['${AppConfig.baseApiUrl}/${record.imageUrl}']; void imageTapClick() { Navigator.push( context, MaterialPageRoute( builder: (context) => ImagePreviewPage(images: imageUrls, initialIndex: 0), ), ); } return Card( elevation: 0, color: Colors.white, child: Padding( padding: EdgeInsets.all(10), child: Column( children: [ Text(record.name, style: TextStyle(fontSize: 16)), const SizedBox(height: 5), GestureDetector( onTap: () => imageTapClick(), child: AspectRatio( aspectRatio: 1.5, child: networkImage(imageUrls[0]), ), ), ], ), ), ); } @override Widget build(BuildContext context) { return SizedBox( width: double.infinity, child: Padding( padding: const EdgeInsets.only(left: 10, bottom: 5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( record.date, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), cardContent(context), ], ), ), ); } }