115 lines
3.7 KiB
Dart
115 lines
3.7 KiB
Dart
import 'package:animations/animations.dart';
|
|
import 'package:dietary_guard/controllers/food_data.dart';
|
|
import 'package:dietary_guard/models/food_data.dart';
|
|
import 'package:dietary_guard/screens/food/details.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
|
class QueryScreen extends StatefulWidget {
|
|
const QueryScreen({super.key});
|
|
|
|
@override
|
|
State<QueryScreen> createState() => _QueryScreenState();
|
|
}
|
|
|
|
class _QueryScreenState extends State<QueryScreen> {
|
|
bool _isLoading = false;
|
|
bool _hasApiKey = true;
|
|
|
|
int? _totalCount;
|
|
List<FoodData> _foodData = List.empty();
|
|
|
|
Future<void> _searchFood(String probe) async {
|
|
if (_isLoading) return;
|
|
|
|
setState(() => _isLoading = true);
|
|
|
|
final FoodDataController data = Get.find();
|
|
if (data.getApiKey() == null || data.getApiKey()!.isEmpty) {
|
|
setState(() => _hasApiKey = false);
|
|
return;
|
|
}
|
|
|
|
final result = await data.searchFood(probe);
|
|
|
|
setState(() {
|
|
_totalCount = result.totalHits;
|
|
_foodData = result.foods;
|
|
_isLoading = false;
|
|
});
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
final FoodDataController data = Get.find();
|
|
data.initialize(context).then((_) {
|
|
setState(() {
|
|
_hasApiKey = data.getApiKey() != null && data.getApiKey()!.isNotEmpty;
|
|
});
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Material(
|
|
color: Theme.of(context).colorScheme.surface,
|
|
child: SafeArea(
|
|
child: Column(
|
|
children: [
|
|
if (!_hasApiKey)
|
|
Text('searchNoKeyHint'.tr).paddingSymmetric(vertical: 8)
|
|
else if (_totalCount != null)
|
|
Text('searchResultHint'
|
|
.trParams({'count': _totalCount.toString()}))
|
|
.paddingSymmetric(vertical: 8)
|
|
else
|
|
Text('searchHint'.tr).paddingSymmetric(vertical: 8),
|
|
SearchBar(
|
|
padding: const WidgetStatePropertyAll<EdgeInsets>(
|
|
EdgeInsets.symmetric(horizontal: 16.0),
|
|
),
|
|
onSubmitted: (value) {
|
|
_searchFood(value);
|
|
},
|
|
leading: const Icon(Icons.search),
|
|
).paddingSymmetric(horizontal: 24),
|
|
if (_isLoading)
|
|
const SizedBox(
|
|
width: 28,
|
|
height: 28,
|
|
child: CircularProgressIndicator(strokeWidth: 3),
|
|
).paddingSymmetric(vertical: 24)
|
|
else
|
|
Expanded(
|
|
child: ListView.builder(
|
|
itemCount: _foodData.length,
|
|
itemBuilder: (context, index) {
|
|
final item = _foodData[index];
|
|
return OpenContainer(
|
|
closedBuilder: (_, open) => ListTile(
|
|
contentPadding:
|
|
const EdgeInsets.symmetric(horizontal: 24),
|
|
title: Text(item.description),
|
|
subtitle: Text(
|
|
'${DateFormat("yyyy-MM-dd").format(item.mostRecentAcquisitionDate ?? item.publishedDate)} ${item.foodCategory ?? ''}',
|
|
),
|
|
onTap: () => open(),
|
|
),
|
|
openBuilder: (_, __) => FoodDetailsScreen(item: item),
|
|
openElevation: 0,
|
|
closedElevation: 0,
|
|
closedColor: Theme.of(context).colorScheme.surface,
|
|
openColor: Colors.transparent,
|
|
);
|
|
},
|
|
).paddingOnly(top: 8),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|