diff --git a/l10n/app_en.arb b/l10n/app_en.arb index 7807fb4..63213a9 100644 --- a/l10n/app_en.arb +++ b/l10n/app_en.arb @@ -2,9 +2,12 @@ "@@locale" : "en", "search": "Search", - "liked": "liked!", - "disliked": "disliked :<", + "liked": "liked", + "disliked": "disliked", "heroDetailsTitle": "Hero Details", + "heroListTitle": "Hero List", + "noHeroesAvailable": "no heroes available", + "noHeroesFound": "no heroes found", "heroNoImage": "No image available", "heroNoDescription": "No description available", diff --git a/l10n/app_ru.arb b/l10n/app_ru.arb index c327bfb..bd7dc0b 100644 --- a/l10n/app_ru.arb +++ b/l10n/app_ru.arb @@ -2,10 +2,13 @@ "@@locale" : "ru", "search": "Поиск", - "liked": "нравится!", - "disliked": "не нравится :<", + "liked": "нравится", + "disliked": "больше не нравится", + "heroListTitle": "Список героев", "heroDetailsTitle": "Детали героя", "heroNoImage": "Изображение недоступно", + "noHeroesAvailable": "Нет доступных героев", + "noHeroesFound": "Герои не найдены", "heroNoDescription": "Описание отсутствует", "arbEnding": "ЗАПЯТАЯ" diff --git a/lib/Components/locale/l10n/app_locale.dart b/lib/Components/locale/l10n/app_locale.dart index 7a48806..86d0347 100644 --- a/lib/Components/locale/l10n/app_locale.dart +++ b/lib/Components/locale/l10n/app_locale.dart @@ -104,15 +104,21 @@ abstract class AppLocale { /// No description provided for @liked. /// /// In ru, this message translates to: - /// **'нравится!'** + /// **'нравится'** String get liked; /// No description provided for @disliked. /// /// In ru, this message translates to: - /// **'не нравится :<'** + /// **'больше не нравится'** String get disliked; + /// No description provided for @heroListTitle. + /// + /// In ru, this message translates to: + /// **'Список героев'** + String get heroListTitle; + /// No description provided for @heroDetailsTitle. /// /// In ru, this message translates to: @@ -125,6 +131,18 @@ abstract class AppLocale { /// **'Изображение недоступно'** String get heroNoImage; + /// No description provided for @noHeroesAvailable. + /// + /// In ru, this message translates to: + /// **'Нет доступных героев'** + String get noHeroesAvailable; + + /// No description provided for @noHeroesFound. + /// + /// In ru, this message translates to: + /// **'Герои не найдены'** + String get noHeroesFound; + /// No description provided for @heroNoDescription. /// /// In ru, this message translates to: diff --git a/lib/Components/locale/l10n/app_locale_en.dart b/lib/Components/locale/l10n/app_locale_en.dart index 76c31d2..2e9b554 100644 --- a/lib/Components/locale/l10n/app_locale_en.dart +++ b/lib/Components/locale/l10n/app_locale_en.dart @@ -10,10 +10,13 @@ class AppLocaleEn extends AppLocale { String get search => 'Search'; @override - String get liked => 'liked!'; + String get liked => 'liked'; @override - String get disliked => 'disliked :<'; + String get disliked => 'disliked'; + + @override + String get heroListTitle => 'Hero List'; @override String get heroDetailsTitle => 'Hero Details'; @@ -21,6 +24,12 @@ class AppLocaleEn extends AppLocale { @override String get heroNoImage => 'No image available'; + @override + String get noHeroesAvailable => 'no heroes available'; + + @override + String get noHeroesFound => 'no heroes found'; + @override String get heroNoDescription => 'No description available'; diff --git a/lib/Components/locale/l10n/app_locale_ru.dart b/lib/Components/locale/l10n/app_locale_ru.dart index b86b145..6142724 100644 --- a/lib/Components/locale/l10n/app_locale_ru.dart +++ b/lib/Components/locale/l10n/app_locale_ru.dart @@ -10,10 +10,13 @@ class AppLocaleRu extends AppLocale { String get search => 'Поиск'; @override - String get liked => 'нравится!'; + String get liked => 'нравится'; @override - String get disliked => 'не нравится :<'; + String get disliked => 'больше не нравится'; + + @override + String get heroListTitle => 'Список героев'; @override String get heroDetailsTitle => 'Детали героя'; @@ -21,6 +24,12 @@ class AppLocaleRu extends AppLocale { @override String get heroNoImage => 'Изображение недоступно'; + @override + String get noHeroesAvailable => 'Нет доступных героев'; + + @override + String get noHeroesFound => 'Герои не найдены'; + @override String get heroNoDescription => 'Описание отсутствует'; diff --git a/lib/Components/screens/hero_list_screen.dart b/lib/Components/screens/hero_list_screen.dart index 1ad2b88..50a4eaf 100644 --- a/lib/Components/screens/hero_list_screen.dart +++ b/lib/Components/screens/hero_list_screen.dart @@ -13,9 +13,10 @@ class HeroListScreen extends StatelessWidget { @override Widget build(BuildContext context) { final locale = AppLocale.of(context)!; // Получаем текущую локализацию + return Scaffold( appBar: AppBar( - title: const Text('Heroes'), + title: Text(locale.heroListTitle), actions: [ IconButton( icon: const Icon(Icons.language), @@ -50,35 +51,46 @@ class HeroListScreen extends StatelessWidget { if (searchState is HeroSearchLoading) { return const Center(child: CircularProgressIndicator()); } else if (searchState is HeroSearchLoaded) { - return ListView.builder( - itemCount: searchState.heroes.length, - itemBuilder: (context, index) { - return HeroCard(hero: searchState.heroes[index]); + return RefreshIndicator( + onRefresh: () async { + // Обновляем список героев + context.read().add(FetchHeroes()); }, + child: ListView.builder( + itemCount: searchState.heroes.length, + itemBuilder: (context, index) { + return HeroCard(hero: searchState.heroes[index]); + }, + ), ); } else if (searchState is HeroSearchError) { return Center(child: Text('Error: ${searchState.message}')); } else if (searchState is HeroSearchInitial) { - // Если поисковый запрос пустой, показываем полный список героев return BlocBuilder( builder: (context, listState) { if (listState is HeroListLoading) { return const Center(child: CircularProgressIndicator()); } else if (listState is HeroListLoaded) { - return ListView.builder( - itemCount: listState.heroes.length, - itemBuilder: (context, index) { - return HeroCard(hero: listState.heroes[index]); + return RefreshIndicator( + onRefresh: () async { + // Выполняем новый запрос к API + context.read().add(FetchHeroes()); }, + child: ListView.builder( + itemCount: listState.heroes.length, + itemBuilder: (context, index) { + return HeroCard(hero: listState.heroes[index]); + }, + ), ); } else if (listState is HeroListError) { return Center(child: Text('Error: ${listState.message}')); } - return const Center(child: Text('No heroes available.')); + return Center(child: Text(locale.noHeroesAvailable)); }, ); } - return const Center(child: Text('No heroes found.')); + return Center(child: Text(locale.noHeroesFound)); }, ), ); diff --git a/lib/widgets/hero_card.dart b/lib/widgets/hero_card.dart index 6b556cd..658ff43 100644 --- a/lib/widgets/hero_card.dart +++ b/lib/widgets/hero_card.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import '../../data/dtos/hero_dto.dart'; import '../components/screens/hero_detail_screen.dart'; import '../services/like_service.dart'; +import '../../Components/locale/l10n/app_locale.dart'; class HeroCard extends StatefulWidget { final HeroDto hero; @@ -30,14 +31,28 @@ class _HeroCardState extends State { } Future _toggleLike() async { + final locale = AppLocale.of(context)!; // Получаем текущую локализацию + String message; + if (_isLiked) { await _likeService.unlikeHero(widget.hero.id); + message = '${locale.disliked} ${widget.hero.name}'; } else { await _likeService.likeHero(widget.hero.id); + message = '${locale.liked} ${widget.hero.name}'; } + setState(() { _isLiked = !_isLiked; }); + + // Отображение Snackbar с локализованным сообщением + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(message), + duration: const Duration(seconds: 2), + ), + ); } @override @@ -46,14 +61,14 @@ class _HeroCardState extends State { child: ListTile( leading: widget.hero.portraitUrl != null ? Image.network(widget.hero.portraitUrl!) - : Icon(Icons.image), + : const Icon(Icons.image), title: Text(widget.hero.name), trailing: IconButton( icon: Icon( _isLiked ? Icons.favorite : Icons.favorite_border, color: _isLiked ? Colors.red : null, ), - onPressed: _toggleLike, + onPressed: _toggleLike, // Вызываем метод с Snackbar ), onTap: () { Navigator.push( @@ -66,4 +81,4 @@ class _HeroCardState extends State { ), ); } -} \ No newline at end of file +}