From a676d454cafa5706cf8b3e7032cacef651f5d773 Mon Sep 17 00:00:00 2001 From: olshab Date: Sun, 15 Dec 2024 23:23:00 +0400 Subject: [PATCH] implemented mock crypto repository changed Cupertino search bar to Material UI 3 changed baseline color and card colors implemented fetching crypto data from public API (untested) --- l10n/app_en.arb | 2 +- l10n/app_ru.arb | 2 +- .../locale/l10n/app_localizations.dart | 2 +- .../locale/l10n/app_localizations_en.dart | 2 +- .../locale/l10n/app_localizations_ru.dart | 2 +- lib/data/dtos/coins_dto.dart | 31 +++++++ lib/data/dtos/coins_dto.g.dart | 21 +++++ lib/data/dtos/search_coins_dto.dart | 21 +++++ lib/data/dtos/search_coins_dto.g.dart | 19 +++++ lib/data/mappers/characters_mapper.dart | 2 + lib/data/mappers/crypto_mapper.dart | 47 +++++++++++ lib/domain/models/card.dart | 12 +-- lib/main.dart | 15 ++-- .../details_page/details_page.dart | 2 +- lib/presentation/home_page/bloc/bloc.dart | 6 +- lib/presentation/home_page/card.dart | 28 +++---- lib/presentation/home_page/home_page.dart | 53 ++++++------ lib/presentation/like_bloc/like_bloc.dart | 6 +- lib/presentation/like_bloc/like_events.dart | 1 + .../settings_page/settings_page.dart | 35 ++++++++ lib/repositories/api_interface.dart | 9 +- lib/repositories/crypto_repository.dart | 84 +++++++++++++++++++ lib/repositories/mock_repository.dart | 35 +++++--- lib/repositories/potter_repository.dart | 3 +- 24 files changed, 363 insertions(+), 77 deletions(-) create mode 100644 lib/data/dtos/coins_dto.dart create mode 100644 lib/data/dtos/coins_dto.g.dart create mode 100644 lib/data/dtos/search_coins_dto.dart create mode 100644 lib/data/dtos/search_coins_dto.g.dart create mode 100644 lib/data/mappers/crypto_mapper.dart create mode 100644 lib/presentation/settings_page/settings_page.dart create mode 100644 lib/repositories/crypto_repository.dart diff --git a/l10n/app_en.arb b/l10n/app_en.arb index 3167b3d..e0134ea 100644 --- a/l10n/app_en.arb +++ b/l10n/app_en.arb @@ -1,7 +1,7 @@ { "@@locale": "en", - "appBarTitle": "Crypto Exchange", + "appBarTitle": "Harry Potter characters", "search": "Search", "liked": "You liked", diff --git a/l10n/app_ru.arb b/l10n/app_ru.arb index ede8c3f..cbcd92e 100644 --- a/l10n/app_ru.arb +++ b/l10n/app_ru.arb @@ -1,7 +1,7 @@ { "@@locale": "ru", - "appBarTitle": "Криптобиржа", + "appBarTitle": "Персонажи из Гарри Поттера", "search": "Поиск", "liked": "Вы добавили в избранное", diff --git a/lib/components/locale/l10n/app_localizations.dart b/lib/components/locale/l10n/app_localizations.dart index 030d71e..81394f5 100644 --- a/lib/components/locale/l10n/app_localizations.dart +++ b/lib/components/locale/l10n/app_localizations.dart @@ -98,7 +98,7 @@ abstract class AppLocale { /// No description provided for @appBarTitle. /// /// In ru, this message translates to: - /// **'Криптобиржа'** + /// **'Персонажи из Гарри Поттера'** String get appBarTitle; /// No description provided for @search. diff --git a/lib/components/locale/l10n/app_localizations_en.dart b/lib/components/locale/l10n/app_localizations_en.dart index 4d7f100..3f81f12 100644 --- a/lib/components/locale/l10n/app_localizations_en.dart +++ b/lib/components/locale/l10n/app_localizations_en.dart @@ -7,7 +7,7 @@ class AppLocaleEn extends AppLocale { AppLocaleEn([String locale = 'en']) : super(locale); @override - String get appBarTitle => 'Crypto Exchange'; + String get appBarTitle => 'Harry Potter characters'; @override String get search => 'Search'; diff --git a/lib/components/locale/l10n/app_localizations_ru.dart b/lib/components/locale/l10n/app_localizations_ru.dart index d3f54e9..eef6832 100644 --- a/lib/components/locale/l10n/app_localizations_ru.dart +++ b/lib/components/locale/l10n/app_localizations_ru.dart @@ -7,7 +7,7 @@ class AppLocaleRu extends AppLocale { AppLocaleRu([String locale = 'ru']) : super(locale); @override - String get appBarTitle => 'Криптобиржа'; + String get appBarTitle => 'Персонажи из Гарри Поттера'; @override String get search => 'Поиск'; diff --git a/lib/data/dtos/coins_dto.dart b/lib/data/dtos/coins_dto.dart new file mode 100644 index 0000000..a0f92cf --- /dev/null +++ b/lib/data/dtos/coins_dto.dart @@ -0,0 +1,31 @@ +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); +} + +@JsonSerializable(createToJson: false) +class CoinDataDto { + final String? id; + final String? name; + final String? image; + final double? currentPrice; + final double? priceChange24h; + + CoinDataDto({ + this.id, + this.name, + this.image, + this.currentPrice, + this.priceChange24h, + }); + + factory CoinDataDto.fromJson(Map json) => _$CoinDataDtoFromJson(json); +} diff --git a/lib/data/dtos/coins_dto.g.dart b/lib/data/dtos/coins_dto.g.dart new file mode 100644 index 0000000..8b3a49f --- /dev/null +++ b/lib/data/dtos/coins_dto.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +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(), + ); diff --git a/lib/data/dtos/search_coins_dto.dart b/lib/data/dtos/search_coins_dto.dart new file mode 100644 index 0000000..a02c2bb --- /dev/null +++ b/lib/data/dtos/search_coins_dto.dart @@ -0,0 +1,21 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'search_coins_dto.g.dart'; + +@JsonSerializable(createToJson: false) +class SearchCoinsDto { + final List? coins; + + const SearchCoinsDto({this.coins}); + + factory SearchCoinsDto.fromJson(Map json) => _$SearchCoinsDtoFromJson(json); +} + +@JsonSerializable(createToJson: false) +class SearchCoinDto { + final String? id; + + const SearchCoinDto({this.id}); + + factory SearchCoinDto.fromJson(Map json) => _$SearchCoinDtoFromJson(json); +} diff --git a/lib/data/dtos/search_coins_dto.g.dart b/lib/data/dtos/search_coins_dto.g.dart new file mode 100644 index 0000000..c0edbfe --- /dev/null +++ b/lib/data/dtos/search_coins_dto.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'search_coins_dto.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SearchCoinsDto _$SearchCoinsDtoFromJson(Map json) => + SearchCoinsDto( + coins: (json['coins'] as List?) + ?.map((e) => SearchCoinDto.fromJson(e as Map)) + .toList(), + ); + +SearchCoinDto _$SearchCoinDtoFromJson(Map json) => + SearchCoinDto( + id: json['id'] as String?, + ); diff --git a/lib/data/mappers/characters_mapper.dart b/lib/data/mappers/characters_mapper.dart index e6c28bb..b7af9bb 100644 --- a/lib/data/mappers/characters_mapper.dart +++ b/lib/data/mappers/characters_mapper.dart @@ -5,6 +5,7 @@ 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(), @@ -30,3 +31,4 @@ String _makeDescriptionText(String? born, String? died) { ? 'died: $died' : ''; } +*/ diff --git a/lib/data/mappers/crypto_mapper.dart b/lib/data/mappers/crypto_mapper.dart new file mode 100644 index 0000000..892d9f7 --- /dev/null +++ b/lib/data/mappers/crypto_mapper.dart @@ -0,0 +1,47 @@ +import 'package:flutter_android_app/components/locale/l10n/app_localizations.dart'; +import 'package:flutter_android_app/data/dtos/coins_dto.dart'; +import 'package:flutter_android_app/domain/models/card.dart'; +import 'package:flutter_android_app/domain/models/home.dart'; + +extension CoinDataDtoToModel on CoinDataDto { + CardData toDomain(AppLocale? locale) => CardData( + id: id ?? 'UNKNOWN', + title: name ?? 'UNKNOWN', + imageUrl: image, + currentPrice: _getLocalizedPrice(currentPrice, locale?.localeName), + priceChange: _getLocalizedPriceChange(priceChange24h, locale), + ); + + String _getLocalizedPrice(double? price, String? localeName) { + if (localeName == null) { + return '$price \$'; + } + + return switch (localeName) { + 'ru' => '$price ₽', + _ => '$price \$', + }; + } + + String _getLocalizedPriceChange(double? priceChange, AppLocale? locale) { + if (priceChange == null) { + return '+${_getLocalizedPrice(0, locale?.localeName)}'; + } + + String retVal = ''; + if (priceChange >= 0.0) { + retVal += '+'; + } + + retVal += _getLocalizedPrice(priceChange, locale?.localeName); + + return '$retVal за последние 24 часа'; + } +} + +extension CoinsDtoToModel on CoinsDto { + HomeData toDomain(AppLocale? locale) => HomeData( + data: coins?.map((e) => e.toDomain(locale)).toList(), + nextPage: 1, + ); +} diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart index e7a9b62..eca6a64 100644 --- a/lib/domain/models/card.dart +++ b/lib/domain/models/card.dart @@ -1,17 +1,17 @@ import 'package:flutter/material.dart'; class CardData { + final String id; final String title; - final String description; - final IconData icon; final String? imageUrl; - final String? id; + final String currentPrice; + final String priceChange; CardData({ + required this.id, required this.title, - required this.description, - this.icon = Icons.adb, this.imageUrl, - this.id, + required this.currentPrice, + required this.priceChange, }); } diff --git a/lib/main.dart b/lib/main.dart index a91fc51..8737e84 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,7 +6,7 @@ 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/potter_repository.dart'; +import 'package:flutter_android_app/repositories/mock_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'components/locale/l10n/app_localizations.dart'; @@ -28,21 +28,22 @@ class MyApp extends StatelessWidget { create: (context) => LocaleBloc(Locale(Platform.localeName)), child: BlocBuilder( builder: (context, state) => MaterialApp( - title: 'Flutter Demo', + title: 'Cryptocurrency Exchange App', locale: state.currentLocale, localizationsDelegates: AppLocale.localizationsDelegates, supportedLocales: AppLocale.supportedLocales, theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.green), + colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigoAccent), useMaterial3: true, ), - home: RepositoryProvider( + debugShowCheckedModeBanner: false, + home: RepositoryProvider( lazy: true, - create: (_) => PotterRepository(), + create: (_) => MockRepository(), child: BlocProvider( lazy: false, - create: (context) => HomeBloc(context.read()), - child: const MyHomePage(title: 'Harry Potter characters'), + create: (context) => HomeBloc(context.read()), + child: const MyHomePage(title: 'Cryptocurrency Exchange'), ), ), ), diff --git a/lib/presentation/details_page/details_page.dart b/lib/presentation/details_page/details_page.dart index 67d35bf..7489e27 100644 --- a/lib/presentation/details_page/details_page.dart +++ b/lib/presentation/details_page/details_page.dart @@ -21,7 +21,7 @@ class DetailsPage extends StatelessWidget { padding: const EdgeInsets.only(bottom: 4), child: Text(data.title, style: Theme.of(context).textTheme.headlineLarge), ), - Text(data.description, style: Theme.of(context).textTheme.bodyLarge), + Text(data.currentPrice, style: Theme.of(context).textTheme.bodyLarge), ], ), ); diff --git a/lib/presentation/home_page/bloc/bloc.dart b/lib/presentation/home_page/bloc/bloc.dart index 55e17a8..7100f99 100644 --- a/lib/presentation/home_page/bloc/bloc.dart +++ b/lib/presentation/home_page/bloc/bloc.dart @@ -1,10 +1,10 @@ import 'package:flutter_android_app/presentation/home_page/bloc/events.dart'; import 'package:flutter_android_app/presentation/home_page/bloc/state.dart'; -import 'package:flutter_android_app/repositories/potter_repository.dart'; +import 'package:flutter_android_app/repositories/api_interface.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class HomeBloc extends Bloc { - final PotterRepository repo; + final ApiInterface repo; HomeBloc(this.repo) : super(const HomeState()) { on(_onLoadData); @@ -20,7 +20,7 @@ class HomeBloc extends Bloc { String? error; final data = await repo.loadData( - q: event.search, + search: event.search, page: event.nextPage ?? 1, onError: (e) => error = e, ); diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart index f148566..b4627f0 100644 --- a/lib/presentation/home_page/card.dart +++ b/lib/presentation/home_page/card.dart @@ -3,26 +3,26 @@ part of 'home_page.dart'; typedef OnLikeCallback = void Function(String? id, String title, bool isLiked)?; class _Card extends StatelessWidget { - final AppLocale locale; + final String id; final String title; - final String description; - final IconData icon; final String? imageUrl; + final String currentPrice; + final String priceChange; + final AppLocale locale; final OnLikeCallback onLike; final VoidCallback? onTap; - final String? id; final bool isLiked; const _Card({ super.key, - required this.locale, + required this.id, required this.title, - required this.description, - this.icon = Icons.hail, this.imageUrl, + required this.currentPrice, + required this.priceChange, + required this.locale, this.onLike, this.onTap, - this.id, this.isLiked = false, }); @@ -33,15 +33,15 @@ class _Card extends StatelessWidget { VoidCallback? onTap, bool isLiked = false, }) => _Card( - locale: locale, + id: data.id, title: data.title, - description: data.description, - icon: data.icon, imageUrl: data.imageUrl, + currentPrice: data.currentPrice, + priceChange: data.priceChange, + locale: locale, onLike: onLike, onTap: onTap, isLiked: isLiked, - id: data.id, ); @override @@ -52,7 +52,7 @@ class _Card extends StatelessWidget { margin: const EdgeInsets.fromLTRB(20, 8, 20, 8), constraints: const BoxConstraints(minHeight: 140), decoration: BoxDecoration( - color: Colors.deepPurple.shade200, + color: Theme.of(context).colorScheme.secondaryContainer, borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( @@ -94,7 +94,7 @@ class _Card extends StatelessWidget { style: Theme.of(context).textTheme.headlineLarge, ), Text( - description, + currentPrice, style: Theme.of(context).textTheme.bodyLarge), ], ), diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart index 7be7b96..e9fe13c 100644 --- a/lib/presentation/home_page/home_page.dart +++ b/lib/presentation/home_page/home_page.dart @@ -17,25 +17,33 @@ 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 StatefulWidget { +class MyHomePage extends StatelessWidget { const MyHomePage({super.key, required this.title}); final String title; - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - backgroundColor: Colors.deepPurple.shade200, - title: Text(widget.title), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: Text(title), + actions: [ + Padding( + padding: const EdgeInsets.only(right: 12.0), + child: IconButton( + icon: const Icon(Icons.settings), + onPressed: () => Navigator.push(context, MaterialPageRoute( + builder: (BuildContext context) => const SettingsPage(), + )), + ), + ), + ], + ), body: const Body(), ); @@ -79,29 +87,26 @@ class _BodyState extends State { flex: 4, child: Padding( padding: const EdgeInsets.all(12), - child: CupertinoSearchTextField( + child: SearchBar( controller: searchController, onChanged: (search) { Debounce.run(() => context.read().add(HomeLoadDataEvent(search: search))); }, + leading: const Icon(Icons.search), + trailing: [ + IconButton( + icon: const Icon(Icons.close), + onPressed: () { searchController.clear(); }, + ), + ], + hintText: context.locale.search, + elevation: const WidgetStatePropertyAll(0.0), + padding: const WidgetStatePropertyAll(EdgeInsets.only(left: 18, right: 10)), + backgroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.secondaryContainer), ), ), ), - 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(); - }), - ), - ), - ), + ], ), BlocBuilder( diff --git a/lib/presentation/like_bloc/like_bloc.dart b/lib/presentation/like_bloc/like_bloc.dart index 7f982f8..13c1f8e 100644 --- a/lib/presentation/like_bloc/like_bloc.dart +++ b/lib/presentation/like_bloc/like_bloc.dart @@ -3,12 +3,12 @@ import 'like_events.dart'; import 'like_state.dart'; import 'package:shared_preferences/shared_preferences.dart'; -const String _likedPrefsKey = 'liked'; - class LikeBloc extends Bloc { + static const String _likedPrefsKey = 'liked'; + LikeBloc() : super(const LikeState(likedIds: [])) { - on(_onChangeLike); on(_onLoadLikes); + on(_onChangeLike); } Future _onLoadLikes( diff --git a/lib/presentation/like_bloc/like_events.dart b/lib/presentation/like_bloc/like_events.dart index 938bce0..d0326d8 100644 --- a/lib/presentation/like_bloc/like_events.dart +++ b/lib/presentation/like_bloc/like_events.dart @@ -8,5 +8,6 @@ class LoadLikesEvent extends LikeEvent { class ChangeLikeEvent extends LikeEvent { final String id; + const ChangeLikeEvent(this.id); } diff --git a/lib/presentation/settings_page/settings_page.dart b/lib/presentation/settings_page/settings_page.dart new file mode 100644 index 0000000..cd11436 --- /dev/null +++ b/lib/presentation/settings_page/settings_page.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../common/svg_objects.dart'; +import '../locale_bloc/locale_bloc.dart'; +import '../locale_bloc/locale_events.dart'; +import '../locale_bloc/locale_state.dart'; + +class SettingsPage extends StatelessWidget { + const SettingsPage({super.key}); + + @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(); + }), + ), + ), + ), + ), + ); + } +} diff --git a/lib/repositories/api_interface.dart b/lib/repositories/api_interface.dart index b8a7d17..1696f3e 100644 --- a/lib/repositories/api_interface.dart +++ b/lib/repositories/api_interface.dart @@ -1,7 +1,14 @@ import 'package:flutter_android_app/domain/models/home.dart'; +import '../components/locale/l10n/app_localizations.dart'; import '../components/utils/error_callback.dart'; abstract class ApiInterface { - Future loadData({OnErrorCallback? onError}); + Future loadData({ + OnErrorCallback? onError, + String? search, + int page = 1, + int pageSize = 20, + AppLocale? locale, + }); } diff --git a/lib/repositories/crypto_repository.dart b/lib/repositories/crypto_repository.dart new file mode 100644 index 0000000..2b9b725 --- /dev/null +++ b/lib/repositories/crypto_repository.dart @@ -0,0 +1,84 @@ +import 'package:dio/dio.dart'; +import 'package:flutter_android_app/components/locale/l10n/app_localizations.dart'; +import 'package:flutter_android_app/components/utils/error_callback.dart'; +import 'package:flutter_android_app/data/dtos/coins_dto.dart'; +import 'package:flutter_android_app/data/dtos/search_coins_dto.dart'; +import 'package:flutter_android_app/data/mappers/crypto_mapper.dart'; +import 'package:flutter_android_app/repositories/api_interface.dart'; +import 'package:pretty_dio_logger/pretty_dio_logger.dart'; + +import '../domain/models/home.dart'; + +class CryptoRepository extends ApiInterface { + static const String _baseUrl = 'https://api.coingecko.com/api/v3'; + static const String _searchUrl = '/search'; + static const String _coinsDataUrl = '/coins/markets'; + + static const String _apiKey = 'CG-oer6F3AAhVpNxGDxc7mjzZCo'; + + static final Dio _dio = Dio() + ..interceptors.add(PrettyDioLogger( + requestBody: true, + requestHeader: true, + )); + + @override + Future loadData({ + OnErrorCallback? onError, + String? search, + int page = 1, + int pageSize = 20, + AppLocale? locale, + }) async { + try { + Map queryParams = { + 'vs_currency': _getCurrencyName(locale?.localeName), + 'per_page': pageSize, + 'page': page, + }; + + if (search != null) { + final Response searchResponse = await _dio.get>( + '$_baseUrl$_searchUrl', + queryParameters: { + 'x_cg_demo_api_key': _apiKey, + 'query': search, + } + ); + + final SearchCoinsDto searchCoinsDto = SearchCoinsDto.fromJson(searchResponse.data as Map); + if (searchCoinsDto.coins != null) { + String ids = ''; + for (var coinData in searchCoinsDto.coins!) { + ids += coinData.id != null ? '${coinData.id},' : ''; + } + queryParams['ids'] = ids; + } + } + + final Response response = await _dio.get>( + '$_baseUrl$_coinsDataUrl', + queryParameters: queryParams, + ); + + final CoinsDto dto = CoinsDto.fromJson(response.data as Map); + final HomeData data = dto.toDomain(locale); + return data; + + } on DioException catch (e) { + onError?.call(e.error?.toString()); + return null; + } + } + + String _getCurrencyName(String? localeName) { + if (localeName == null) { + return 'usd'; + } + + return switch (localeName) { + 'ru' => 'rub', + _ => 'usd', + }; + } +} diff --git a/lib/repositories/mock_repository.dart b/lib/repositories/mock_repository.dart index a1a2b7d..4cc43cc 100644 --- a/lib/repositories/mock_repository.dart +++ b/lib/repositories/mock_repository.dart @@ -1,29 +1,40 @@ -import 'package:flutter/material.dart'; import 'package:flutter_android_app/domain/models/card.dart'; import 'package:flutter_android_app/repositories/api_interface.dart'; +import '../components/locale/l10n/app_localizations.dart'; import '../components/utils/error_callback.dart'; import '../domain/models/home.dart'; class MockRepository extends ApiInterface { @override - Future loadData({OnErrorCallback? onError}) async { + Future loadData({ + OnErrorCallback? onError, + String? search, + int page = 1, + int pageSize = 20, + AppLocale? locale, + }) async { return HomeData(data: [ CardData( - title: 'Title 1', - description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', - imageUrl: 'https://i.imgur.com/a9WA68S.png', + id: 'bitcoin', + title: 'Bitcoin', + imageUrl: 'https://coin-images.coingecko.com/coins/images/1/large/bitcoin.png?1696501400', + currentPrice: '103233 \$', + priceChange: '+2207.71 \$ for the last 24 hours', ), CardData( - title: 'Title 2', - description: 'Lorem ipsum dolor sit amet', - icon: Icons.add_chart_outlined, - imageUrl: 'https://i.imgur.com/dAUcs6I.png', + id: 'ethereum', + title: 'Ethereum', + imageUrl: 'https://coin-images.coingecko.com/coins/images/279/large/ethereum.png?1696501628', + currentPrice: '3900.92 \$', + priceChange: '+58.27 \$ for the last 24 hours', ), CardData( - title: 'Title 3', - description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', - imageUrl: 'https://i.imgur.com/m2FhVAK.png', + id: 'tether', + title: 'Tether', + imageUrl: 'https://coin-images.coingecko.com/coins/images/325/large/Tether.png?1696501661', + currentPrice: '1.001 \$', + priceChange: '+0.00059798 \$ for the last 24 hours', ), ]); } diff --git a/lib/repositories/potter_repository.dart b/lib/repositories/potter_repository.dart index f5e916f..b80789d 100644 --- a/lib/repositories/potter_repository.dart +++ b/lib/repositories/potter_repository.dart @@ -6,7 +6,7 @@ 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( @@ -43,3 +43,4 @@ class PotterRepository extends ApiInterface { } } } +*/