From 04120c4847d1dd439f99e7f5ac39708537be5d16 Mon Sep 17 00:00:00 2001 From: olshab Date: Mon, 16 Dec 2024 22:59:15 +0400 Subject: [PATCH] fixed localizations issues changed application name updated svg icons --- android/app/src/main/AndroidManifest.xml | 2 +- assets/svg/ru.svg | 24 ++++- assets/svg/us.svg | 43 ++++++-- devtools_options.yaml | 3 + l10n.yaml | 2 +- l10n/app_en.arb | 22 ++-- l10n/app_ru.arb | 22 ++-- .../locale/l10n/app_localizations.dart | 100 ++++++------------ .../locale/l10n/app_localizations_en.dart | 34 ++---- .../locale/l10n/app_localizations_ru.dart | 34 ++---- lib/data/dtos/characters_dto.dart | 56 ---------- lib/data/dtos/characters_dto.g.dart | 49 --------- lib/data/dtos/coins_dto.dart | 7 +- lib/data/dtos/coins_dto.g.dart | 10 +- lib/data/mappers/characters_mapper.dart | 34 ------ lib/data/mappers/crypto_mapper.dart | 6 +- lib/domain/models/card.dart | 2 - lib/main.dart | 18 ++-- .../details_page/details_page.dart | 6 +- lib/presentation/home_page/bloc/bloc.dart | 1 + lib/presentation/home_page/bloc/events.dart | 5 +- lib/presentation/home_page/card.dart | 4 - lib/presentation/home_page/home_page.dart | 34 +++--- .../settings_page/settings_page.dart | 48 ++++++--- lib/repositories/crypto_repository.dart | 14 ++- lib/repositories/potter_repository.dart | 46 -------- 26 files changed, 212 insertions(+), 414 deletions(-) create mode 100644 devtools_options.yaml delete mode 100644 lib/data/dtos/characters_dto.dart delete mode 100644 lib/data/dtos/characters_dto.g.dart delete mode 100644 lib/data/mappers/characters_mapper.dart delete mode 100644 lib/repositories/potter_repository.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e274649..a0542aa 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ - - - - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/svg/us.svg b/assets/svg/us.svg index 9cfd0c9..f5a7a01 100644 --- a/assets/svg/us.svg +++ b/assets/svg/us.svg @@ -1,9 +1,34 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/l10n.yaml b/l10n.yaml index 8bda731..041622a 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,5 +1,5 @@ arb-dir: l10n -template-arb-file: app_ru.arb +template-arb-file: app_en.arb output-localization: app_locale.dart output-dir: lib/components/locale/l10n output-class: AppLocale diff --git a/l10n/app_en.arb b/l10n/app_en.arb index e0134ea..e437606 100644 --- a/l10n/app_en.arb +++ b/l10n/app_en.arb @@ -1,21 +1,15 @@ { "@@locale": "en", - "appBarTitle": "Harry Potter characters", + "mainAppBarTitle": "Cryptocurrency Exchange", + "detailsPageAppBarTitle": "Cryptocurrency info", + "settingsPageAppBarTitle": "Settings", - "search": "Search", - "liked": "You liked", - "unliked": "Like removed from", - "errorOccurred": "Error occurred", - "noErrorMsg": "No message provided", - "retry": "Retry", - "unknown": "Unknown", + "searchHint": "Search", + "addedToFavourite": "is added to favourites", + "removedFromFavourite": "is removed from favourites", - "apiYear": "Year", - "apiType": "Type", - "apiRating": "Rating", - "apiDesc": "", - "apiNoDesc": "No description provided", + "coinDataPriceChange": "for the last 24 hours", - "arbEnding": "t" + "settingsLanguage": "Language" } \ No newline at end of file diff --git a/l10n/app_ru.arb b/l10n/app_ru.arb index cbcd92e..770835c 100644 --- a/l10n/app_ru.arb +++ b/l10n/app_ru.arb @@ -1,21 +1,15 @@ { "@@locale": "ru", - "appBarTitle": "Персонажи из Гарри Поттера", + "mainAppBarTitle": "Криптобиржа", + "detailsPageAppBarTitle": "Сведения о валюте", + "settingsPageAppBarTitle": "Настройки", - "search": "Поиск", - "liked": "Вы добавили в избранное", - "unliked": "Вы удалили из избранного", - "errorOccured": "Произошла ошибка", - "noErrorMsg": "Нет сообщения", - "retry": "Повторить", - "unknown": "Неизвестно", + "searchHint": "Поиск", + "addedToFavourite": "добавлен в избранное", + "removedFromFavourite": "удален из избранного", - "apiYear": "Год", - "apiType": "Тип", - "apiRating": "Рейтинг", - "apiDesc": "(Описание доступно только на английском языке)", - "apiNoDesc": "Нет описания", + "coinDataPriceChange": "за последние 24 часа", - "arbEnding": "t" + "settingsLanguage": "Язык" } \ No newline at end of file diff --git a/lib/components/locale/l10n/app_localizations.dart b/lib/components/locale/l10n/app_localizations.dart index 81394f5..bce270b 100644 --- a/lib/components/locale/l10n/app_localizations.dart +++ b/lib/components/locale/l10n/app_localizations.dart @@ -95,89 +95,53 @@ abstract class AppLocale { Locale('ru') ]; - /// No description provided for @appBarTitle. + /// No description provided for @mainAppBarTitle. /// - /// In ru, this message translates to: - /// **'Персонажи из Гарри Поттера'** - String get appBarTitle; + /// In en, this message translates to: + /// **'Cryptocurrency Exchange'** + String get mainAppBarTitle; - /// No description provided for @search. + /// No description provided for @detailsPageAppBarTitle. /// - /// In ru, this message translates to: - /// **'Поиск'** - String get search; + /// In en, this message translates to: + /// **'Cryptocurrency info'** + String get detailsPageAppBarTitle; - /// No description provided for @liked. + /// No description provided for @settingsPageAppBarTitle. /// - /// In ru, this message translates to: - /// **'Вы добавили в избранное'** - String get liked; + /// In en, this message translates to: + /// **'Settings'** + String get settingsPageAppBarTitle; - /// No description provided for @unliked. + /// No description provided for @searchHint. /// - /// In ru, this message translates to: - /// **'Вы удалили из избранного'** - String get unliked; + /// In en, this message translates to: + /// **'Search'** + String get searchHint; - /// No description provided for @errorOccured. + /// No description provided for @addedToFavourite. /// - /// In ru, this message translates to: - /// **'Произошла ошибка'** - String get errorOccured; + /// In en, this message translates to: + /// **'is added to favourites'** + String get addedToFavourite; - /// No description provided for @noErrorMsg. + /// No description provided for @removedFromFavourite. /// - /// In ru, this message translates to: - /// **'Нет сообщения'** - String get noErrorMsg; + /// In en, this message translates to: + /// **'is removed from favourites'** + String get removedFromFavourite; - /// No description provided for @retry. + /// No description provided for @coinDataPriceChange. /// - /// In ru, this message translates to: - /// **'Повторить'** - String get retry; + /// In en, this message translates to: + /// **'for the last 24 hours'** + String get coinDataPriceChange; - /// No description provided for @unknown. + /// No description provided for @settingsLanguage. /// - /// In ru, this message translates to: - /// **'Неизвестно'** - String get unknown; - - /// No description provided for @apiYear. - /// - /// In ru, this message translates to: - /// **'Год'** - String get apiYear; - - /// No description provided for @apiType. - /// - /// In ru, this message translates to: - /// **'Тип'** - String get apiType; - - /// No description provided for @apiRating. - /// - /// In ru, this message translates to: - /// **'Рейтинг'** - String get apiRating; - - /// No description provided for @apiDesc. - /// - /// In ru, this message translates to: - /// **'(Описание доступно только на английском языке)'** - String get apiDesc; - - /// No description provided for @apiNoDesc. - /// - /// In ru, this message translates to: - /// **'Нет описания'** - String get apiNoDesc; - - /// No description provided for @arbEnding. - /// - /// In ru, this message translates to: - /// **'t'** - String get arbEnding; + /// In en, this message translates to: + /// **'Language'** + String get settingsLanguage; } class _AppLocaleDelegate extends LocalizationsDelegate { diff --git a/lib/components/locale/l10n/app_localizations_en.dart b/lib/components/locale/l10n/app_localizations_en.dart index 3f81f12..b70b22d 100644 --- a/lib/components/locale/l10n/app_localizations_en.dart +++ b/lib/components/locale/l10n/app_localizations_en.dart @@ -7,44 +7,26 @@ class AppLocaleEn extends AppLocale { AppLocaleEn([String locale = 'en']) : super(locale); @override - String get appBarTitle => 'Harry Potter characters'; + String get mainAppBarTitle => 'Cryptocurrency Exchange'; @override - String get search => 'Search'; + String get detailsPageAppBarTitle => 'Cryptocurrency info'; @override - String get liked => 'You liked'; + String get settingsPageAppBarTitle => 'Settings'; @override - String get unliked => 'Like removed from'; + String get searchHint => 'Search'; @override - String get errorOccured => 'Произошла ошибка'; + String get addedToFavourite => 'is added to favourites'; @override - String get noErrorMsg => 'No message provided'; + String get removedFromFavourite => 'is removed from favourites'; @override - String get retry => 'Retry'; + String get coinDataPriceChange => 'for the last 24 hours'; @override - String get unknown => 'Unknown'; - - @override - String get apiYear => 'Year'; - - @override - String get apiType => 'Type'; - - @override - String get apiRating => 'Rating'; - - @override - String get apiDesc => ''; - - @override - String get apiNoDesc => 'No description provided'; - - @override - String get arbEnding => 't'; + String get settingsLanguage => 'Language'; } diff --git a/lib/components/locale/l10n/app_localizations_ru.dart b/lib/components/locale/l10n/app_localizations_ru.dart index eef6832..372c21d 100644 --- a/lib/components/locale/l10n/app_localizations_ru.dart +++ b/lib/components/locale/l10n/app_localizations_ru.dart @@ -7,44 +7,26 @@ class AppLocaleRu extends AppLocale { AppLocaleRu([String locale = 'ru']) : super(locale); @override - String get appBarTitle => 'Персонажи из Гарри Поттера'; + String get mainAppBarTitle => 'Криптобиржа'; @override - String get search => 'Поиск'; + String get detailsPageAppBarTitle => 'Сведения о валюте'; @override - String get liked => 'Вы добавили в избранное'; + String get settingsPageAppBarTitle => 'Настройки'; @override - String get unliked => 'Вы удалили из избранного'; + String get searchHint => 'Поиск'; @override - String get errorOccured => 'Произошла ошибка'; + String get addedToFavourite => 'добавлен в избранное'; @override - String get noErrorMsg => 'Нет сообщения'; + String get removedFromFavourite => 'удален из избранного'; @override - String get retry => 'Повторить'; + String get coinDataPriceChange => 'за последние 24 часа'; @override - String get unknown => 'Неизвестно'; - - @override - String get apiYear => 'Год'; - - @override - String get apiType => 'Тип'; - - @override - String get apiRating => 'Рейтинг'; - - @override - String get apiDesc => '(Описание доступно только на английском языке)'; - - @override - String get apiNoDesc => 'Нет описания'; - - @override - String get arbEnding => 't'; + String get settingsLanguage => 'Язык'; } diff --git a/lib/data/dtos/characters_dto.dart b/lib/data/dtos/characters_dto.dart deleted file mode 100644 index a48f4ab..0000000 --- a/lib/data/dtos/characters_dto.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'characters_dto.g.dart'; - -@JsonSerializable(createToJson: false) -class CharactersDto { - final List? data; - final MetaDto? meta; - - const CharactersDto({this.data, this.meta}); - - factory CharactersDto.fromJson(Map json) => _$CharactersDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class CharacterDataDto { - final String? id; - final String? type; - final CharacterAttributesDataDto? attributes; - - const CharacterDataDto({this.id, this.type, this.attributes}); - - factory CharacterDataDto.fromJson(Map json) => _$CharacterDataDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class CharacterAttributesDataDto { - final String? name; - final String? born; - final String? died; - final String? image; - - const CharacterAttributesDataDto({this.name, this.born, this.died, this.image}); - - factory CharacterAttributesDataDto.fromJson(Map json) => _$CharacterAttributesDataDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class MetaDto { - final PaginationDto? pagination; - - const MetaDto({this.pagination}); - - factory MetaDto.fromJson(Map json) => _$MetaDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class PaginationDto { - final int? current; - final int? next; - final int? last; - - const PaginationDto({this.current, this.next, this.last}); - - factory PaginationDto.fromJson(Map json) => _$PaginationDtoFromJson(json); -} diff --git a/lib/data/dtos/characters_dto.g.dart b/lib/data/dtos/characters_dto.g.dart deleted file mode 100644 index c4e1b40..0000000 --- a/lib/data/dtos/characters_dto.g.dart +++ /dev/null @@ -1,49 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'characters_dto.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -CharactersDto _$CharactersDtoFromJson(Map json) => - CharactersDto( - data: (json['data'] as List?) - ?.map((e) => CharacterDataDto.fromJson(e as Map)) - .toList(), - meta: json['meta'] == null - ? null - : MetaDto.fromJson(json['meta'] as Map), - ); - -CharacterDataDto _$CharacterDataDtoFromJson(Map json) => - CharacterDataDto( - id: json['id'] as String?, - type: json['type'] as String?, - attributes: json['attributes'] == null - ? null - : CharacterAttributesDataDto.fromJson( - json['attributes'] as Map), - ); - -CharacterAttributesDataDto _$CharacterAttributesDataDtoFromJson( - Map json) => - CharacterAttributesDataDto( - name: json['name'] as String?, - born: json['born'] as String?, - died: json['died'] as String?, - image: json['image'] as String?, - ); - -MetaDto _$MetaDtoFromJson(Map json) => MetaDto( - pagination: json['pagination'] == null - ? null - : PaginationDto.fromJson(json['pagination'] as Map), - ); - -PaginationDto _$PaginationDtoFromJson(Map json) => - PaginationDto( - current: (json['current'] as num?)?.toInt(), - next: (json['next'] as num?)?.toInt(), - last: (json['last'] as num?)?.toInt(), - ); diff --git a/lib/data/dtos/coins_dto.dart b/lib/data/dtos/coins_dto.dart index a0f92cf..ca13079 100644 --- a/lib/data/dtos/coins_dto.dart +++ b/lib/data/dtos/coins_dto.dart @@ -2,13 +2,14 @@ import 'package:json_annotation/json_annotation.dart'; part 'coins_dto.g.dart'; -@JsonSerializable(createToJson: false) class CoinsDto { final List? coins; CoinsDto({this.coins}); - factory CoinsDto.fromJson(Map json) => _$CoinsDtoFromJson(json); + factory CoinsDto.fromJson(List json) => CoinsDto( + coins: json.map((e) => CoinDataDto.fromJson(e as Map)).toList(), + ); } @JsonSerializable(createToJson: false) @@ -16,7 +17,9 @@ class CoinDataDto { final String? id; final String? name; final String? image; + @JsonKey(name: 'current_price') final double? currentPrice; + @JsonKey(name: 'price_change_24h') final double? priceChange24h; CoinDataDto({ diff --git a/lib/data/dtos/coins_dto.g.dart b/lib/data/dtos/coins_dto.g.dart index 8b3a49f..9c8d487 100644 --- a/lib/data/dtos/coins_dto.g.dart +++ b/lib/data/dtos/coins_dto.g.dart @@ -6,16 +6,10 @@ part of 'coins_dto.dart'; // JsonSerializableGenerator // ************************************************************************** -CoinsDto _$CoinsDtoFromJson(Map json) => CoinsDto( - coins: (json['coins'] as List?) - ?.map((e) => CoinDataDto.fromJson(e as Map)) - .toList(), - ); - CoinDataDto _$CoinDataDtoFromJson(Map json) => CoinDataDto( id: json['id'] as String?, name: json['name'] as String?, image: json['image'] as String?, - currentPrice: (json['currentPrice'] as num?)?.toDouble(), - priceChange24h: (json['priceChange24h'] as num?)?.toDouble(), + currentPrice: (json['current_price'] as num?)?.toDouble(), + priceChange24h: (json['price_change_24h'] as num?)?.toDouble(), ); diff --git a/lib/data/mappers/characters_mapper.dart b/lib/data/mappers/characters_mapper.dart deleted file mode 100644 index b7af9bb..0000000 --- a/lib/data/mappers/characters_mapper.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter_android_app/data/dtos/characters_dto.dart'; -import 'package:flutter_android_app/domain/models/card.dart'; - -import '../../domain/models/home.dart'; - -const _imagePlaceholder = 'https://gryazoveckij-r19.gosweb.gosuslugi.ru/netcat_files/460/2008/net_foto_muzh.jpg'; - -/* -extension CharactersDataDto on CharactersDto { - HomeData toDomain() => HomeData( - data: data?.map((e) => e.toDomain()).toList(), - nextPage: meta?.pagination?.next, - ); -} - -extension CharacterDataDtoToModel on CharacterDataDto { - CardData toDomain() => CardData( - title: attributes?.name ?? 'UNKNOWN', - imageUrl: attributes?.image ?? _imagePlaceholder, - description: _makeDescriptionText(attributes?.born, attributes?.died), - id: id, - ); -} - -String _makeDescriptionText(String? born, String? died) { - return born != null && died != null - ? '$born - $died' - : born != null - ? 'born: $born' - : died != null - ? 'died: $died' - : ''; -} -*/ diff --git a/lib/data/mappers/crypto_mapper.dart b/lib/data/mappers/crypto_mapper.dart index 892d9f7..349ffcf 100644 --- a/lib/data/mappers/crypto_mapper.dart +++ b/lib/data/mappers/crypto_mapper.dart @@ -35,13 +35,13 @@ extension CoinDataDtoToModel on CoinDataDto { retVal += _getLocalizedPrice(priceChange, locale?.localeName); - return '$retVal за последние 24 часа'; + return '$retVal ${locale?.coinDataPriceChange}'; } } extension CoinsDtoToModel on CoinsDto { - HomeData toDomain(AppLocale? locale) => HomeData( + HomeData toDomain(AppLocale? locale, int currentPage) => HomeData( data: coins?.map((e) => e.toDomain(locale)).toList(), - nextPage: 1, + nextPage: currentPage + 1, ); } diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart index eca6a64..eacd914 100644 --- a/lib/domain/models/card.dart +++ b/lib/domain/models/card.dart @@ -1,5 +1,3 @@ -import 'package:flutter/material.dart'; - class CardData { final String id; final String title; diff --git a/lib/main.dart b/lib/main.dart index 8737e84..3d85ec2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,12 +1,13 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter_android_app/components/extensions/context_x.dart'; import 'package:flutter_android_app/presentation/home_page/bloc/bloc.dart'; import 'package:flutter_android_app/presentation/home_page/home_page.dart'; import 'package:flutter_android_app/presentation/like_bloc/like_bloc.dart'; import 'package:flutter_android_app/presentation/locale_bloc/locale_bloc.dart'; import 'package:flutter_android_app/presentation/locale_bloc/locale_state.dart'; -import 'package:flutter_android_app/repositories/mock_repository.dart'; +import 'package:flutter_android_app/repositories/crypto_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'components/locale/l10n/app_localizations.dart'; @@ -25,7 +26,7 @@ class MyApp extends StatelessWidget { create: (context) => LikeBloc(), child: BlocProvider( lazy: false, - create: (context) => LocaleBloc(Locale(Platform.localeName)), + create: (context) => LocaleBloc(Locale(_getLangCode(Platform.localeName))), child: BlocBuilder( builder: (context, state) => MaterialApp( title: 'Cryptocurrency Exchange App', @@ -37,13 +38,13 @@ class MyApp extends StatelessWidget { useMaterial3: true, ), debugShowCheckedModeBanner: false, - home: RepositoryProvider( + home: RepositoryProvider( lazy: true, - create: (_) => MockRepository(), + create: (_) => CryptoRepository(), child: BlocProvider( lazy: false, - create: (context) => HomeBloc(context.read()), - child: const MyHomePage(title: 'Cryptocurrency Exchange'), + create: (context) => HomeBloc(context.read()), + child: const MyHomePage(), ), ), ), @@ -51,4 +52,9 @@ class MyApp extends StatelessWidget { ), ); } + + String _getLangCode(String fullLocaleName) { + int index = fullLocaleName.indexOf('_'); + return index != -1 ? fullLocaleName.substring(0, index) : fullLocaleName; + } } diff --git a/lib/presentation/details_page/details_page.dart b/lib/presentation/details_page/details_page.dart index 7489e27..0d326be 100644 --- a/lib/presentation/details_page/details_page.dart +++ b/lib/presentation/details_page/details_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_android_app/components/extensions/context_x.dart'; import 'package:flutter_android_app/domain/models/card.dart'; class DetailsPage extends StatelessWidget { @@ -9,7 +10,10 @@ class DetailsPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(), + appBar: AppBar( + title: Text(context.locale.detailsPageAppBarTitle), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + ), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/presentation/home_page/bloc/bloc.dart b/lib/presentation/home_page/bloc/bloc.dart index 7100f99..a41a211 100644 --- a/lib/presentation/home_page/bloc/bloc.dart +++ b/lib/presentation/home_page/bloc/bloc.dart @@ -23,6 +23,7 @@ class HomeBloc extends Bloc { search: event.search, page: event.nextPage ?? 1, onError: (e) => error = e, + locale: event.locale, ); if (event.nextPage != null) { diff --git a/lib/presentation/home_page/bloc/events.dart b/lib/presentation/home_page/bloc/events.dart index cefba70..608bbac 100644 --- a/lib/presentation/home_page/bloc/events.dart +++ b/lib/presentation/home_page/bloc/events.dart @@ -1,3 +1,5 @@ +import 'package:flutter_android_app/components/locale/l10n/app_localizations.dart'; + abstract class HomeEvent { const HomeEvent(); } @@ -5,6 +7,7 @@ abstract class HomeEvent { class HomeLoadDataEvent extends HomeEvent { final String? search; final int? nextPage; + final AppLocale? locale; - const HomeLoadDataEvent({this.search, this.nextPage}); + const HomeLoadDataEvent({this.search, this.nextPage, this.locale}); } diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart index b4627f0..44bbb0f 100644 --- a/lib/presentation/home_page/card.dart +++ b/lib/presentation/home_page/card.dart @@ -8,7 +8,6 @@ class _Card extends StatelessWidget { final String? imageUrl; final String currentPrice; final String priceChange; - final AppLocale locale; final OnLikeCallback onLike; final VoidCallback? onTap; final bool isLiked; @@ -20,14 +19,12 @@ class _Card extends StatelessWidget { this.imageUrl, required this.currentPrice, required this.priceChange, - required this.locale, this.onLike, this.onTap, this.isLiked = false, }); factory _Card.fromData( - AppLocale locale, CardData data, { OnLikeCallback onLike, VoidCallback? onTap, @@ -38,7 +35,6 @@ class _Card extends StatelessWidget { imageUrl: data.imageUrl, currentPrice: data.currentPrice, priceChange: data.priceChange, - locale: locale, onLike: onLike, onTap: onTap, isLiked: isLiked, diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart index e9fe13c..48e0569 100644 --- a/lib/presentation/home_page/home_page.dart +++ b/lib/presentation/home_page/home_page.dart @@ -1,7 +1,5 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_android_app/components/extensions/context_x.dart'; -import 'package:flutter_android_app/components/locale/l10n/app_localizations.dart'; import 'package:flutter_android_app/components/utils/debounce.dart'; import 'package:flutter_android_app/domain/models/card.dart'; import 'package:flutter_android_app/presentation/details_page/details_page.dart'; @@ -14,24 +12,19 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import '../common/svg_objects.dart'; import '../like_bloc/like_events.dart'; -import '../locale_bloc/locale_bloc.dart'; -import '../locale_bloc/locale_events.dart'; -import '../locale_bloc/locale_state.dart'; import '../settings_page/settings_page.dart'; part 'card.dart'; class MyHomePage extends StatelessWidget { - const MyHomePage({super.key, required this.title}); - - final String title; + const MyHomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text(title), + title: Text(context.locale.mainAppBarTitle), actions: [ Padding( padding: const EdgeInsets.only(right: 12.0), @@ -43,7 +36,6 @@ class MyHomePage extends StatelessWidget { ), ), ], - ), body: const Body(), ); @@ -66,7 +58,7 @@ class _BodyState extends State { SvgObjects.init(); WidgetsBinding.instance.addPostFrameCallback((_) { - context.read().add(const HomeLoadDataEvent()); + context.read().add(HomeLoadDataEvent(locale: context.locale)); context.read().add(const LoadLikesEvent()); }); @@ -90,23 +82,25 @@ class _BodyState extends State { child: SearchBar( controller: searchController, onChanged: (search) { - Debounce.run(() => context.read().add(HomeLoadDataEvent(search: search))); + Debounce.run(() => context.read().add(HomeLoadDataEvent(search: search, locale: context.locale))); }, leading: const Icon(Icons.search), trailing: [ IconButton( icon: const Icon(Icons.close), - onPressed: () { searchController.clear(); }, + onPressed: () { + searchController.clear(); + context.read().add(HomeLoadDataEvent(locale: context.locale)); + }, ), ], - hintText: context.locale.search, + hintText: context.locale.searchHint, elevation: const WidgetStatePropertyAll(0.0), padding: const WidgetStatePropertyAll(EdgeInsets.only(left: 18, right: 10)), backgroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.secondaryContainer), ), ), ), - ], ), BlocBuilder( @@ -129,7 +123,6 @@ class _BodyState extends State { final data = state.data?.data?[index]; return data != null ? _Card.fromData( - context.locale, data, isLiked: likeState.likedIds?.contains(data.id) == true, onLike: _onLike, @@ -164,7 +157,7 @@ class _BodyState extends State { WidgetsBinding.instance.addPostFrameCallback((_) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( - '$title ${isLiked ? context.locale.liked : context.locale.unliked}', + '$title ${isLiked ? context.locale.addedToFavourite : context.locale.removedFromFavourite}', style: Theme.of(context).textTheme.bodyLarge ), backgroundColor: Colors.deepPurple.shade200, @@ -174,11 +167,13 @@ class _BodyState extends State { } void _navToDetails(BuildContext context, CardData data) { - Navigator.push(context, CupertinoPageRoute(builder: (context) => DetailsPage(data))); + Navigator.push(context, MaterialPageRoute( + builder: (context) => DetailsPage(data)), + ); } Future _onRefresh() { - context.read().add(HomeLoadDataEvent(search: searchController.text)); + context.read().add(HomeLoadDataEvent(search: searchController.text, locale: context.locale)); return Future.value(null); } @@ -189,6 +184,7 @@ class _BodyState extends State { bloc.add(HomeLoadDataEvent( search: searchController.text, nextPage: bloc.state.data?.nextPage, + locale: context.locale, )); } } diff --git a/lib/presentation/settings_page/settings_page.dart b/lib/presentation/settings_page/settings_page.dart index cd11436..04fd467 100644 --- a/lib/presentation/settings_page/settings_page.dart +++ b/lib/presentation/settings_page/settings_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_android_app/components/extensions/context_x.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../common/svg_objects.dart'; @@ -12,22 +13,39 @@ class SettingsPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('Settings')), - body: Center( - child: GestureDetector( - onTap: () => context.read().add(const ChangeLocaleEvent()), - child: SizedBox.square( - dimension: 50, - child: Padding( - padding: const EdgeInsets.only(right: 12), - child: BlocBuilder( - builder: (context, state) { - return state.currentLocale.languageCode == 'ru' - ? const SvgRu() - : const SvgUs(); - }), + appBar: AppBar( + title: Text(context.locale.settingsPageAppBarTitle), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + ), + body: Padding( + padding: const EdgeInsets.only(left: 20, right: 16, top: 8), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '${context.locale.settingsLanguage}:', + style: Theme.of(context).textTheme.titleMedium, + ), + GestureDetector( + onTap: () => context.read().add(const ChangeLocaleEvent()), + child: SizedBox.square( + dimension: 50, + child: Padding( + padding: const EdgeInsets.only(right: 0), + child: BlocBuilder( + builder: (context, state) { + return state.currentLocale.languageCode == 'ru' + ? const SvgRu() + : const SvgUs(); + }), + ), + ), + ), + ], ), - ), + ], ), ), ); diff --git a/lib/repositories/crypto_repository.dart b/lib/repositories/crypto_repository.dart index 2b9b725..bbd165d 100644 --- a/lib/repositories/crypto_repository.dart +++ b/lib/repositories/crypto_repository.dart @@ -32,12 +32,13 @@ class CryptoRepository extends ApiInterface { }) async { try { Map queryParams = { + 'x_cg_demo_api_key': _apiKey, 'vs_currency': _getCurrencyName(locale?.localeName), 'per_page': pageSize, 'page': page, }; - if (search != null) { + if (search != null && search.isNotEmpty) { final Response searchResponse = await _dio.get>( '$_baseUrl$_searchUrl', queryParameters: { @@ -52,17 +53,22 @@ class CryptoRepository extends ApiInterface { for (var coinData in searchCoinsDto.coins!) { ids += coinData.id != null ? '${coinData.id},' : ''; } + + if (ids.isEmpty) { + return HomeData(); + } + queryParams['ids'] = ids; } } - final Response response = await _dio.get>( + final response = await _dio.get( '$_baseUrl$_coinsDataUrl', queryParameters: queryParams, ); - final CoinsDto dto = CoinsDto.fromJson(response.data as Map); - final HomeData data = dto.toDomain(locale); + final CoinsDto dto = CoinsDto.fromJson(response.data as List); + final HomeData data = dto.toDomain(locale, page); return data; } on DioException catch (e) { diff --git a/lib/repositories/potter_repository.dart b/lib/repositories/potter_repository.dart deleted file mode 100644 index b80789d..0000000 --- a/lib/repositories/potter_repository.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:flutter_android_app/data/dtos/characters_dto.dart'; -import 'package:flutter_android_app/data/mappers/characters_mapper.dart'; -import 'package:flutter_android_app/domain/models/home.dart'; -import 'package:flutter_android_app/repositories/api_interface.dart'; -import 'package:pretty_dio_logger/pretty_dio_logger.dart'; - -import '../components/utils/error_callback.dart'; -/* -class PotterRepository extends ApiInterface { - static final Dio _dio = Dio() - ..interceptors.add(PrettyDioLogger( - requestHeader: true, - requestBody: true, - )); - - static const String _baseUrl = 'https://api.potterdb.com'; - - @override - Future loadData({ - OnErrorCallback? onError, - String? q, int page = 1, - int pageSize = 20, - }) async { - try { - const String url = '$_baseUrl/v1/characters'; - - final Response response = await _dio.get>( - url, - queryParameters: { - 'filter[name_cont]': q, - 'page[number]': page, - 'page[size]': pageSize, - }, - ); - - final CharactersDto dto = CharactersDto.fromJson(response.data as Map); - final HomeData data = dto.toDomain(); - return data; - } on DioException catch (e) { - onError?.call(e.error?.toString()); - return null; - } - } -} -*/