diff --git a/lib/data/dtos/food_dto.g.dart b/lib/data/dtos/food_dto.g.dart new file mode 100644 index 0000000..aa664ca --- /dev/null +++ b/lib/data/dtos/food_dto.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'food_dto.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +FoodsDto _$FoodsDtoFromJson(Map json) => FoodsDto( + meals: (json['meals'] as List?) + ?.map((e) => FoodDataDto.fromJson(e as Map)) + .toList(), + ); + +FoodDataDto _$FoodDataDtoFromJson(Map json) => FoodDataDto( + idMeal: json['idMeal'] as String?, + strMeal: json['strMeal'] as String?, + strMealThumb: json['strMealThumb'] as String?, + ); diff --git a/lib/data/repository/food_repository.dart b/lib/data/repository/food_repository.dart index 4059e91..da64963 100644 --- a/lib/data/repository/food_repository.dart +++ b/lib/data/repository/food_repository.dart @@ -12,19 +12,22 @@ class FoodRepository extends ApiInterface{ requestBody: true, )); - static const String _baseUrl = 'https://www.themealdb.com/api/json'; - + static const String _baseUrl = 'https://www.themealdb.com/api/json/v1/1'; @override - Future?> loadData() async { + Future?> loadData({String? q}) async { try { - const String url = '$_baseUrl/v1/1/filter.php?i=chicken_breast'; + final String url = q != null ? '$_baseUrl/search.php' : '$_baseUrl/filter.php?i=chicken_breast'; - final Response response = await _dio.get>(url); + final Response response = await _dio.get( + url, + queryParameters: q != null ? {'s': q} : null, + ); final FoodsDto dto = FoodsDto.fromJson(response.data as Map); final List? items = dto.meals?.map((e) => e.toDomain()).toList(); return items; - } on DioException catch(e){ + } on DioException catch (e) { + print('Ошибка запроса: $e'); return null; } } diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart index 05735e9..c7867b2 100644 --- a/lib/presentation/home_page/home_page.dart +++ b/lib/presentation/home_page/home_page.dart @@ -18,66 +18,80 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { final Color _color = const Color(0xFFFFA400); + final searchController = TextEditingController(); + late Future?> data; + final repo = FoodRepository(); + @override + void initState() { + data = repo.loadData(); + super.initState(); + } @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: _color, - title: Text(widget.title), - ), - body: const Body(), - ); - } -} - -class Body extends StatelessWidget { - const Body({super.key}); - - @override - Widget build(BuildContext context) { - final marketData = FoodRepository().loadData(); - - return Center( - child: FutureBuilder?>( - future: marketData, - builder: (context, snapshot) => SingleChildScrollView( - child: snapshot.hasData - ? Column( - mainAxisAlignment: MainAxisAlignment.center, - children: snapshot.data?.map((data) { - return _MarketCard.fromData( - data, - onLike: (String title, bool isLiked) => - _showSnackBar(context, title, isLiked), - onTap: () => _navToDetails(context, data), - ); - }).toList() ?? - [], - ) - : const CircularProgressIndicator(), - ), - ), - ); - } - - void _showSnackBar(BuildContext context, String title, bool isLiked) { - WidgetsBinding.instance.addPostFrameCallback((_) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text( - 'Товар $title ${isLiked ? 'добавлен в избранное' : 'удален из избранного'}', - style: Theme.of(context).textTheme.bodyLarge, - ), - backgroundColor: Colors.orangeAccent, - duration: const Duration(seconds: 1), - )); - }); - } - - void _navToDetails(BuildContext context, MarketData data) { - Navigator.push( - context, - CupertinoPageRoute(builder: (context) => DetailsPage(data)), - ); + return Padding( + padding: EdgeInsets.only(top: MediaQuery + .of(context) + .padding + .top), + child: Column(children: [ + Padding( + padding: const EdgeInsets.all(12), + child: CupertinoSearchTextField( + controller: searchController, + style: const TextStyle(color: Colors.white), + onSubmitted: (search) { + setState(() { + data = repo.loadData(q: search); + }); + }, + ), + ), + Expanded( + child: Center( + child: FutureBuilder?>( + future: data, + builder: (context, snapshot) => + SingleChildScrollView( + child: snapshot.hasData + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: snapshot.data?.map((data) { + return _MarketCard.fromData( + data, + onLike: (String title, bool isLiked) => + _showSnackBar(context, title, isLiked), + onTap: () => _navToDetails(context, data), + ); + }).toList() ?? + [], + ) + : const CircularProgressIndicator(), + ), + ), + ), + ), + ])); } + + + void _showSnackBar(BuildContext context, String title, bool isLiked) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + 'Товар $title ${isLiked ? 'добавлен в избранное' : 'удален из избранного'}', + style: Theme.of(context).textTheme.bodyLarge, + ), + backgroundColor: Colors.orangeAccent, + duration: const Duration(seconds: 1), + )); + }); + } + + void _navToDetails(BuildContext context, MarketData data) { + Navigator.push( + context, + CupertinoPageRoute(builder: (context) => DetailsPage(data)), + ); + } }