From ff5720570da855fb59025ea77b4945ad0ce9c609 Mon Sep 17 00:00:00 2001 From: Igor Khramtsov Date: Fri, 10 Sep 2021 23:22:38 +0700 Subject: [PATCH 1/3] * fixing token refresh logic * reddit api --- ios/Podfile.lock | 2 +- .../accounts/bloc/accounts_bloc.dart | 23 ------- lib/application/feed/bloc/feed_bloc.dart | 24 ++++--- lib/application/navigator/app_navigator.dart | 3 +- lib/domain/managers/accounts_manager.dart | 50 ++++++++++++++ lib/infrastructure/api/reddit_api.dart | 26 ++++++-- lib/infrastructure/api/reddit_api.g.dart | 16 ++++- lib/infrastructure/api/reddit_auth_api.dart | 11 ++-- lib/injection.config.dart | 66 ++++++++++--------- lib/presentation/screens/Home.dart | 48 -------------- 10 files changed, 141 insertions(+), 128 deletions(-) create mode 100644 lib/domain/managers/accounts_manager.dart delete mode 100644 lib/presentation/screens/Home.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 68178c4..3d0f5a6 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -25,4 +25,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c -COCOAPODS: 1.10.1 +COCOAPODS: 1.10.2 diff --git a/lib/application/accounts/bloc/accounts_bloc.dart b/lib/application/accounts/bloc/accounts_bloc.dart index 24822c8..3189e59 100644 --- a/lib/application/accounts/bloc/accounts_bloc.dart +++ b/lib/application/accounts/bloc/accounts_bloc.dart @@ -3,15 +3,10 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:devour/application/navigator/app_navigator.dart'; import 'package:devour/application/navigator/routes.dart'; -import 'package:devour/domain/auth/oauth_account_model.dart'; import 'package:devour/domain/auth/reddit_account.dart'; import 'package:devour/domain/repositories/account_repository.dart'; -import 'package:devour/infrastructure/api/reddit_api.dart'; import 'package:devour/infrastructure/api/reddit_auth_api.dart'; import 'package:devour/infrastructure/core/misc.dart'; -import 'package:devour/infrastructure/register_module.dart'; -import 'package:devour/injection.dart'; -import 'package:dio/dio.dart'; import 'package:fpdart/fpdart.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:injectable/injectable.dart'; @@ -39,7 +34,6 @@ class AccountsBloc extends Bloc { yield* event.map( Fetching: (_Fetching value) async* { final account = _accountsRepository.getAccount(); - _updateDioOptions(account); yield state.copyWith( redditAccount: account, @@ -50,7 +44,6 @@ class AccountsBloc extends Bloc { final response = await _redditAuthAPI.getAccessToken(e.args.code); final account = RedditAccount.fromResponse(response); _accountsRepository.setAccount(account); - _updateDioOptions(Option.of(account)); yield state.copyWith( redditAccount: Option.of(account), @@ -70,20 +63,4 @@ class AccountsBloc extends Bloc { }, ); } - - /// Updates interceptors of reddit dio, to add Authorization header, and catch expired - /// token exception, to refresh it and retry. - void _updateDioOptions(Option accountOption) { - if (accountOption.isNone()) { - return; - } - final account = accountOption.toNullable()!; - - final dio = serviceLocator(instanceName: kRedditDioName); - dio.interceptors.clear(); - if (account is RedditAccount) { - dio.interceptors.add(RedditAPI.getAuthenticationTokenInterceptor()); - dio.interceptors.add(RedditAuthAPI.getRefreshTokenInterceptor(dio)); - } - } } diff --git a/lib/application/feed/bloc/feed_bloc.dart b/lib/application/feed/bloc/feed_bloc.dart index 7f63daa..ba52ef4 100644 --- a/lib/application/feed/bloc/feed_bloc.dart +++ b/lib/application/feed/bloc/feed_bloc.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:devour/domain/meme/abstract_meme_model.dart'; import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart'; +import 'package:devour/infrastructure/api/reddit_api.dart'; import 'package:fpdart/fpdart.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:injectable/injectable.dart'; @@ -15,14 +16,10 @@ const int kMemeChunkSize = 20; @injectable class FeedBloc extends Bloc { - IMemeScrapperFacade _memeScrapper; + RedditAPI redditAPI; - /// BLoC for feed widget. although [memeScrapper] marked as nullable, in must be not null. - /// It marked nullable because of Injectable. - FeedBloc(@factoryParam IMemeScrapperFacade? memeScrapper) - : assert(memeScrapper != null), - _memeScrapper = memeScrapper!, - super(FeedState.loading()); + /// BLoC for feed widget. + FeedBloc(this.redditAPI) : super(FeedState.loading()); @override Stream mapEventToState( @@ -31,12 +28,13 @@ class FeedBloc extends Bloc { yield* event.map( init: (e) async* { yield FeedState.loading(); - final scrappedMemes = await _memeScrapper.getMemes(kMemeChunkSize); - yield state.copyWith( - isLoading: false, - memes: scrappedMemes, - iterator: 0, - ); + final scrappedMemes = await redditAPI.getMemes(); + print(scrappedMemes); + // yield state.copyWith( + // isLoading: false, + // memes: scrappedMemes, + // iterator: 0, + // ); }, like: (e) async* { yield state; diff --git a/lib/application/navigator/app_navigator.dart b/lib/application/navigator/app_navigator.dart index cb87135..f52b18a 100644 --- a/lib/application/navigator/app_navigator.dart +++ b/lib/application/navigator/app_navigator.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:devour/application/navigator/routes.dart'; import 'package:devour/presentation/screens/accounts/accounts_screen.dart'; +import 'package:devour/presentation/screens/feed/feed_screen.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -55,7 +56,7 @@ class AppNavigator { return (BuildContext ctx) => AccountScreen( redirectArguments: settings.arguments! as RedditRedirectArguments); default: - return (BuildContext ctx) => AccountScreen(); + return (BuildContext ctx) => const FeedScreen(); } } diff --git a/lib/domain/managers/accounts_manager.dart b/lib/domain/managers/accounts_manager.dart new file mode 100644 index 0000000..f5f1df1 --- /dev/null +++ b/lib/domain/managers/accounts_manager.dart @@ -0,0 +1,50 @@ +import 'package:devour/domain/auth/oauth_account_model.dart'; +import 'package:devour/domain/auth/reddit_account.dart'; +import 'package:devour/domain/repositories/account_repository.dart'; +import 'package:collection/collection.dart'; +import 'package:devour/infrastructure/api/reddit_api.dart'; +import 'package:devour/infrastructure/api/reddit_auth_api.dart'; +import 'package:devour/infrastructure/register_module.dart'; +import 'package:devour/injection.dart'; +import 'package:dio/dio.dart'; +import 'package:fpdart/fpdart.dart'; +import 'package:injectable/injectable.dart'; + +@singleton +class AccountsManager { + AccountsRepository accountsRepository; + AccountsManager(this.accountsRepository); + + /// Creates account manager, and listen to accounts repo, to update interceptors + @factoryMethod + static Future init(AccountsRepository accountsRepository) async { + final manager = AccountsManager(accountsRepository); + manager.initAccountsListener(); + + return manager; + } + + /// Listen to accounts in repo, and updates `Dio` interceptors accordingly + void initAccountsListener() { + accountsRepository.accounts.listen((accounts) { + final redditAccount = accounts.whereType().firstOrNull; + _updateDioOptions(Option.fromNullable(redditAccount)); + }); + } + + /// Updates interceptors of reddit dio, to add Authorization header, and catch expired + /// token exception, to refresh it and retry. + void _updateDioOptions(Option accountOption) { + if (accountOption.isNone()) { + return; + } + final account = accountOption.toNullable()!; + + final dio = serviceLocator(instanceName: kRedditDioName); + dio.interceptors.clear(); + if (account is RedditAccount) { + dio.interceptors.add(RedditAPI.getAuthenticationTokenInterceptor()); + dio.interceptors.add(RedditAuthAPI.getRefreshTokenInterceptor(dio)); + } + } +} \ No newline at end of file diff --git a/lib/infrastructure/api/reddit_api.dart b/lib/infrastructure/api/reddit_api.dart index 0558dd3..3a5bec1 100644 --- a/lib/infrastructure/api/reddit_api.dart +++ b/lib/infrastructure/api/reddit_api.dart @@ -1,13 +1,23 @@ import 'package:devour/domain/auth/reddit_account.dart'; import 'package:devour/domain/repositories/account_repository.dart'; +import 'package:devour/infrastructure/api/reddit_auth_api.dart'; +import 'package:devour/infrastructure/register_module.dart'; import 'package:devour/injection.dart'; import 'package:dio/dio.dart'; +import 'package:injectable/injectable.dart'; import 'package:retrofit/retrofit.dart'; part 'reddit_api.g.dart'; -@RestApi(baseUrl: 'https://oauth.reddit.com/api/v1') -class RedditAPI { +@singleton +@RestApi(baseUrl: 'https://oauth.reddit.com') +abstract class RedditAPI { + @factoryMethod + factory RedditAPI(@Named(kRedditDioName) Dio dio) = _RedditAPI; + + @GET('/r/memes') + Future getMemes(); + static Interceptor getAuthenticationTokenInterceptor() => AuthenticationTokenInterceptor(); } @@ -17,11 +27,13 @@ class AuthenticationTokenInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { - final account = - serviceLocator().getAccount(); - if (account.isSome()) { - options.headers['Authorization'] = - 'Bearer ${account.toNullable()!.accessToken}'; + if (options.path != kAccessTokenPath) { + final account = + serviceLocator().getAccount(); + if (account.isSome()) { + options.headers['Authorization'] = + 'bearer ${account.toNullable()!.accessToken}'; + } } handler.next(options); diff --git a/lib/infrastructure/api/reddit_api.g.dart b/lib/infrastructure/api/reddit_api.g.dart index 86a835a..d83d9c6 100644 --- a/lib/infrastructure/api/reddit_api.g.dart +++ b/lib/infrastructure/api/reddit_api.g.dart @@ -8,13 +8,27 @@ part of 'reddit_api.dart'; class _RedditAPI implements RedditAPI { _RedditAPI(this._dio, {this.baseUrl}) { - baseUrl ??= 'https://oauth.reddit.com/api/v1'; + baseUrl ??= 'https://oauth.reddit.com'; } final Dio _dio; String? baseUrl; + @override + Future getMemes() async { + const _extra = {}; + final queryParameters = {}; + final _data = {}; + final _result = await _dio.fetch(_setStreamType( + Options(method: 'GET', headers: {}, extra: _extra) + .compose(_dio.options, '/r/memes', + queryParameters: queryParameters, data: _data) + .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); + final value = _result.data; + return value; + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || diff --git a/lib/infrastructure/api/reddit_auth_api.dart b/lib/infrastructure/api/reddit_auth_api.dart index 636b99e..e484518 100644 --- a/lib/infrastructure/api/reddit_auth_api.dart +++ b/lib/infrastructure/api/reddit_auth_api.dart @@ -13,9 +13,10 @@ part 'reddit_auth_api.g.dart'; part 'reddit_auth_api.freezed.dart'; const String _kBaseUrl = 'https://www.reddit.com/api/v1/'; +const String kAccessTokenPath = '/access_token'; // add ignored to path, because flutter sometimes dont show first path element const String _kRedirectUrl = 'devour://ignored/reddit/auth_redirect'; -const int _kRefreshTokenNeeded = 0; +const int _kRefreshTokenNeeded = 401; @Singleton() @RestApi(baseUrl: _kBaseUrl) @@ -23,7 +24,7 @@ abstract class RedditAuthAPI { @factoryMethod factory RedditAuthAPI(@Named(kRedditDioName) Dio dio) = _RedditAuthAPI; - @POST('/access_token') + @POST(kAccessTokenPath) Future _getAccessToken({ @Query('grant_type') required String grantType, @Query('refresh_token') String? refreshToken, @@ -45,7 +46,8 @@ class RefreshTokenInterceptor extends Interceptor { @override Future onError(DioError err, ErrorInterceptorHandler handler) async { - if (err.response?.statusCode == _kRefreshTokenNeeded) { + if (err.response?.statusCode == _kRefreshTokenNeeded && + err.response?.requestOptions.path != kAccessTokenPath) { final requestOptions = err.response!.requestOptions; final options = Options( method: requestOptions.method, @@ -58,7 +60,7 @@ class RefreshTokenInterceptor extends Interceptor { final newAccount = RedditAccount.fromResponse( await serviceLocator().refreshToken(account)); serviceLocator().setAccount(newAccount); - options.headers!['Authorization'] = 'Bearer ${newAccount.accessToken}'; + options.headers!['Authorization'] = 'bearer ${newAccount.accessToken}'; final cloneRequest = await dio.request(requestOptions.path, options: options, queryParameters: requestOptions.queryParameters); @@ -91,6 +93,7 @@ extension Authorize on RedditAuthAPI { _getAccessToken( grantType: 'refresh_token', refreshToken: account.refreshToken, + authorization: getBasicCredentials(EnvVariables.clientId, ''), ); Future getAccessToken(String code) => _getAccessToken( diff --git a/lib/injection.config.dart b/lib/injection.config.dart index 3fe08f2..021b857 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -4,24 +4,27 @@ // InjectableConfigGenerator // ************************************************************************** -import 'package:devour/application/accounts/bloc/accounts_bloc.dart' as _i10; -import 'package:devour/application/auth/login/login_bloc.dart' as _i9; -import 'package:devour/application/feed/bloc/feed_bloc.dart' as _i4; +import 'package:devour/application/accounts/bloc/accounts_bloc.dart' as _i9; +import 'package:devour/application/auth/login/login_bloc.dart' as _i6; +import 'package:devour/application/feed/bloc/feed_bloc.dart' as _i7; import 'package:devour/application/navigator/app_navigator.dart' as _i3; -import 'package:devour/domain/auth/i_auth_facade.dart' as _i7; -import 'package:devour/domain/meme/abstract_meme_model.dart' as _i6; -import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart' as _i5; -import 'package:devour/domain/repositories/account_repository.dart' as _i12; -import 'package:devour/infrastructure/api/reddit_auth_api.dart' as _i11; -import 'package:devour/infrastructure/auth/telegram_auth_facade.dart' as _i8; -import 'package:devour/infrastructure/data/local/data_adapter.dart' as _i14; -import 'package:devour/infrastructure/data/local/hive_adapter.dart' as _i15; +import 'package:devour/domain/auth/i_auth_facade.dart' as _i4; +import 'package:devour/domain/managers/accounts_manager.dart' as _i19; +import 'package:devour/domain/meme/abstract_meme_model.dart' as _i16; +import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart' + as _i15; +import 'package:devour/domain/repositories/account_repository.dart' as _i11; +import 'package:devour/infrastructure/api/reddit_api.dart' as _i8; +import 'package:devour/infrastructure/api/reddit_auth_api.dart' as _i10; +import 'package:devour/infrastructure/auth/telegram_auth_facade.dart' as _i5; +import 'package:devour/infrastructure/data/local/data_adapter.dart' as _i13; +import 'package:devour/infrastructure/data/local/hive_adapter.dart' as _i14; import 'package:devour/infrastructure/meme_scrapper/reddit_scrapper_facade.dart' - as _i16; -import 'package:devour/infrastructure/register_module.dart' as _i18; -import 'package:devour/infrastructure/repositories/accounts_repository.dart' as _i17; -import 'package:dio/dio.dart' as _i13; +import 'package:devour/infrastructure/register_module.dart' as _i20; +import 'package:devour/infrastructure/repositories/accounts_repository.dart' + as _i18; +import 'package:dio/dio.dart' as _i12; import 'package:get_it/get_it.dart' as _i1; import 'package:injectable/injectable.dart' as _i2; // ignore_for_file: unnecessary_lambdas @@ -33,24 +36,27 @@ Future<_i1.GetIt> $initGetIt(_i1.GetIt get, final gh = _i2.GetItHelper(get, environment, environmentFilter); final registerModule = _$RegisterModule(); gh.factory<_i3.AppNavigator>(() => _i3.AppNavigator()); - gh.factoryParam<_i4.FeedBloc, _i5.IMemeScrapperFacade<_i6.AbstractMemeModel>?, - dynamic>((memeScrapper, _) => _i4.FeedBloc(memeScrapper)); - gh.factory<_i7.IAuthFacade>(() => _i8.TelegramAuthFacade()); - gh.factory<_i9.LoginBloc>(() => _i9.LoginBloc(get<_i7.IAuthFacade>())); - gh.factory<_i10.AccountsBloc>(() => _i10.AccountsBloc( - get<_i11.RedditAuthAPI>(), get<_i12.AccountsRepository>())); - gh.singleton<_i13.Dio>(registerModule.getRedditDio(), + gh.factory<_i4.IAuthFacade>(() => _i5.TelegramAuthFacade()); + gh.factory<_i6.LoginBloc>(() => _i6.LoginBloc(get<_i4.IAuthFacade>())); + gh.factory<_i7.FeedBloc>(() => _i7.FeedBloc(get<_i8.RedditAPI>())); + gh.factory<_i9.AccountsBloc>(() => _i9.AccountsBloc( + get<_i10.RedditAuthAPI>(), get<_i11.AccountsRepository>())); + gh.singleton<_i12.Dio>(registerModule.getRedditDio(), instanceName: 'redditDio'); - await gh.singletonAsync<_i14.IDataAdapter>(() => _i15.HiveAdapter.create(), + await gh.singletonAsync<_i13.IDataAdapter>(() => _i14.HiveAdapter.create(), preResolve: true); - gh.singleton<_i5.IMemeScrapperFacade<_i6.RedditMemeModel>>( - _i16.RedditScrapperFacade(get<_i13.Dio>(instanceName: 'redditDio'))); - gh.singleton<_i11.RedditAuthAPI>( - _i11.RedditAuthAPI(get<_i13.Dio>(instanceName: 'redditDio'))); - await gh.singletonAsync<_i12.AccountsRepository>( - () => _i17.AccountsRepositoryImpl.create(get<_i14.IDataAdapter>()), + gh.singleton<_i15.IMemeScrapperFacade<_i16.RedditMemeModel>>( + _i17.RedditScrapperFacade(get<_i12.Dio>(instanceName: 'redditDio'))); + gh.singleton<_i8.RedditAPI>( + _i8.RedditAPI(get<_i12.Dio>(instanceName: 'redditDio'))); + gh.singleton<_i10.RedditAuthAPI>( + _i10.RedditAuthAPI(get<_i12.Dio>(instanceName: 'redditDio'))); + await gh.singletonAsync<_i11.AccountsRepository>( + () => _i18.AccountsRepositoryImpl.create(get<_i13.IDataAdapter>()), preResolve: true); + gh.singletonAsync<_i19.AccountsManager>( + () => _i19.AccountsManager.init(get<_i11.AccountsRepository>())); return get; } -class _$RegisterModule extends _i18.RegisterModule {} +class _$RegisterModule extends _i20.RegisterModule {} diff --git a/lib/presentation/screens/Home.dart b/lib/presentation/screens/Home.dart deleted file mode 100644 index a304949..0000000 --- a/lib/presentation/screens/Home.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -class MyHomePage extends StatefulWidget { - MyHomePage({Key? key, required this.title}) : super(key: key); - final String title; - - @override - _MyHomePageState createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headline4, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: Icon(Icons.add), - ), - ); - } -} From 9ad4ab26b5bef7f7d8bca3664ba7ee386dc3f9c1 Mon Sep 17 00:00:00 2001 From: Igor Khramtsov Date: Sat, 11 Sep 2021 22:22:22 +0700 Subject: [PATCH 2/3] * dependencies upgraded * structure reorganizing (move reddit api to redidt folder) + reddit response classes --- .gitignore | 1 + ios/Flutter/AppFrameworkInfo.plist | 2 +- ios/Podfile.lock | 2 +- .../accounts/bloc/accounts_bloc.dart | 4 +- .../accounts/bloc/accounts_bloc.freezed.dart | 147 ++- .../auth/login/login_bloc.freezed.dart | 107 +- lib/application/feed/bloc/feed_bloc.dart | 6 +- .../feed/bloc/feed_bloc.freezed.dart | 107 +- lib/application/navigator/routes.freezed.dart | 3 +- lib/domain/auth/auth_failure.freezed.dart | 51 +- lib/domain/auth/reddit_account.dart | 2 +- lib/domain/auth/reddit_account.freezed.dart | 3 +- lib/domain/managers/accounts_manager.dart | 11 +- .../meme/abstract_meme_model.freezed.dart | 101 +- lib/domain/meme/abstract_meme_model.g.dart | 54 +- .../api/{ => reddit}/reddit_api.dart | 5 +- .../api/{ => reddit}/reddit_api.g.dart | 15 +- .../api/{ => reddit}/reddit_auth_api.dart | 19 +- .../api/{ => reddit}/reddit_auth_api.g.dart | 25 - .../reddit/response/reddit_auth_response.dart | 20 + .../reddit_auth_response.freezed.dart} | 9 +- .../response/reddit_auth_response.g.dart | 27 + .../api/reddit/response/reddit_responses.dart | 80 ++ .../response/reddit_responses.freezed.dart | 919 ++++++++++++++++++ .../reddit/response/reddit_responses.g.dart | 76 ++ lib/infrastructure/core/misc.dart | 5 + lib/injection.config.dart | 63 +- .../screens/accounts/accounts_screen.dart | 1 - pubspec.lock | 44 +- pubspec.yaml | 25 +- 30 files changed, 1756 insertions(+), 178 deletions(-) rename lib/infrastructure/api/{ => reddit}/reddit_api.dart (85%) rename lib/infrastructure/api/{ => reddit}/reddit_api.g.dart (67%) rename lib/infrastructure/api/{ => reddit}/reddit_auth_api.dart (85%) rename lib/infrastructure/api/{ => reddit}/reddit_auth_api.g.dart (68%) create mode 100644 lib/infrastructure/api/reddit/response/reddit_auth_response.dart rename lib/infrastructure/api/{reddit_auth_api.freezed.dart => reddit/response/reddit_auth_response.freezed.dart} (97%) create mode 100644 lib/infrastructure/api/reddit/response/reddit_auth_response.g.dart create mode 100644 lib/infrastructure/api/reddit/response/reddit_responses.dart create mode 100644 lib/infrastructure/api/reddit/response/reddit_responses.freezed.dart create mode 100644 lib/infrastructure/api/reddit/response/reddit_responses.g.dart diff --git a/.gitignore b/.gitignore index e565663..a0f8c36 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ .pub-cache/ .pub/ /build/ +ios/build/ # Web related lib/generated_plugin_registrant.dart diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9367d48..8d4492f 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 9.0 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3d0f5a6..ca8ea86 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -19,7 +19,7 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/url_launcher/ios" SPEC CHECKSUMS: - Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef diff --git a/lib/application/accounts/bloc/accounts_bloc.dart b/lib/application/accounts/bloc/accounts_bloc.dart index 3189e59..15d0ca6 100644 --- a/lib/application/accounts/bloc/accounts_bloc.dart +++ b/lib/application/accounts/bloc/accounts_bloc.dart @@ -1,12 +1,12 @@ import 'dart:async'; -import 'package:bloc/bloc.dart'; import 'package:devour/application/navigator/app_navigator.dart'; import 'package:devour/application/navigator/routes.dart'; import 'package:devour/domain/auth/reddit_account.dart'; import 'package:devour/domain/repositories/account_repository.dart'; -import 'package:devour/infrastructure/api/reddit_auth_api.dart'; +import 'package:devour/infrastructure/api/reddit/reddit_auth_api.dart'; import 'package:devour/infrastructure/core/misc.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:fpdart/fpdart.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:injectable/injectable.dart'; diff --git a/lib/application/accounts/bloc/accounts_bloc.freezed.dart b/lib/application/accounts/bloc/accounts_bloc.freezed.dart index 9e3b48d..4a6c832 100644 --- a/lib/application/accounts/bloc/accounts_bloc.freezed.dart +++ b/lib/application/accounts/bloc/accounts_bloc.freezed.dart @@ -1,5 +1,6 @@ +// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target part of 'accounts_bloc.dart'; @@ -54,6 +55,15 @@ mixin _$AccountsEvent { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? Fetching, + TResult Function()? RequestAuthorizationReddit, + TResult Function()? RequestAuthorizationVK, + TResult Function(RedditRedirectArguments args)? AuthorizeReddit, + TResult Function()? AuthorizeVK, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeWhen({ TResult Function()? Fetching, TResult Function()? RequestAuthorizationReddit, @@ -75,6 +85,16 @@ mixin _$AccountsEvent { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Fetching value)? Fetching, + TResult Function(_RequestAuthorizationReddit value)? + RequestAuthorizationReddit, + TResult Function(_RequestAuthorizationVK value)? RequestAuthorizationVK, + TResult Function(_AuthorizeReddit value)? AuthorizeReddit, + TResult Function(_AuthorizeVK value)? AuthorizeVK, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeMap({ TResult Function(_Fetching value)? Fetching, TResult Function(_RequestAuthorizationReddit value)? @@ -150,6 +170,18 @@ class _$_Fetching implements _Fetching { return Fetching(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? Fetching, + TResult Function()? RequestAuthorizationReddit, + TResult Function()? RequestAuthorizationVK, + TResult Function(RedditRedirectArguments args)? AuthorizeReddit, + TResult Function()? AuthorizeVK, + }) { + return Fetching?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -180,6 +212,19 @@ class _$_Fetching implements _Fetching { return Fetching(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Fetching value)? Fetching, + TResult Function(_RequestAuthorizationReddit value)? + RequestAuthorizationReddit, + TResult Function(_RequestAuthorizationVK value)? RequestAuthorizationVK, + TResult Function(_AuthorizeReddit value)? AuthorizeReddit, + TResult Function(_AuthorizeVK value)? AuthorizeVK, + }) { + return Fetching?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -253,6 +298,18 @@ class _$_RequestAuthorizationReddit implements _RequestAuthorizationReddit { return RequestAuthorizationReddit(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? Fetching, + TResult Function()? RequestAuthorizationReddit, + TResult Function()? RequestAuthorizationVK, + TResult Function(RedditRedirectArguments args)? AuthorizeReddit, + TResult Function()? AuthorizeVK, + }) { + return RequestAuthorizationReddit?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -283,6 +340,19 @@ class _$_RequestAuthorizationReddit implements _RequestAuthorizationReddit { return RequestAuthorizationReddit(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Fetching value)? Fetching, + TResult Function(_RequestAuthorizationReddit value)? + RequestAuthorizationReddit, + TResult Function(_RequestAuthorizationVK value)? RequestAuthorizationVK, + TResult Function(_AuthorizeReddit value)? AuthorizeReddit, + TResult Function(_AuthorizeVK value)? AuthorizeVK, + }) { + return RequestAuthorizationReddit?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -354,6 +424,18 @@ class _$_RequestAuthorizationVK implements _RequestAuthorizationVK { return RequestAuthorizationVK(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? Fetching, + TResult Function()? RequestAuthorizationReddit, + TResult Function()? RequestAuthorizationVK, + TResult Function(RedditRedirectArguments args)? AuthorizeReddit, + TResult Function()? AuthorizeVK, + }) { + return RequestAuthorizationVK?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -384,6 +466,19 @@ class _$_RequestAuthorizationVK implements _RequestAuthorizationVK { return RequestAuthorizationVK(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Fetching value)? Fetching, + TResult Function(_RequestAuthorizationReddit value)? + RequestAuthorizationReddit, + TResult Function(_RequestAuthorizationVK value)? RequestAuthorizationVK, + TResult Function(_AuthorizeReddit value)? AuthorizeReddit, + TResult Function(_AuthorizeVK value)? AuthorizeVK, + }) { + return RequestAuthorizationVK?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -489,6 +584,18 @@ class _$_AuthorizeReddit implements _AuthorizeReddit { return AuthorizeReddit(args); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? Fetching, + TResult Function()? RequestAuthorizationReddit, + TResult Function()? RequestAuthorizationVK, + TResult Function(RedditRedirectArguments args)? AuthorizeReddit, + TResult Function()? AuthorizeVK, + }) { + return AuthorizeReddit?.call(args); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -519,6 +626,19 @@ class _$_AuthorizeReddit implements _AuthorizeReddit { return AuthorizeReddit(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Fetching value)? Fetching, + TResult Function(_RequestAuthorizationReddit value)? + RequestAuthorizationReddit, + TResult Function(_RequestAuthorizationVK value)? RequestAuthorizationVK, + TResult Function(_AuthorizeReddit value)? AuthorizeReddit, + TResult Function(_AuthorizeVK value)? AuthorizeVK, + }) { + return AuthorizeReddit?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -595,6 +715,18 @@ class _$_AuthorizeVK implements _AuthorizeVK { return AuthorizeVK(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? Fetching, + TResult Function()? RequestAuthorizationReddit, + TResult Function()? RequestAuthorizationVK, + TResult Function(RedditRedirectArguments args)? AuthorizeReddit, + TResult Function()? AuthorizeVK, + }) { + return AuthorizeVK?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -625,6 +757,19 @@ class _$_AuthorizeVK implements _AuthorizeVK { return AuthorizeVK(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Fetching value)? Fetching, + TResult Function(_RequestAuthorizationReddit value)? + RequestAuthorizationReddit, + TResult Function(_RequestAuthorizationVK value)? RequestAuthorizationVK, + TResult Function(_AuthorizeReddit value)? AuthorizeReddit, + TResult Function(_AuthorizeVK value)? AuthorizeVK, + }) { + return AuthorizeVK?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ diff --git a/lib/application/auth/login/login_bloc.freezed.dart b/lib/application/auth/login/login_bloc.freezed.dart index ec34fc1..e981b86 100644 --- a/lib/application/auth/login/login_bloc.freezed.dart +++ b/lib/application/auth/login/login_bloc.freezed.dart @@ -1,5 +1,6 @@ +// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target part of 'login_bloc.dart'; @@ -51,6 +52,14 @@ mixin _$LoginEvent { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? whenOrNull({ + TResult Function(String number)? numberChanged, + TResult Function(String confirmationCode)? confirmationCodeChanged, + TResult Function()? loginPressed, + TResult Function()? confirmPressed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeWhen({ TResult Function(String number)? numberChanged, TResult Function(String confirmationCode)? confirmationCodeChanged, @@ -69,6 +78,14 @@ mixin _$LoginEvent { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(NumberChanged value)? numberChanged, + TResult Function(ConfirmationCodeChanged value)? confirmationCodeChanged, + TResult Function(LoginPressed value)? loginPressed, + TResult Function(ConfirmPressed value)? confirmPressed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeMap({ TResult Function(NumberChanged value)? numberChanged, TResult Function(ConfirmationCodeChanged value)? confirmationCodeChanged, @@ -167,6 +184,17 @@ class _$NumberChanged implements NumberChanged { return numberChanged(number); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function(String number)? numberChanged, + TResult Function(String confirmationCode)? confirmationCodeChanged, + TResult Function()? loginPressed, + TResult Function()? confirmPressed, + }) { + return numberChanged?.call(number); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -194,6 +222,17 @@ class _$NumberChanged implements NumberChanged { return numberChanged(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(NumberChanged value)? numberChanged, + TResult Function(ConfirmationCodeChanged value)? confirmationCodeChanged, + TResult Function(LoginPressed value)? loginPressed, + TResult Function(ConfirmPressed value)? confirmPressed, + }) { + return numberChanged?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -295,6 +334,17 @@ class _$ConfirmationCodeChanged implements ConfirmationCodeChanged { return confirmationCodeChanged(confirmationCode); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function(String number)? numberChanged, + TResult Function(String confirmationCode)? confirmationCodeChanged, + TResult Function()? loginPressed, + TResult Function()? confirmPressed, + }) { + return confirmationCodeChanged?.call(confirmationCode); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -322,6 +372,17 @@ class _$ConfirmationCodeChanged implements ConfirmationCodeChanged { return confirmationCodeChanged(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(NumberChanged value)? numberChanged, + TResult Function(ConfirmationCodeChanged value)? confirmationCodeChanged, + TResult Function(LoginPressed value)? loginPressed, + TResult Function(ConfirmPressed value)? confirmPressed, + }) { + return confirmationCodeChanged?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -395,6 +456,17 @@ class _$LoginPressed implements LoginPressed { return loginPressed(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function(String number)? numberChanged, + TResult Function(String confirmationCode)? confirmationCodeChanged, + TResult Function()? loginPressed, + TResult Function()? confirmPressed, + }) { + return loginPressed?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -422,6 +494,17 @@ class _$LoginPressed implements LoginPressed { return loginPressed(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(NumberChanged value)? numberChanged, + TResult Function(ConfirmationCodeChanged value)? confirmationCodeChanged, + TResult Function(LoginPressed value)? loginPressed, + TResult Function(ConfirmPressed value)? confirmPressed, + }) { + return loginPressed?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -489,6 +572,17 @@ class _$ConfirmPressed implements ConfirmPressed { return confirmPressed(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function(String number)? numberChanged, + TResult Function(String confirmationCode)? confirmationCodeChanged, + TResult Function()? loginPressed, + TResult Function()? confirmPressed, + }) { + return confirmPressed?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -516,6 +610,17 @@ class _$ConfirmPressed implements ConfirmPressed { return confirmPressed(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(NumberChanged value)? numberChanged, + TResult Function(ConfirmationCodeChanged value)? confirmationCodeChanged, + TResult Function(LoginPressed value)? loginPressed, + TResult Function(ConfirmPressed value)? confirmPressed, + }) { + return confirmPressed?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ diff --git a/lib/application/feed/bloc/feed_bloc.dart b/lib/application/feed/bloc/feed_bloc.dart index ba52ef4..1dd6c5f 100644 --- a/lib/application/feed/bloc/feed_bloc.dart +++ b/lib/application/feed/bloc/feed_bloc.dart @@ -1,10 +1,8 @@ import 'dart:async'; -import 'package:bloc/bloc.dart'; import 'package:devour/domain/meme/abstract_meme_model.dart'; -import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart'; -import 'package:devour/infrastructure/api/reddit_api.dart'; -import 'package:fpdart/fpdart.dart'; +import 'package:devour/infrastructure/api/reddit/reddit_api.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:injectable/injectable.dart'; diff --git a/lib/application/feed/bloc/feed_bloc.freezed.dart b/lib/application/feed/bloc/feed_bloc.freezed.dart index d7b7237..5a03bfc 100644 --- a/lib/application/feed/bloc/feed_bloc.freezed.dart +++ b/lib/application/feed/bloc/feed_bloc.freezed.dart @@ -1,5 +1,6 @@ +// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target part of 'feed_bloc.dart'; @@ -47,6 +48,14 @@ mixin _$FeedEvent { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? like, + TResult Function()? refresh, + TResult Function()? next, + TResult Function()? init, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeWhen({ TResult Function()? like, TResult Function()? refresh, @@ -64,6 +73,14 @@ mixin _$FeedEvent { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Like value)? like, + TResult Function(_Refresh value)? refresh, + TResult Function(_Next value)? next, + TResult Function(_Init value)? init, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeMap({ TResult Function(_Like value)? like, TResult Function(_Refresh value)? refresh, @@ -134,6 +151,17 @@ class _$_Like implements _Like { return like(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? like, + TResult Function()? refresh, + TResult Function()? next, + TResult Function()? init, + }) { + return like?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -160,6 +188,17 @@ class _$_Like implements _Like { return like(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Like value)? like, + TResult Function(_Refresh value)? refresh, + TResult Function(_Next value)? next, + TResult Function(_Init value)? init, + }) { + return like?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -225,6 +264,17 @@ class _$_Refresh implements _Refresh { return refresh(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? like, + TResult Function()? refresh, + TResult Function()? next, + TResult Function()? init, + }) { + return refresh?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -251,6 +301,17 @@ class _$_Refresh implements _Refresh { return refresh(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Like value)? like, + TResult Function(_Refresh value)? refresh, + TResult Function(_Next value)? next, + TResult Function(_Init value)? init, + }) { + return refresh?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -316,6 +377,17 @@ class _$_Next implements _Next { return next(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? like, + TResult Function()? refresh, + TResult Function()? next, + TResult Function()? init, + }) { + return next?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -342,6 +414,17 @@ class _$_Next implements _Next { return next(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Like value)? like, + TResult Function(_Refresh value)? refresh, + TResult Function(_Next value)? next, + TResult Function(_Init value)? init, + }) { + return next?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -407,6 +490,17 @@ class _$_Init implements _Init { return init(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? like, + TResult Function()? refresh, + TResult Function()? next, + TResult Function()? init, + }) { + return init?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -433,6 +527,17 @@ class _$_Init implements _Init { return init(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(_Like value)? like, + TResult Function(_Refresh value)? refresh, + TResult Function(_Next value)? next, + TResult Function(_Init value)? init, + }) { + return init?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ diff --git a/lib/application/navigator/routes.freezed.dart b/lib/application/navigator/routes.freezed.dart index 4149a2c..dc5143a 100644 --- a/lib/application/navigator/routes.freezed.dart +++ b/lib/application/navigator/routes.freezed.dart @@ -1,5 +1,6 @@ +// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target part of 'routes.dart'; diff --git a/lib/domain/auth/auth_failure.freezed.dart b/lib/domain/auth/auth_failure.freezed.dart index 206aec2..3873acc 100644 --- a/lib/domain/auth/auth_failure.freezed.dart +++ b/lib/domain/auth/auth_failure.freezed.dart @@ -1,5 +1,6 @@ +// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target part of 'auth_failure.dart'; @@ -37,6 +38,12 @@ mixin _$AuthFailure { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? invalidNumber, + TResult Function()? userNotFound, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeWhen({ TResult Function()? invalidNumber, TResult Function()? userNotFound, @@ -50,6 +57,12 @@ mixin _$AuthFailure { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(InvalidNumber value)? invalidNumber, + TResult Function(UserNotFound value)? userNotFound, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeMap({ TResult Function(InvalidNumber value)? invalidNumber, TResult Function(UserNotFound value)? userNotFound, @@ -125,6 +138,15 @@ class _$InvalidNumber with DiagnosticableTreeMixin implements InvalidNumber { return invalidNumber(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? invalidNumber, + TResult Function()? userNotFound, + }) { + return invalidNumber?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -147,6 +169,15 @@ class _$InvalidNumber with DiagnosticableTreeMixin implements InvalidNumber { return invalidNumber(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(InvalidNumber value)? invalidNumber, + TResult Function(UserNotFound value)? userNotFound, + }) { + return invalidNumber?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -216,6 +247,15 @@ class _$UserNotFound with DiagnosticableTreeMixin implements UserNotFound { return userNotFound(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? invalidNumber, + TResult Function()? userNotFound, + }) { + return userNotFound?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -238,6 +278,15 @@ class _$UserNotFound with DiagnosticableTreeMixin implements UserNotFound { return userNotFound(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(InvalidNumber value)? invalidNumber, + TResult Function(UserNotFound value)? userNotFound, + }) { + return userNotFound?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ diff --git a/lib/domain/auth/reddit_account.dart b/lib/domain/auth/reddit_account.dart index d531462..02d5aec 100644 --- a/lib/domain/auth/reddit_account.dart +++ b/lib/domain/auth/reddit_account.dart @@ -1,5 +1,5 @@ import 'package:devour/domain/auth/oauth_account_model.dart'; -import 'package:devour/infrastructure/api/reddit_auth_api.dart'; +import 'package:devour/infrastructure/api/reddit/response/reddit_auth_response.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hive_flutter/hive_flutter.dart'; diff --git a/lib/domain/auth/reddit_account.freezed.dart b/lib/domain/auth/reddit_account.freezed.dart index 5fb4cd5..84fa37f 100644 --- a/lib/domain/auth/reddit_account.freezed.dart +++ b/lib/domain/auth/reddit_account.freezed.dart @@ -1,5 +1,6 @@ +// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target part of 'reddit_account.dart'; diff --git a/lib/domain/managers/accounts_manager.dart b/lib/domain/managers/accounts_manager.dart index f5f1df1..17a52fb 100644 --- a/lib/domain/managers/accounts_manager.dart +++ b/lib/domain/managers/accounts_manager.dart @@ -1,9 +1,9 @@ +import 'package:collection/collection.dart'; import 'package:devour/domain/auth/oauth_account_model.dart'; import 'package:devour/domain/auth/reddit_account.dart'; import 'package:devour/domain/repositories/account_repository.dart'; -import 'package:collection/collection.dart'; -import 'package:devour/infrastructure/api/reddit_api.dart'; -import 'package:devour/infrastructure/api/reddit_auth_api.dart'; +import 'package:devour/infrastructure/api/reddit/reddit_api.dart'; +import 'package:devour/infrastructure/api/reddit/reddit_auth_api.dart'; import 'package:devour/infrastructure/register_module.dart'; import 'package:devour/injection.dart'; import 'package:dio/dio.dart'; @@ -17,7 +17,8 @@ class AccountsManager { /// Creates account manager, and listen to accounts repo, to update interceptors @factoryMethod - static Future init(AccountsRepository accountsRepository) async { + static Future init( + AccountsRepository accountsRepository) async { final manager = AccountsManager(accountsRepository); manager.initAccountsListener(); @@ -47,4 +48,4 @@ class AccountsManager { dio.interceptors.add(RedditAuthAPI.getRefreshTokenInterceptor(dio)); } } -} \ No newline at end of file +} diff --git a/lib/domain/meme/abstract_meme_model.freezed.dart b/lib/domain/meme/abstract_meme_model.freezed.dart index c33fd79..e269163 100644 --- a/lib/domain/meme/abstract_meme_model.freezed.dart +++ b/lib/domain/meme/abstract_meme_model.freezed.dart @@ -1,5 +1,6 @@ +// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target part of 'abstract_meme_model.dart'; @@ -13,14 +14,15 @@ final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); AbstractMemeModel _$AbstractMemeModelFromJson(Map json) { - switch (json['runtimeType'] as String) { + switch (json['runtimeType'] as String?) { case 'default': return _AbstractMemeModel.fromJson(json); case 'reddit': return RedditMemeModel.fromJson(json); default: - throw FallThroughError(); + throw CheckedFromJsonException(json, 'runtimeType', 'AbstractMemeModel', + 'Invalid union type "${json['runtimeType']}"!'); } } @@ -101,6 +103,24 @@ mixin _$AbstractMemeModel { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? whenOrNull( + TResult Function(String sourceLink, String imageLink, String title, + String author, List imagePreviews)? + $default, { + TResult Function( + String title, + String author, + @JsonKey(name: 'image_reviews') List imagePreviews, + @JsonKey(name: 'url') String imageLink, + @JsonKey(name: 'post_link') String sourceLink, + String subreddit, + int ups, + @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, + bool nsfw)? + reddit, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeWhen( TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews)? @@ -126,6 +146,12 @@ mixin _$AbstractMemeModel { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? mapOrNull( + TResult Function(_AbstractMemeModel value)? $default, { + TResult Function(RedditMemeModel value)? reddit, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeMap( TResult Function(_AbstractMemeModel value)? $default, { TResult Function(RedditMemeModel value)? reddit, @@ -264,7 +290,7 @@ class _$_AbstractMemeModel extends _AbstractMemeModel { : super._(); factory _$_AbstractMemeModel.fromJson(Map json) => - _$_$_AbstractMemeModelFromJson(json); + _$$_AbstractMemeModelFromJson(json); @override final String sourceLink; @@ -336,6 +362,27 @@ class _$_AbstractMemeModel extends _AbstractMemeModel { return $default(sourceLink, imageLink, title, author, imagePreviews); } + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult Function(String sourceLink, String imageLink, String title, + String author, List imagePreviews)? + $default, { + TResult Function( + String title, + String author, + @JsonKey(name: 'image_reviews') List imagePreviews, + @JsonKey(name: 'url') String imageLink, + @JsonKey(name: 'post_link') String sourceLink, + String subreddit, + int ups, + @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, + bool nsfw)? + reddit, + }) { + return $default?.call(sourceLink, imageLink, title, author, imagePreviews); + } + @override @optionalTypeArgs TResult maybeWhen( @@ -370,6 +417,15 @@ class _$_AbstractMemeModel extends _AbstractMemeModel { return $default(this); } + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult Function(_AbstractMemeModel value)? $default, { + TResult Function(RedditMemeModel value)? reddit, + }) { + return $default?.call(this); + } + @override @optionalTypeArgs TResult maybeMap( @@ -385,7 +441,7 @@ class _$_AbstractMemeModel extends _AbstractMemeModel { @override Map toJson() { - return _$_$_AbstractMemeModelToJson(this)..['runtimeType'] = 'default'; + return _$$_AbstractMemeModelToJson(this)..['runtimeType'] = 'default'; } } @@ -516,7 +572,7 @@ class _$RedditMemeModel extends RedditMemeModel { : super._(); factory _$RedditMemeModel.fromJson(Map json) => - _$_$RedditMemeModelFromJson(json); + _$$RedditMemeModelFromJson(json); @override final String title; @@ -615,6 +671,28 @@ class _$RedditMemeModel extends RedditMemeModel { subreddit, ups, spoilersEnabled, nsfw); } + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult Function(String sourceLink, String imageLink, String title, + String author, List imagePreviews)? + $default, { + TResult Function( + String title, + String author, + @JsonKey(name: 'image_reviews') List imagePreviews, + @JsonKey(name: 'url') String imageLink, + @JsonKey(name: 'post_link') String sourceLink, + String subreddit, + int ups, + @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, + bool nsfw)? + reddit, + }) { + return reddit?.call(title, author, imagePreviews, imageLink, sourceLink, + subreddit, ups, spoilersEnabled, nsfw); + } + @override @optionalTypeArgs TResult maybeWhen( @@ -650,6 +728,15 @@ class _$RedditMemeModel extends RedditMemeModel { return reddit(this); } + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult Function(_AbstractMemeModel value)? $default, { + TResult Function(RedditMemeModel value)? reddit, + }) { + return reddit?.call(this); + } + @override @optionalTypeArgs TResult maybeMap( @@ -665,7 +752,7 @@ class _$RedditMemeModel extends RedditMemeModel { @override Map toJson() { - return _$_$RedditMemeModelToJson(this)..['runtimeType'] = 'reddit'; + return _$$RedditMemeModelToJson(this)..['runtimeType'] = 'reddit'; } } diff --git a/lib/domain/meme/abstract_meme_model.g.dart b/lib/domain/meme/abstract_meme_model.g.dart index 9a68473..95c4671 100644 --- a/lib/domain/meme/abstract_meme_model.g.dart +++ b/lib/domain/meme/abstract_meme_model.g.dart @@ -6,19 +6,18 @@ part of 'abstract_meme_model.dart'; // JsonSerializableGenerator // ************************************************************************** -_$_AbstractMemeModel _$_$_AbstractMemeModelFromJson(Map json) { - return _$_AbstractMemeModel( - sourceLink: json['sourceLink'] as String, - imageLink: json['imageLink'] as String, - title: json['title'] as String, - author: json['author'] as String, - imagePreviews: (json['imagePreviews'] as List) - .map((e) => e as String) - .toList(), - ); -} +_$_AbstractMemeModel _$$_AbstractMemeModelFromJson(Map json) => + _$_AbstractMemeModel( + sourceLink: json['sourceLink'] as String, + imageLink: json['imageLink'] as String, + title: json['title'] as String, + author: json['author'] as String, + imagePreviews: (json['imagePreviews'] as List) + .map((e) => e as String) + .toList(), + ); -Map _$_$_AbstractMemeModelToJson( +Map _$$_AbstractMemeModelToJson( _$_AbstractMemeModel instance) => { 'sourceLink': instance.sourceLink, @@ -28,23 +27,22 @@ Map _$_$_AbstractMemeModelToJson( 'imagePreviews': instance.imagePreviews, }; -_$RedditMemeModel _$_$RedditMemeModelFromJson(Map json) { - return _$RedditMemeModel( - title: json['title'] as String, - author: json['author'] as String, - imagePreviews: (json['image_reviews'] as List) - .map((e) => e as String) - .toList(), - imageLink: json['url'] as String, - sourceLink: json['post_link'] as String, - subreddit: json['subreddit'] as String, - ups: json['ups'] as int, - spoilersEnabled: json['spoilers_enabled'] as bool, - nsfw: json['nsfw'] as bool, - ); -} +_$RedditMemeModel _$$RedditMemeModelFromJson(Map json) => + _$RedditMemeModel( + title: json['title'] as String, + author: json['author'] as String, + imagePreviews: (json['image_reviews'] as List) + .map((e) => e as String) + .toList(), + imageLink: json['url'] as String, + sourceLink: json['post_link'] as String, + subreddit: json['subreddit'] as String, + ups: json['ups'] as int, + spoilersEnabled: json['spoilers_enabled'] as bool, + nsfw: json['nsfw'] as bool, + ); -Map _$_$RedditMemeModelToJson(_$RedditMemeModel instance) => +Map _$$RedditMemeModelToJson(_$RedditMemeModel instance) => { 'title': instance.title, 'author': instance.author, diff --git a/lib/infrastructure/api/reddit_api.dart b/lib/infrastructure/api/reddit/reddit_api.dart similarity index 85% rename from lib/infrastructure/api/reddit_api.dart rename to lib/infrastructure/api/reddit/reddit_api.dart index 3a5bec1..28864bd 100644 --- a/lib/infrastructure/api/reddit_api.dart +++ b/lib/infrastructure/api/reddit/reddit_api.dart @@ -1,6 +1,7 @@ import 'package:devour/domain/auth/reddit_account.dart'; import 'package:devour/domain/repositories/account_repository.dart'; -import 'package:devour/infrastructure/api/reddit_auth_api.dart'; +import 'package:devour/infrastructure/api/reddit/reddit_auth_api.dart'; +import 'package:devour/infrastructure/api/reddit/response/reddit_responses.dart'; import 'package:devour/infrastructure/register_module.dart'; import 'package:devour/injection.dart'; import 'package:dio/dio.dart'; @@ -16,7 +17,7 @@ abstract class RedditAPI { factory RedditAPI(@Named(kRedditDioName) Dio dio) = _RedditAPI; @GET('/r/memes') - Future getMemes(); + Future getMemes(); static Interceptor getAuthenticationTokenInterceptor() => AuthenticationTokenInterceptor(); diff --git a/lib/infrastructure/api/reddit_api.g.dart b/lib/infrastructure/api/reddit/reddit_api.g.dart similarity index 67% rename from lib/infrastructure/api/reddit_api.g.dart rename to lib/infrastructure/api/reddit/reddit_api.g.dart index d83d9c6..e5ac83f 100644 --- a/lib/infrastructure/api/reddit_api.g.dart +++ b/lib/infrastructure/api/reddit/reddit_api.g.dart @@ -16,16 +16,17 @@ class _RedditAPI implements RedditAPI { String? baseUrl; @override - Future getMemes() async { + Future> getMemes() async { const _extra = {}; final queryParameters = {}; final _data = {}; - final _result = await _dio.fetch(_setStreamType( - Options(method: 'GET', headers: {}, extra: _extra) - .compose(_dio.options, '/r/memes', - queryParameters: queryParameters, data: _data) - .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); - final value = _result.data; + final _result = await _dio.fetch>( + _setStreamType>( + Options(method: 'GET', headers: {}, extra: _extra) + .compose(_dio.options, '/r/memes', + queryParameters: queryParameters, data: _data) + .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); + final value = RedditResponse.fromJson(_result.data!); return value; } diff --git a/lib/infrastructure/api/reddit_auth_api.dart b/lib/infrastructure/api/reddit/reddit_auth_api.dart similarity index 85% rename from lib/infrastructure/api/reddit_auth_api.dart rename to lib/infrastructure/api/reddit/reddit_auth_api.dart index e484518..8d75471 100644 --- a/lib/infrastructure/api/reddit_auth_api.dart +++ b/lib/infrastructure/api/reddit/reddit_auth_api.dart @@ -1,16 +1,15 @@ import 'package:devour/domain/auth/reddit_account.dart'; import 'package:devour/domain/repositories/account_repository.dart'; +import 'package:devour/infrastructure/api/reddit/response/reddit_auth_response.dart'; import 'package:devour/infrastructure/core/env.dart'; import 'package:devour/infrastructure/core/misc.dart'; import 'package:devour/infrastructure/register_module.dart'; import 'package:devour/injection.dart'; import 'package:dio/dio.dart' hide Headers; -import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:injectable/injectable.dart'; import 'package:retrofit/retrofit.dart'; part 'reddit_auth_api.g.dart'; -part 'reddit_auth_api.freezed.dart'; const String _kBaseUrl = 'https://www.reddit.com/api/v1/'; const String kAccessTokenPath = '/access_token'; @@ -71,22 +70,6 @@ class RefreshTokenInterceptor extends Interceptor { } } -/// Authorization response data -@freezed -class AuthorizationResponse with _$AuthorizationResponse { - // ignore: public_member_api_docs - factory AuthorizationResponse({ - @JsonKey(name: 'access_token') required String accessToken, - @JsonKey(name: 'token_type') required String tokenType, - @JsonKey(name: 'expires_in') required int expiresIn, - @JsonKey(name: 'refresh_token') required String refreshToken, - @JsonKey(name: 'scope') required String scope, - }) = _AuthorizationResponse; - - factory AuthorizationResponse.fromJson(Map json) => - _$AuthorizationResponseFromJson(json); -} - /// Extension for authorization extension Authorize on RedditAuthAPI { Future refreshToken(RedditAccount account) => diff --git a/lib/infrastructure/api/reddit_auth_api.g.dart b/lib/infrastructure/api/reddit/reddit_auth_api.g.dart similarity index 68% rename from lib/infrastructure/api/reddit_auth_api.g.dart rename to lib/infrastructure/api/reddit/reddit_auth_api.g.dart index 694ceff..ff78afe 100644 --- a/lib/infrastructure/api/reddit_auth_api.g.dart +++ b/lib/infrastructure/api/reddit/reddit_auth_api.g.dart @@ -2,31 +2,6 @@ part of 'reddit_auth_api.dart'; -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$_AuthorizationResponse _$_$_AuthorizationResponseFromJson( - Map json) { - return _$_AuthorizationResponse( - accessToken: json['access_token'] as String, - tokenType: json['token_type'] as String, - expiresIn: json['expires_in'] as int, - refreshToken: json['refresh_token'] as String, - scope: json['scope'] as String, - ); -} - -Map _$_$_AuthorizationResponseToJson( - _$_AuthorizationResponse instance) => - { - 'access_token': instance.accessToken, - 'token_type': instance.tokenType, - 'expires_in': instance.expiresIn, - 'refresh_token': instance.refreshToken, - 'scope': instance.scope, - }; - // ************************************************************************** // RetrofitGenerator // ************************************************************************** diff --git a/lib/infrastructure/api/reddit/response/reddit_auth_response.dart b/lib/infrastructure/api/reddit/response/reddit_auth_response.dart new file mode 100644 index 0000000..bb5ee01 --- /dev/null +++ b/lib/infrastructure/api/reddit/response/reddit_auth_response.dart @@ -0,0 +1,20 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'reddit_auth_response.g.dart'; +part 'reddit_auth_response.freezed.dart'; + +/// Authorization response data +@freezed +class AuthorizationResponse with _$AuthorizationResponse { + // ignore: public_member_api_docs + factory AuthorizationResponse({ + @JsonKey(name: 'access_token') required String accessToken, + @JsonKey(name: 'token_type') required String tokenType, + @JsonKey(name: 'expires_in') required int expiresIn, + @JsonKey(name: 'refresh_token') required String refreshToken, + @JsonKey(name: 'scope') required String scope, + }) = _AuthorizationResponse; + + factory AuthorizationResponse.fromJson(Map json) => + _$AuthorizationResponseFromJson(json); +} diff --git a/lib/infrastructure/api/reddit_auth_api.freezed.dart b/lib/infrastructure/api/reddit/response/reddit_auth_response.freezed.dart similarity index 97% rename from lib/infrastructure/api/reddit_auth_api.freezed.dart rename to lib/infrastructure/api/reddit/response/reddit_auth_response.freezed.dart index f2f5cfe..091ef72 100644 --- a/lib/infrastructure/api/reddit_auth_api.freezed.dart +++ b/lib/infrastructure/api/reddit/response/reddit_auth_response.freezed.dart @@ -1,7 +1,8 @@ +// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target -part of 'reddit_auth_api.dart'; +part of 'reddit_auth_response.dart'; // ************************************************************************** // FreezedGenerator @@ -188,7 +189,7 @@ class _$_AuthorizationResponse implements _AuthorizationResponse { @JsonKey(name: 'scope') required this.scope}); factory _$_AuthorizationResponse.fromJson(Map json) => - _$_$_AuthorizationResponseFromJson(json); + _$$_AuthorizationResponseFromJson(json); @override @JsonKey(name: 'access_token') @@ -248,7 +249,7 @@ class _$_AuthorizationResponse implements _AuthorizationResponse { @override Map toJson() { - return _$_$_AuthorizationResponseToJson(this); + return _$$_AuthorizationResponseToJson(this); } } diff --git a/lib/infrastructure/api/reddit/response/reddit_auth_response.g.dart b/lib/infrastructure/api/reddit/response/reddit_auth_response.g.dart new file mode 100644 index 0000000..81cd667 --- /dev/null +++ b/lib/infrastructure/api/reddit/response/reddit_auth_response.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'reddit_auth_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_AuthorizationResponse _$$_AuthorizationResponseFromJson( + Map json) => + _$_AuthorizationResponse( + accessToken: json['access_token'] as String, + tokenType: json['token_type'] as String, + expiresIn: json['expires_in'] as int, + refreshToken: json['refresh_token'] as String, + scope: json['scope'] as String, + ); + +Map _$$_AuthorizationResponseToJson( + _$_AuthorizationResponse instance) => + { + 'access_token': instance.accessToken, + 'token_type': instance.tokenType, + 'expires_in': instance.expiresIn, + 'refresh_token': instance.refreshToken, + 'scope': instance.scope, + }; diff --git a/lib/infrastructure/api/reddit/response/reddit_responses.dart b/lib/infrastructure/api/reddit/response/reddit_responses.dart new file mode 100644 index 0000000..bf7dcfe --- /dev/null +++ b/lib/infrastructure/api/reddit/response/reddit_responses.dart @@ -0,0 +1,80 @@ +import 'package:devour/infrastructure/core/misc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'reddit_responses.g.dart'; +part 'reddit_responses.freezed.dart'; + +@freezed +class RedditResponse with _$RedditResponse { + const factory RedditResponse({ + required String kind, + @RRDataConverter() required T data, + }) = _RedditResponse; + + factory RedditResponse.fromJson(Map json) => + _$RedditResponseFromJson(json); +} + +@freezed +class RedditListingResponse with _$RedditListingResponse { + factory RedditListingResponse({ + @JsonKey(name: 'after') required String after, // "t3_plk79v" + @JsonKey(name: 'dist') required int dist, // 27 + @JsonKey(name: 'modhash') String? modhash, // null + @JsonKey(name: 'geo_filter') Object? geo_filter, // null + @JsonKey(name: 'children') + @RRDataConverter() + required List children, // List (27 items) + @JsonKey(name: 'before') String? before, // null + }) = _RedditListingResponse; + + factory RedditListingResponse.fromJson(Map json) => + _$RedditListingResponseFromJson(json); +} + +@freezed +class RedditPostResponse with _$RedditPostResponse { + factory RedditPostResponse({ + @JsonKey(name: 'subreddit') required String subreddit, + @JsonKey(name: 'author') required String author, + @JsonKey(name: 'title') required String title, + @JsonKey(name: 'upvote_ratio') required double upvoteRatio, + @JsonKey(name: 'ups') required int ups, + @JsonKey(name: 'num_comments') required int numComments, + @JsonKey(name: 'stickied') required bool stickied, // is 'pinned' + @JsonKey(name: 'created_utc') required double createdUtc, + @JsonKey(name: 'is_video') required bool isVide, + @JsonKey(name: 'url') required String url, + @JsonKey(name: 'over_18') required bool over18, + }) = _RedditPostResponse; + + factory RedditPostResponse.fromJson(Map json) => + _$RedditPostResponseFromJson(json); +} + +class RRDataConverter implements JsonConverter { + const RRDataConverter(); + + @override + T fromJson(Object json) { + final data = json as Map; + + if (data.containsKey('after')) { + // The 'after' key is Listing feature + return RedditListingResponse.fromJson(data) as T; + } else if (data['kind'] == 't3') { + // By reddit API documentation, 't3' is a Link, and requrests to subbreddit + // listing contains 't3' objects. Maybe its can be something elese, not only + // reddit post. + return RedditPostResponse.fromJson(data['data'] as Map) + as T; + } else { + throw UnimplementedError('Cant convert this json'); + } + } + + @override + Object toJson(T object) { + throw UnimplementedError('Dont supose to convert into json'); + } +} diff --git a/lib/infrastructure/api/reddit/response/reddit_responses.freezed.dart b/lib/infrastructure/api/reddit/response/reddit_responses.freezed.dart new file mode 100644 index 0000000..20c0f4d --- /dev/null +++ b/lib/infrastructure/api/reddit/response/reddit_responses.freezed.dart @@ -0,0 +1,919 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target + +part of 'reddit_responses.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +RedditResponse _$RedditResponseFromJson(Map json) { + return _RedditResponse.fromJson(json); +} + +/// @nodoc +class _$RedditResponseTearOff { + const _$RedditResponseTearOff(); + + _RedditResponse call( + {required String kind, @RRDataConverter() required T data}) { + return _RedditResponse( + kind: kind, + data: data, + ); + } + + RedditResponse fromJson(Map json) { + return RedditResponse.fromJson(json); + } +} + +/// @nodoc +const $RedditResponse = _$RedditResponseTearOff(); + +/// @nodoc +mixin _$RedditResponse { + String get kind => throw _privateConstructorUsedError; + @RRDataConverter() + T get data => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $RedditResponseCopyWith> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $RedditResponseCopyWith { + factory $RedditResponseCopyWith( + RedditResponse value, $Res Function(RedditResponse) then) = + _$RedditResponseCopyWithImpl; + $Res call({String kind, @RRDataConverter() T data}); +} + +/// @nodoc +class _$RedditResponseCopyWithImpl + implements $RedditResponseCopyWith { + _$RedditResponseCopyWithImpl(this._value, this._then); + + final RedditResponse _value; + // ignore: unused_field + final $Res Function(RedditResponse) _then; + + @override + $Res call({ + Object? kind = freezed, + Object? data = freezed, + }) { + return _then(_value.copyWith( + kind: kind == freezed + ? _value.kind + : kind // ignore: cast_nullable_to_non_nullable + as String, + data: data == freezed + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as T, + )); + } +} + +/// @nodoc +abstract class _$RedditResponseCopyWith + implements $RedditResponseCopyWith { + factory _$RedditResponseCopyWith( + _RedditResponse value, $Res Function(_RedditResponse) then) = + __$RedditResponseCopyWithImpl; + @override + $Res call({String kind, @RRDataConverter() T data}); +} + +/// @nodoc +class __$RedditResponseCopyWithImpl + extends _$RedditResponseCopyWithImpl + implements _$RedditResponseCopyWith { + __$RedditResponseCopyWithImpl( + _RedditResponse _value, $Res Function(_RedditResponse) _then) + : super(_value, (v) => _then(v as _RedditResponse)); + + @override + _RedditResponse get _value => super._value as _RedditResponse; + + @override + $Res call({ + Object? kind = freezed, + Object? data = freezed, + }) { + return _then(_RedditResponse( + kind: kind == freezed + ? _value.kind + : kind // ignore: cast_nullable_to_non_nullable + as String, + data: data == freezed + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as T, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_RedditResponse implements _RedditResponse { + const _$_RedditResponse( + {required this.kind, @RRDataConverter() required this.data}); + + factory _$_RedditResponse.fromJson(Map json) => + _$$_RedditResponseFromJson(json); + + @override + final String kind; + @override + @RRDataConverter() + final T data; + + @override + String toString() { + return 'RedditResponse<$T>(kind: $kind, data: $data)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _RedditResponse && + (identical(other.kind, kind) || + const DeepCollectionEquality().equals(other.kind, kind)) && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(kind) ^ + const DeepCollectionEquality().hash(data); + + @JsonKey(ignore: true) + @override + _$RedditResponseCopyWith> get copyWith => + __$RedditResponseCopyWithImpl>(this, _$identity); + + @override + Map toJson() { + return _$$_RedditResponseToJson(this); + } +} + +abstract class _RedditResponse implements RedditResponse { + const factory _RedditResponse( + {required String kind, + @RRDataConverter() required T data}) = _$_RedditResponse; + + factory _RedditResponse.fromJson(Map json) = + _$_RedditResponse.fromJson; + + @override + String get kind => throw _privateConstructorUsedError; + @override + @RRDataConverter() + T get data => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$RedditResponseCopyWith> get copyWith => + throw _privateConstructorUsedError; +} + +RedditListingResponse _$RedditListingResponseFromJson( + Map json) { + return _RedditListingResponse.fromJson(json); +} + +/// @nodoc +class _$RedditListingResponseTearOff { + const _$RedditListingResponseTearOff(); + + _RedditListingResponse call( + {@JsonKey(name: 'after') required String after, + @JsonKey(name: 'dist') required int dist, + @JsonKey(name: 'modhash') String? modhash, + @JsonKey(name: 'geo_filter') Object? geo_filter, + @JsonKey(name: 'children') @RRDataConverter() required List children, + @JsonKey(name: 'before') String? before}) { + return _RedditListingResponse( + after: after, + dist: dist, + modhash: modhash, + geo_filter: geo_filter, + children: children, + before: before, + ); + } + + RedditListingResponse fromJson(Map json) { + return RedditListingResponse.fromJson(json); + } +} + +/// @nodoc +const $RedditListingResponse = _$RedditListingResponseTearOff(); + +/// @nodoc +mixin _$RedditListingResponse { + @JsonKey(name: 'after') + String get after => throw _privateConstructorUsedError; // "t3_plk79v" + @JsonKey(name: 'dist') + int get dist => throw _privateConstructorUsedError; // 27 + @JsonKey(name: 'modhash') + String? get modhash => throw _privateConstructorUsedError; // null + @JsonKey(name: 'geo_filter') + Object? get geo_filter => throw _privateConstructorUsedError; // null + @JsonKey(name: 'children') + @RRDataConverter() + List get children => throw _privateConstructorUsedError; // List (27 items) + @JsonKey(name: 'before') + String? get before => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $RedditListingResponseCopyWith> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $RedditListingResponseCopyWith { + factory $RedditListingResponseCopyWith(RedditListingResponse value, + $Res Function(RedditListingResponse) then) = + _$RedditListingResponseCopyWithImpl; + $Res call( + {@JsonKey(name: 'after') String after, + @JsonKey(name: 'dist') int dist, + @JsonKey(name: 'modhash') String? modhash, + @JsonKey(name: 'geo_filter') Object? geo_filter, + @JsonKey(name: 'children') @RRDataConverter() List children, + @JsonKey(name: 'before') String? before}); +} + +/// @nodoc +class _$RedditListingResponseCopyWithImpl + implements $RedditListingResponseCopyWith { + _$RedditListingResponseCopyWithImpl(this._value, this._then); + + final RedditListingResponse _value; + // ignore: unused_field + final $Res Function(RedditListingResponse) _then; + + @override + $Res call({ + Object? after = freezed, + Object? dist = freezed, + Object? modhash = freezed, + Object? geo_filter = freezed, + Object? children = freezed, + Object? before = freezed, + }) { + return _then(_value.copyWith( + after: after == freezed + ? _value.after + : after // ignore: cast_nullable_to_non_nullable + as String, + dist: dist == freezed + ? _value.dist + : dist // ignore: cast_nullable_to_non_nullable + as int, + modhash: modhash == freezed + ? _value.modhash + : modhash // ignore: cast_nullable_to_non_nullable + as String?, + geo_filter: geo_filter == freezed ? _value.geo_filter : geo_filter, + children: children == freezed + ? _value.children + : children // ignore: cast_nullable_to_non_nullable + as List, + before: before == freezed + ? _value.before + : before // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +abstract class _$RedditListingResponseCopyWith + implements $RedditListingResponseCopyWith { + factory _$RedditListingResponseCopyWith(_RedditListingResponse value, + $Res Function(_RedditListingResponse) then) = + __$RedditListingResponseCopyWithImpl; + @override + $Res call( + {@JsonKey(name: 'after') String after, + @JsonKey(name: 'dist') int dist, + @JsonKey(name: 'modhash') String? modhash, + @JsonKey(name: 'geo_filter') Object? geo_filter, + @JsonKey(name: 'children') @RRDataConverter() List children, + @JsonKey(name: 'before') String? before}); +} + +/// @nodoc +class __$RedditListingResponseCopyWithImpl + extends _$RedditListingResponseCopyWithImpl + implements _$RedditListingResponseCopyWith { + __$RedditListingResponseCopyWithImpl(_RedditListingResponse _value, + $Res Function(_RedditListingResponse) _then) + : super(_value, (v) => _then(v as _RedditListingResponse)); + + @override + _RedditListingResponse get _value => + super._value as _RedditListingResponse; + + @override + $Res call({ + Object? after = freezed, + Object? dist = freezed, + Object? modhash = freezed, + Object? geo_filter = freezed, + Object? children = freezed, + Object? before = freezed, + }) { + return _then(_RedditListingResponse( + after: after == freezed + ? _value.after + : after // ignore: cast_nullable_to_non_nullable + as String, + dist: dist == freezed + ? _value.dist + : dist // ignore: cast_nullable_to_non_nullable + as int, + modhash: modhash == freezed + ? _value.modhash + : modhash // ignore: cast_nullable_to_non_nullable + as String?, + geo_filter: geo_filter == freezed ? _value.geo_filter : geo_filter, + children: children == freezed + ? _value.children + : children // ignore: cast_nullable_to_non_nullable + as List, + before: before == freezed + ? _value.before + : before // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_RedditListingResponse implements _RedditListingResponse { + _$_RedditListingResponse( + {@JsonKey(name: 'after') required this.after, + @JsonKey(name: 'dist') required this.dist, + @JsonKey(name: 'modhash') this.modhash, + @JsonKey(name: 'geo_filter') this.geo_filter, + @JsonKey(name: 'children') @RRDataConverter() required this.children, + @JsonKey(name: 'before') this.before}); + + factory _$_RedditListingResponse.fromJson(Map json) => + _$$_RedditListingResponseFromJson(json); + + @override + @JsonKey(name: 'after') + final String after; + @override // "t3_plk79v" + @JsonKey(name: 'dist') + final int dist; + @override // 27 + @JsonKey(name: 'modhash') + final String? modhash; + @override // null + @JsonKey(name: 'geo_filter') + final Object? geo_filter; + @override // null + @JsonKey(name: 'children') + @RRDataConverter() + final List children; + @override // List (27 items) + @JsonKey(name: 'before') + final String? before; + + @override + String toString() { + return 'RedditListingResponse<$T>(after: $after, dist: $dist, modhash: $modhash, geo_filter: $geo_filter, children: $children, before: $before)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _RedditListingResponse && + (identical(other.after, after) || + const DeepCollectionEquality().equals(other.after, after)) && + (identical(other.dist, dist) || + const DeepCollectionEquality().equals(other.dist, dist)) && + (identical(other.modhash, modhash) || + const DeepCollectionEquality() + .equals(other.modhash, modhash)) && + (identical(other.geo_filter, geo_filter) || + const DeepCollectionEquality() + .equals(other.geo_filter, geo_filter)) && + (identical(other.children, children) || + const DeepCollectionEquality() + .equals(other.children, children)) && + (identical(other.before, before) || + const DeepCollectionEquality().equals(other.before, before))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(after) ^ + const DeepCollectionEquality().hash(dist) ^ + const DeepCollectionEquality().hash(modhash) ^ + const DeepCollectionEquality().hash(geo_filter) ^ + const DeepCollectionEquality().hash(children) ^ + const DeepCollectionEquality().hash(before); + + @JsonKey(ignore: true) + @override + _$RedditListingResponseCopyWith> get copyWith => + __$RedditListingResponseCopyWithImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$_RedditListingResponseToJson(this); + } +} + +abstract class _RedditListingResponse implements RedditListingResponse { + factory _RedditListingResponse( + {@JsonKey(name: 'after') required String after, + @JsonKey(name: 'dist') required int dist, + @JsonKey(name: 'modhash') String? modhash, + @JsonKey(name: 'geo_filter') Object? geo_filter, + @JsonKey(name: 'children') @RRDataConverter() required List children, + @JsonKey(name: 'before') String? before}) = _$_RedditListingResponse; + + factory _RedditListingResponse.fromJson(Map json) = + _$_RedditListingResponse.fromJson; + + @override + @JsonKey(name: 'after') + String get after => throw _privateConstructorUsedError; + @override // "t3_plk79v" + @JsonKey(name: 'dist') + int get dist => throw _privateConstructorUsedError; + @override // 27 + @JsonKey(name: 'modhash') + String? get modhash => throw _privateConstructorUsedError; + @override // null + @JsonKey(name: 'geo_filter') + Object? get geo_filter => throw _privateConstructorUsedError; + @override // null + @JsonKey(name: 'children') + @RRDataConverter() + List get children => throw _privateConstructorUsedError; + @override // List (27 items) + @JsonKey(name: 'before') + String? get before => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$RedditListingResponseCopyWith> get copyWith => + throw _privateConstructorUsedError; +} + +RedditPostResponse _$RedditPostResponseFromJson(Map json) { + return _RedditPostResponse.fromJson(json); +} + +/// @nodoc +class _$RedditPostResponseTearOff { + const _$RedditPostResponseTearOff(); + + _RedditPostResponse call( + {@JsonKey(name: 'subreddit') required String subreddit, + @JsonKey(name: 'author') required String author, + @JsonKey(name: 'title') required String title, + @JsonKey(name: 'upvote_ratio') required double upvoteRatio, + @JsonKey(name: 'ups') required int ups, + @JsonKey(name: 'num_comments') required int numComments, + @JsonKey(name: 'stickied') required bool stickied, + @JsonKey(name: 'created_utc') required double createdUtc, + @JsonKey(name: 'is_video') required bool isVide, + @JsonKey(name: 'url') required String url, + @JsonKey(name: 'over_18') required bool over18}) { + return _RedditPostResponse( + subreddit: subreddit, + author: author, + title: title, + upvoteRatio: upvoteRatio, + ups: ups, + numComments: numComments, + stickied: stickied, + createdUtc: createdUtc, + isVide: isVide, + url: url, + over18: over18, + ); + } + + RedditPostResponse fromJson(Map json) { + return RedditPostResponse.fromJson(json); + } +} + +/// @nodoc +const $RedditPostResponse = _$RedditPostResponseTearOff(); + +/// @nodoc +mixin _$RedditPostResponse { + @JsonKey(name: 'subreddit') + String get subreddit => throw _privateConstructorUsedError; + @JsonKey(name: 'author') + String get author => throw _privateConstructorUsedError; + @JsonKey(name: 'title') + String get title => throw _privateConstructorUsedError; + @JsonKey(name: 'upvote_ratio') + double get upvoteRatio => throw _privateConstructorUsedError; + @JsonKey(name: 'ups') + int get ups => throw _privateConstructorUsedError; + @JsonKey(name: 'num_comments') + int get numComments => throw _privateConstructorUsedError; + @JsonKey(name: 'stickied') + bool get stickied => throw _privateConstructorUsedError; // is 'pinned' + @JsonKey(name: 'created_utc') + double get createdUtc => throw _privateConstructorUsedError; + @JsonKey(name: 'is_video') + bool get isVide => throw _privateConstructorUsedError; + @JsonKey(name: 'url') + String get url => throw _privateConstructorUsedError; + @JsonKey(name: 'over_18') + bool get over18 => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $RedditPostResponseCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $RedditPostResponseCopyWith<$Res> { + factory $RedditPostResponseCopyWith( + RedditPostResponse value, $Res Function(RedditPostResponse) then) = + _$RedditPostResponseCopyWithImpl<$Res>; + $Res call( + {@JsonKey(name: 'subreddit') String subreddit, + @JsonKey(name: 'author') String author, + @JsonKey(name: 'title') String title, + @JsonKey(name: 'upvote_ratio') double upvoteRatio, + @JsonKey(name: 'ups') int ups, + @JsonKey(name: 'num_comments') int numComments, + @JsonKey(name: 'stickied') bool stickied, + @JsonKey(name: 'created_utc') double createdUtc, + @JsonKey(name: 'is_video') bool isVide, + @JsonKey(name: 'url') String url, + @JsonKey(name: 'over_18') bool over18}); +} + +/// @nodoc +class _$RedditPostResponseCopyWithImpl<$Res> + implements $RedditPostResponseCopyWith<$Res> { + _$RedditPostResponseCopyWithImpl(this._value, this._then); + + final RedditPostResponse _value; + // ignore: unused_field + final $Res Function(RedditPostResponse) _then; + + @override + $Res call({ + Object? subreddit = freezed, + Object? author = freezed, + Object? title = freezed, + Object? upvoteRatio = freezed, + Object? ups = freezed, + Object? numComments = freezed, + Object? stickied = freezed, + Object? createdUtc = freezed, + Object? isVide = freezed, + Object? url = freezed, + Object? over18 = freezed, + }) { + return _then(_value.copyWith( + subreddit: subreddit == freezed + ? _value.subreddit + : subreddit // ignore: cast_nullable_to_non_nullable + as String, + author: author == freezed + ? _value.author + : author // ignore: cast_nullable_to_non_nullable + as String, + title: title == freezed + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + upvoteRatio: upvoteRatio == freezed + ? _value.upvoteRatio + : upvoteRatio // ignore: cast_nullable_to_non_nullable + as double, + ups: ups == freezed + ? _value.ups + : ups // ignore: cast_nullable_to_non_nullable + as int, + numComments: numComments == freezed + ? _value.numComments + : numComments // ignore: cast_nullable_to_non_nullable + as int, + stickied: stickied == freezed + ? _value.stickied + : stickied // ignore: cast_nullable_to_non_nullable + as bool, + createdUtc: createdUtc == freezed + ? _value.createdUtc + : createdUtc // ignore: cast_nullable_to_non_nullable + as double, + isVide: isVide == freezed + ? _value.isVide + : isVide // ignore: cast_nullable_to_non_nullable + as bool, + url: url == freezed + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String, + over18: over18 == freezed + ? _value.over18 + : over18 // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +abstract class _$RedditPostResponseCopyWith<$Res> + implements $RedditPostResponseCopyWith<$Res> { + factory _$RedditPostResponseCopyWith( + _RedditPostResponse value, $Res Function(_RedditPostResponse) then) = + __$RedditPostResponseCopyWithImpl<$Res>; + @override + $Res call( + {@JsonKey(name: 'subreddit') String subreddit, + @JsonKey(name: 'author') String author, + @JsonKey(name: 'title') String title, + @JsonKey(name: 'upvote_ratio') double upvoteRatio, + @JsonKey(name: 'ups') int ups, + @JsonKey(name: 'num_comments') int numComments, + @JsonKey(name: 'stickied') bool stickied, + @JsonKey(name: 'created_utc') double createdUtc, + @JsonKey(name: 'is_video') bool isVide, + @JsonKey(name: 'url') String url, + @JsonKey(name: 'over_18') bool over18}); +} + +/// @nodoc +class __$RedditPostResponseCopyWithImpl<$Res> + extends _$RedditPostResponseCopyWithImpl<$Res> + implements _$RedditPostResponseCopyWith<$Res> { + __$RedditPostResponseCopyWithImpl( + _RedditPostResponse _value, $Res Function(_RedditPostResponse) _then) + : super(_value, (v) => _then(v as _RedditPostResponse)); + + @override + _RedditPostResponse get _value => super._value as _RedditPostResponse; + + @override + $Res call({ + Object? subreddit = freezed, + Object? author = freezed, + Object? title = freezed, + Object? upvoteRatio = freezed, + Object? ups = freezed, + Object? numComments = freezed, + Object? stickied = freezed, + Object? createdUtc = freezed, + Object? isVide = freezed, + Object? url = freezed, + Object? over18 = freezed, + }) { + return _then(_RedditPostResponse( + subreddit: subreddit == freezed + ? _value.subreddit + : subreddit // ignore: cast_nullable_to_non_nullable + as String, + author: author == freezed + ? _value.author + : author // ignore: cast_nullable_to_non_nullable + as String, + title: title == freezed + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + upvoteRatio: upvoteRatio == freezed + ? _value.upvoteRatio + : upvoteRatio // ignore: cast_nullable_to_non_nullable + as double, + ups: ups == freezed + ? _value.ups + : ups // ignore: cast_nullable_to_non_nullable + as int, + numComments: numComments == freezed + ? _value.numComments + : numComments // ignore: cast_nullable_to_non_nullable + as int, + stickied: stickied == freezed + ? _value.stickied + : stickied // ignore: cast_nullable_to_non_nullable + as bool, + createdUtc: createdUtc == freezed + ? _value.createdUtc + : createdUtc // ignore: cast_nullable_to_non_nullable + as double, + isVide: isVide == freezed + ? _value.isVide + : isVide // ignore: cast_nullable_to_non_nullable + as bool, + url: url == freezed + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String, + over18: over18 == freezed + ? _value.over18 + : over18 // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_RedditPostResponse implements _RedditPostResponse { + _$_RedditPostResponse( + {@JsonKey(name: 'subreddit') required this.subreddit, + @JsonKey(name: 'author') required this.author, + @JsonKey(name: 'title') required this.title, + @JsonKey(name: 'upvote_ratio') required this.upvoteRatio, + @JsonKey(name: 'ups') required this.ups, + @JsonKey(name: 'num_comments') required this.numComments, + @JsonKey(name: 'stickied') required this.stickied, + @JsonKey(name: 'created_utc') required this.createdUtc, + @JsonKey(name: 'is_video') required this.isVide, + @JsonKey(name: 'url') required this.url, + @JsonKey(name: 'over_18') required this.over18}); + + factory _$_RedditPostResponse.fromJson(Map json) => + _$$_RedditPostResponseFromJson(json); + + @override + @JsonKey(name: 'subreddit') + final String subreddit; + @override + @JsonKey(name: 'author') + final String author; + @override + @JsonKey(name: 'title') + final String title; + @override + @JsonKey(name: 'upvote_ratio') + final double upvoteRatio; + @override + @JsonKey(name: 'ups') + final int ups; + @override + @JsonKey(name: 'num_comments') + final int numComments; + @override + @JsonKey(name: 'stickied') + final bool stickied; + @override // is 'pinned' + @JsonKey(name: 'created_utc') + final double createdUtc; + @override + @JsonKey(name: 'is_video') + final bool isVide; + @override + @JsonKey(name: 'url') + final String url; + @override + @JsonKey(name: 'over_18') + final bool over18; + + @override + String toString() { + return 'RedditPostResponse(subreddit: $subreddit, author: $author, title: $title, upvoteRatio: $upvoteRatio, ups: $ups, numComments: $numComments, stickied: $stickied, createdUtc: $createdUtc, isVide: $isVide, url: $url, over18: $over18)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is _RedditPostResponse && + (identical(other.subreddit, subreddit) || + const DeepCollectionEquality() + .equals(other.subreddit, subreddit)) && + (identical(other.author, author) || + const DeepCollectionEquality().equals(other.author, author)) && + (identical(other.title, title) || + const DeepCollectionEquality().equals(other.title, title)) && + (identical(other.upvoteRatio, upvoteRatio) || + const DeepCollectionEquality() + .equals(other.upvoteRatio, upvoteRatio)) && + (identical(other.ups, ups) || + const DeepCollectionEquality().equals(other.ups, ups)) && + (identical(other.numComments, numComments) || + const DeepCollectionEquality() + .equals(other.numComments, numComments)) && + (identical(other.stickied, stickied) || + const DeepCollectionEquality() + .equals(other.stickied, stickied)) && + (identical(other.createdUtc, createdUtc) || + const DeepCollectionEquality() + .equals(other.createdUtc, createdUtc)) && + (identical(other.isVide, isVide) || + const DeepCollectionEquality().equals(other.isVide, isVide)) && + (identical(other.url, url) || + const DeepCollectionEquality().equals(other.url, url)) && + (identical(other.over18, over18) || + const DeepCollectionEquality().equals(other.over18, over18))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(subreddit) ^ + const DeepCollectionEquality().hash(author) ^ + const DeepCollectionEquality().hash(title) ^ + const DeepCollectionEquality().hash(upvoteRatio) ^ + const DeepCollectionEquality().hash(ups) ^ + const DeepCollectionEquality().hash(numComments) ^ + const DeepCollectionEquality().hash(stickied) ^ + const DeepCollectionEquality().hash(createdUtc) ^ + const DeepCollectionEquality().hash(isVide) ^ + const DeepCollectionEquality().hash(url) ^ + const DeepCollectionEquality().hash(over18); + + @JsonKey(ignore: true) + @override + _$RedditPostResponseCopyWith<_RedditPostResponse> get copyWith => + __$RedditPostResponseCopyWithImpl<_RedditPostResponse>(this, _$identity); + + @override + Map toJson() { + return _$$_RedditPostResponseToJson(this); + } +} + +abstract class _RedditPostResponse implements RedditPostResponse { + factory _RedditPostResponse( + {@JsonKey(name: 'subreddit') required String subreddit, + @JsonKey(name: 'author') required String author, + @JsonKey(name: 'title') required String title, + @JsonKey(name: 'upvote_ratio') required double upvoteRatio, + @JsonKey(name: 'ups') required int ups, + @JsonKey(name: 'num_comments') required int numComments, + @JsonKey(name: 'stickied') required bool stickied, + @JsonKey(name: 'created_utc') required double createdUtc, + @JsonKey(name: 'is_video') required bool isVide, + @JsonKey(name: 'url') required String url, + @JsonKey(name: 'over_18') required bool over18}) = _$_RedditPostResponse; + + factory _RedditPostResponse.fromJson(Map json) = + _$_RedditPostResponse.fromJson; + + @override + @JsonKey(name: 'subreddit') + String get subreddit => throw _privateConstructorUsedError; + @override + @JsonKey(name: 'author') + String get author => throw _privateConstructorUsedError; + @override + @JsonKey(name: 'title') + String get title => throw _privateConstructorUsedError; + @override + @JsonKey(name: 'upvote_ratio') + double get upvoteRatio => throw _privateConstructorUsedError; + @override + @JsonKey(name: 'ups') + int get ups => throw _privateConstructorUsedError; + @override + @JsonKey(name: 'num_comments') + int get numComments => throw _privateConstructorUsedError; + @override + @JsonKey(name: 'stickied') + bool get stickied => throw _privateConstructorUsedError; + @override // is 'pinned' + @JsonKey(name: 'created_utc') + double get createdUtc => throw _privateConstructorUsedError; + @override + @JsonKey(name: 'is_video') + bool get isVide => throw _privateConstructorUsedError; + @override + @JsonKey(name: 'url') + String get url => throw _privateConstructorUsedError; + @override + @JsonKey(name: 'over_18') + bool get over18 => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$RedditPostResponseCopyWith<_RedditPostResponse> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/infrastructure/api/reddit/response/reddit_responses.g.dart b/lib/infrastructure/api/reddit/response/reddit_responses.g.dart new file mode 100644 index 0000000..c8279b3 --- /dev/null +++ b/lib/infrastructure/api/reddit/response/reddit_responses.g.dart @@ -0,0 +1,76 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'reddit_responses.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_RedditResponse _$$_RedditResponseFromJson(Map json) => + _$_RedditResponse( + kind: json['kind'] as String, + data: RRDataConverter().fromJson(json['data'] as Object), + ); + +Map _$$_RedditResponseToJson( + _$_RedditResponse instance) => + { + 'kind': instance.kind, + 'data': RRDataConverter().toJson(instance.data), + }; + +_$_RedditListingResponse _$$_RedditListingResponseFromJson( + Map json) => + _$_RedditListingResponse( + after: json['after'] as String, + dist: json['dist'] as int, + modhash: json['modhash'] as String?, + geo_filter: json['geo_filter'], + children: (json['children'] as List) + .map((e) => RRDataConverter().fromJson(e as Object)) + .toList(), + before: json['before'] as String?, + ); + +Map _$$_RedditListingResponseToJson( + _$_RedditListingResponse instance) => + { + 'after': instance.after, + 'dist': instance.dist, + 'modhash': instance.modhash, + 'geo_filter': instance.geo_filter, + 'children': instance.children.map(RRDataConverter().toJson).toList(), + 'before': instance.before, + }; + +_$_RedditPostResponse _$$_RedditPostResponseFromJson( + Map json) => + _$_RedditPostResponse( + subreddit: json['subreddit'] as String, + author: json['author'] as String, + title: json['title'] as String, + upvoteRatio: (json['upvote_ratio'] as num).toDouble(), + ups: json['ups'] as int, + numComments: json['num_comments'] as int, + stickied: json['stickied'] as bool, + createdUtc: (json['created_utc'] as num).toDouble(), + isVide: json['is_video'] as bool, + url: json['url'] as String, + over18: json['over_18'] as bool, + ); + +Map _$$_RedditPostResponseToJson( + _$_RedditPostResponse instance) => + { + 'subreddit': instance.subreddit, + 'author': instance.author, + 'title': instance.title, + 'upvote_ratio': instance.upvoteRatio, + 'ups': instance.ups, + 'num_comments': instance.numComments, + 'stickied': instance.stickied, + 'created_utc': instance.createdUtc, + 'is_video': instance.isVide, + 'url': instance.url, + 'over_18': instance.over18, + }; diff --git a/lib/infrastructure/core/misc.dart b/lib/infrastructure/core/misc.dart index 16651f8..d135c3a 100644 --- a/lib/infrastructure/core/misc.dart +++ b/lib/infrastructure/core/misc.dart @@ -12,5 +12,10 @@ String getRandomString(int len) { /// Return Type of T Type typeOf() => T; +class _IsSubtypeHelper {} + +// T is not T, so use this helper to check subtypes +bool isSubtype() => _IsSubtypeHelper() is _IsSubtypeHelper; + String getBasicCredentials(String username, String password) => 'Basic ${base64Encode(utf8.encode('$username:$password'))}'; diff --git a/lib/injection.config.dart b/lib/injection.config.dart index 021b857..6351279 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -4,27 +4,26 @@ // InjectableConfigGenerator // ************************************************************************** -import 'package:devour/application/accounts/bloc/accounts_bloc.dart' as _i9; -import 'package:devour/application/auth/login/login_bloc.dart' as _i6; -import 'package:devour/application/feed/bloc/feed_bloc.dart' as _i7; +import 'package:devour/application/accounts/bloc/accounts_bloc.dart' as _i18; +import 'package:devour/application/auth/login/login_bloc.dart' as _i12; +import 'package:devour/application/feed/bloc/feed_bloc.dart' as _i17; import 'package:devour/application/navigator/app_navigator.dart' as _i3; -import 'package:devour/domain/auth/i_auth_facade.dart' as _i4; +import 'package:devour/domain/auth/i_auth_facade.dart' as _i5; import 'package:devour/domain/managers/accounts_manager.dart' as _i19; -import 'package:devour/domain/meme/abstract_meme_model.dart' as _i16; -import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart' - as _i15; -import 'package:devour/domain/repositories/account_repository.dart' as _i11; -import 'package:devour/infrastructure/api/reddit_api.dart' as _i8; -import 'package:devour/infrastructure/api/reddit_auth_api.dart' as _i10; -import 'package:devour/infrastructure/auth/telegram_auth_facade.dart' as _i5; -import 'package:devour/infrastructure/data/local/data_adapter.dart' as _i13; -import 'package:devour/infrastructure/data/local/hive_adapter.dart' as _i14; +import 'package:devour/domain/meme/abstract_meme_model.dart' as _i10; +import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart' as _i9; +import 'package:devour/domain/repositories/account_repository.dart' as _i15; +import 'package:devour/infrastructure/api/reddit/reddit_api.dart' as _i13; +import 'package:devour/infrastructure/api/reddit/reddit_auth_api.dart' as _i14; +import 'package:devour/infrastructure/auth/telegram_auth_facade.dart' as _i6; +import 'package:devour/infrastructure/data/local/data_adapter.dart' as _i7; +import 'package:devour/infrastructure/data/local/hive_adapter.dart' as _i8; import 'package:devour/infrastructure/meme_scrapper/reddit_scrapper_facade.dart' - as _i17; + as _i11; import 'package:devour/infrastructure/register_module.dart' as _i20; import 'package:devour/infrastructure/repositories/accounts_repository.dart' - as _i18; -import 'package:dio/dio.dart' as _i12; + as _i16; +import 'package:dio/dio.dart' as _i4; import 'package:get_it/get_it.dart' as _i1; import 'package:injectable/injectable.dart' as _i2; // ignore_for_file: unnecessary_lambdas @@ -36,26 +35,26 @@ Future<_i1.GetIt> $initGetIt(_i1.GetIt get, final gh = _i2.GetItHelper(get, environment, environmentFilter); final registerModule = _$RegisterModule(); gh.factory<_i3.AppNavigator>(() => _i3.AppNavigator()); - gh.factory<_i4.IAuthFacade>(() => _i5.TelegramAuthFacade()); - gh.factory<_i6.LoginBloc>(() => _i6.LoginBloc(get<_i4.IAuthFacade>())); - gh.factory<_i7.FeedBloc>(() => _i7.FeedBloc(get<_i8.RedditAPI>())); - gh.factory<_i9.AccountsBloc>(() => _i9.AccountsBloc( - get<_i10.RedditAuthAPI>(), get<_i11.AccountsRepository>())); - gh.singleton<_i12.Dio>(registerModule.getRedditDio(), + gh.singleton<_i4.Dio>(registerModule.getRedditDio(), instanceName: 'redditDio'); - await gh.singletonAsync<_i13.IDataAdapter>(() => _i14.HiveAdapter.create(), + gh.factory<_i5.IAuthFacade>(() => _i6.TelegramAuthFacade()); + await gh.singletonAsync<_i7.IDataAdapter>(() => _i8.HiveAdapter.create(), preResolve: true); - gh.singleton<_i15.IMemeScrapperFacade<_i16.RedditMemeModel>>( - _i17.RedditScrapperFacade(get<_i12.Dio>(instanceName: 'redditDio'))); - gh.singleton<_i8.RedditAPI>( - _i8.RedditAPI(get<_i12.Dio>(instanceName: 'redditDio'))); - gh.singleton<_i10.RedditAuthAPI>( - _i10.RedditAuthAPI(get<_i12.Dio>(instanceName: 'redditDio'))); - await gh.singletonAsync<_i11.AccountsRepository>( - () => _i18.AccountsRepositoryImpl.create(get<_i13.IDataAdapter>()), + gh.singleton<_i9.IMemeScrapperFacade<_i10.RedditMemeModel>>( + _i11.RedditScrapperFacade(get<_i4.Dio>(instanceName: 'redditDio'))); + gh.factory<_i12.LoginBloc>(() => _i12.LoginBloc(get<_i5.IAuthFacade>())); + gh.singleton<_i13.RedditAPI>( + _i13.RedditAPI(get<_i4.Dio>(instanceName: 'redditDio'))); + gh.singleton<_i14.RedditAuthAPI>( + _i14.RedditAuthAPI(get<_i4.Dio>(instanceName: 'redditDio'))); + await gh.singletonAsync<_i15.AccountsRepository>( + () => _i16.AccountsRepositoryImpl.create(get<_i7.IDataAdapter>()), preResolve: true); + gh.factory<_i17.FeedBloc>(() => _i17.FeedBloc(get<_i13.RedditAPI>())); + gh.factory<_i18.AccountsBloc>(() => _i18.AccountsBloc( + get<_i14.RedditAuthAPI>(), get<_i15.AccountsRepository>())); gh.singletonAsync<_i19.AccountsManager>( - () => _i19.AccountsManager.init(get<_i11.AccountsRepository>())); + () => _i19.AccountsManager.init(get<_i15.AccountsRepository>())); return get; } diff --git a/lib/presentation/screens/accounts/accounts_screen.dart b/lib/presentation/screens/accounts/accounts_screen.dart index 95684d0..446bfe3 100644 --- a/lib/presentation/screens/accounts/accounts_screen.dart +++ b/lib/presentation/screens/accounts/accounts_screen.dart @@ -1,6 +1,5 @@ import 'package:devour/application/accounts/bloc/accounts_bloc.dart'; import 'package:devour/application/navigator/routes.dart'; -import 'package:devour/infrastructure/api/reddit_auth_api.dart'; import 'package:devour/injection.dart'; import 'package:devour/presentation/widgets/platform/platform_button.dart'; import 'package:devour/presentation/widgets/platform/platform_scaffold.dart'; diff --git a/pubspec.lock b/pubspec.lock index 60d1aab..2b63d23 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "22.0.0" + version: "25.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "1.7.1" + version: "2.2.0" args: dependency: transitive description: @@ -28,7 +28,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.6.1" + version: "2.8.1" bloc: dependency: transitive description: @@ -77,7 +77,7 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" build_runner_core: dependency: transitive description: @@ -112,7 +112,7 @@ packages: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.1" checked_yaml: dependency: transitive description: @@ -142,7 +142,7 @@ packages: source: hosted version: "4.1.0" collection: - dependency: transitive + dependency: "direct main" description: name: collection url: "https://pub.dartlang.org" @@ -229,7 +229,7 @@ packages: name: flutter_bloc url: "https://pub.dartlang.org" source: hosted - version: "7.1.0" + version: "7.2.0" flutter_dotenv: dependency: "direct main" description: @@ -260,14 +260,14 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.14.2" + version: "0.14.5" freezed_annotation: dependency: "direct main" description: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.14.2" + version: "0.14.3" frontend_server_client: dependency: transitive description: @@ -316,7 +316,7 @@ packages: name: hive_generator url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" http_multi_server: dependency: transitive description: @@ -344,7 +344,7 @@ packages: name: injectable_generator url: "https://pub.dartlang.org" source: hosted - version: "1.4.1" + version: "1.5.2" io: dependency: transitive description: @@ -365,28 +365,28 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "4.1.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "4.1.4" + version: "5.0.0" lint: dependency: "direct dev" description: name: lint url: "https://pub.dartlang.org" source: hosted - version: "1.5.3" + version: "1.7.2" logger: dependency: "direct main" description: name: logger url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0" logging: dependency: transitive description: @@ -407,7 +407,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.7.0" mime: dependency: transitive description: @@ -512,7 +512,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "6.0.0" pub_semver: dependency: transitive description: @@ -547,7 +547,7 @@ packages: name: retrofit_generator url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.1+1" rxdart: dependency: "direct main" description: @@ -580,7 +580,7 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.1.0" source_helper: dependency: transitive description: @@ -636,7 +636,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.4.2" timing: dependency: transitive description: @@ -664,7 +664,7 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.0.9" + version: "6.0.10" url_launcher_linux: dependency: transitive description: @@ -743,5 +743,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.13.0 <3.0.0" + dart: ">=2.14.0-360.0.dev <3.0.0" flutter: ">=2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index c450142..6d2f799 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,35 +8,36 @@ environment: sdk: ">=2.12.0 <3.0.0" dependencies: - cupertino_icons: ^1.0.2 + collection: ^1.15.0 + cupertino_icons: ^1.0.3 dio: ^4.0.0 equatable: ^2.0.3 flutter: sdk: flutter - flutter_bloc: ^7.1.0 + flutter_bloc: ^7.2.0 flutter_dotenv: ^5.0.2 fpdart: ^0.0.10 - freezed_annotation: ^0.14.2 + freezed_annotation: ^0.14.3 get_it: ^7.2.0 hive: ^2.0.4 hive_flutter: ^1.1.0 injectable: ^1.5.0 - logger: ^1.0.0 - provider: ^5.0.0 + logger: ^1.1.0 + provider: ^6.0.0 retrofit: ^2.0.1 rxdart: ^0.27.2 - url_launcher: ^6.0.9 + url_launcher: ^6.0.10 dev_dependencies: - build_runner: ^2.1.1 + build_runner: ^2.1.2 flutter_test: sdk: flutter - freezed: ^0.14.2 - hive_generator: ^1.1.0 - injectable_generator: ^1.4.1 - json_serializable: ^4.1.4 - lint: ^1.5.3 + freezed: ^0.14.5 + hive_generator: ^1.1.1 + injectable_generator: ^1.5.2 + json_serializable: ^5.0.0 + lint: ^1.7.2 retrofit_generator: ^2.0.1 # The following section is specific to Flutter. From 5ad00a071d45b826e4dfb171841ec7b92667b6a9 Mon Sep 17 00:00:00 2001 From: Igor Khramtsov Date: Sun, 12 Sep 2021 01:00:51 +0700 Subject: [PATCH 3/3] + reddit post to meme model mapper + reddit api getMemes wrapper + reddit scrapper implementation --- lib/application/feed/bloc/feed_bloc.dart | 19 +- lib/domain/meme/abstract_meme_model.dart | 13 +- .../meme/abstract_meme_model.freezed.dart | 254 +++--------------- lib/domain/meme/abstract_meme_model.g.dart | 56 ---- lib/infrastructure/api/reddit/reddit_api.dart | 32 ++- .../api/reddit/reddit_api.g.dart | 13 +- .../api/reddit/reddit_auth_api.dart | 10 +- .../meme_scrapper/reddit_meme_mapper.dart | 16 ++ .../meme_scrapper/reddit_scrapper.dart | 29 ++ .../meme_scrapper/reddit_scrapper_facade.dart | 27 -- .../reddit_scrapper_facade.g.dart | 62 ----- lib/injection.config.dart | 55 ++-- .../screens/feed/feed_screen.dart | 18 +- 13 files changed, 179 insertions(+), 425 deletions(-) delete mode 100644 lib/domain/meme/abstract_meme_model.g.dart create mode 100644 lib/infrastructure/meme_scrapper/reddit_meme_mapper.dart create mode 100644 lib/infrastructure/meme_scrapper/reddit_scrapper.dart delete mode 100644 lib/infrastructure/meme_scrapper/reddit_scrapper_facade.dart delete mode 100644 lib/infrastructure/meme_scrapper/reddit_scrapper_facade.g.dart diff --git a/lib/application/feed/bloc/feed_bloc.dart b/lib/application/feed/bloc/feed_bloc.dart index 1dd6c5f..e6ab123 100644 --- a/lib/application/feed/bloc/feed_bloc.dart +++ b/lib/application/feed/bloc/feed_bloc.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:devour/domain/meme/abstract_meme_model.dart'; -import 'package:devour/infrastructure/api/reddit/reddit_api.dart'; +import 'package:devour/infrastructure/meme_scrapper/reddit_scrapper.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:injectable/injectable.dart'; @@ -14,10 +14,10 @@ const int kMemeChunkSize = 20; @injectable class FeedBloc extends Bloc { - RedditAPI redditAPI; + RedditScrapperFacade redditScrapper; /// BLoC for feed widget. - FeedBloc(this.redditAPI) : super(FeedState.loading()); + FeedBloc(this.redditScrapper) : super(FeedState.loading()); @override Stream mapEventToState( @@ -26,13 +26,12 @@ class FeedBloc extends Bloc { yield* event.map( init: (e) async* { yield FeedState.loading(); - final scrappedMemes = await redditAPI.getMemes(); - print(scrappedMemes); - // yield state.copyWith( - // isLoading: false, - // memes: scrappedMemes, - // iterator: 0, - // ); + final scrappedMemes = await redditScrapper.getMemes(kMemeChunkSize); + yield state.copyWith( + isLoading: false, + memes: scrappedMemes, + iterator: 0, + ); }, like: (e) async* { yield state; diff --git a/lib/domain/meme/abstract_meme_model.dart b/lib/domain/meme/abstract_meme_model.dart index 3fcff0c..ba0db04 100644 --- a/lib/domain/meme/abstract_meme_model.dart +++ b/lib/domain/meme/abstract_meme_model.dart @@ -1,7 +1,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'abstract_meme_model.freezed.dart'; -part 'abstract_meme_model.g.dart'; // part 'abstract_meme_model.g.dart'; @freezed @@ -19,18 +18,10 @@ abstract class AbstractMemeModel with _$AbstractMemeModel { factory AbstractMemeModel.reddit({ required String title, required String author, - @JsonKey(name: 'image_reviews') required List imagePreviews, - @JsonKey(name: 'url') required String imageLink, - @JsonKey(name: 'post_link') required String sourceLink, + required String imageLink, + required String sourceLink, required String subreddit, required int ups, - @JsonKey(name: 'spoilers_enabled') required bool spoilersEnabled, required bool nsfw, }) = RedditMemeModel; - - const AbstractMemeModel._(); - - factory AbstractMemeModel.fromJson(Map json) => - _$AbstractMemeModelFromJson(json); - // ignore: public_member_api_docs } diff --git a/lib/domain/meme/abstract_meme_model.freezed.dart b/lib/domain/meme/abstract_meme_model.freezed.dart index e269163..ddcb0e4 100644 --- a/lib/domain/meme/abstract_meme_model.freezed.dart +++ b/lib/domain/meme/abstract_meme_model.freezed.dart @@ -13,19 +13,6 @@ T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); -AbstractMemeModel _$AbstractMemeModelFromJson(Map json) { - switch (json['runtimeType'] as String?) { - case 'default': - return _AbstractMemeModel.fromJson(json); - case 'reddit': - return RedditMemeModel.fromJson(json); - - default: - throw CheckedFromJsonException(json, 'runtimeType', 'AbstractMemeModel', - 'Invalid union type "${json['runtimeType']}"!'); - } -} - /// @nodoc class _$AbstractMemeModelTearOff { const _$AbstractMemeModelTearOff(); @@ -48,29 +35,21 @@ class _$AbstractMemeModelTearOff { RedditMemeModel reddit( {required String title, required String author, - @JsonKey(name: 'image_reviews') required List imagePreviews, - @JsonKey(name: 'url') required String imageLink, - @JsonKey(name: 'post_link') required String sourceLink, + required String imageLink, + required String sourceLink, required String subreddit, required int ups, - @JsonKey(name: 'spoilers_enabled') required bool spoilersEnabled, required bool nsfw}) { return RedditMemeModel( title: title, author: author, - imagePreviews: imagePreviews, imageLink: imageLink, sourceLink: sourceLink, subreddit: subreddit, ups: ups, - spoilersEnabled: spoilersEnabled, nsfw: nsfw, ); } - - AbstractMemeModel fromJson(Map json) { - return AbstractMemeModel.fromJson(json); - } } /// @nodoc @@ -82,23 +61,14 @@ mixin _$AbstractMemeModel { String get imageLink => throw _privateConstructorUsedError; String get title => throw _privateConstructorUsedError; String get author => throw _privateConstructorUsedError; - List get imagePreviews => throw _privateConstructorUsedError; @optionalTypeArgs TResult when( TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews) $default, { - required TResult Function( - String title, - String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, - String subreddit, - int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, - bool nsfw) + required TResult Function(String title, String author, String imageLink, + String sourceLink, String subreddit, int ups, bool nsfw) reddit, }) => throw _privateConstructorUsedError; @@ -107,16 +77,8 @@ mixin _$AbstractMemeModel { TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews)? $default, { - TResult Function( - String title, - String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, - String subreddit, - int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, - bool nsfw)? + TResult Function(String title, String author, String imageLink, + String sourceLink, String subreddit, int ups, bool nsfw)? reddit, }) => throw _privateConstructorUsedError; @@ -125,16 +87,8 @@ mixin _$AbstractMemeModel { TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews)? $default, { - TResult Function( - String title, - String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, - String subreddit, - int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, - bool nsfw)? + TResult Function(String title, String author, String imageLink, + String sourceLink, String subreddit, int ups, bool nsfw)? reddit, required TResult orElse(), }) => @@ -158,7 +112,7 @@ mixin _$AbstractMemeModel { required TResult orElse(), }) => throw _privateConstructorUsedError; - Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) $AbstractMemeModelCopyWith get copyWith => throw _privateConstructorUsedError; @@ -169,12 +123,7 @@ abstract class $AbstractMemeModelCopyWith<$Res> { factory $AbstractMemeModelCopyWith( AbstractMemeModel value, $Res Function(AbstractMemeModel) then) = _$AbstractMemeModelCopyWithImpl<$Res>; - $Res call( - {String sourceLink, - String imageLink, - String title, - String author, - List imagePreviews}); + $Res call({String sourceLink, String imageLink, String title, String author}); } /// @nodoc @@ -192,7 +141,6 @@ class _$AbstractMemeModelCopyWithImpl<$Res> Object? imageLink = freezed, Object? title = freezed, Object? author = freezed, - Object? imagePreviews = freezed, }) { return _then(_value.copyWith( sourceLink: sourceLink == freezed @@ -211,10 +159,6 @@ class _$AbstractMemeModelCopyWithImpl<$Res> ? _value.author : author // ignore: cast_nullable_to_non_nullable as String, - imagePreviews: imagePreviews == freezed - ? _value.imagePreviews - : imagePreviews // ignore: cast_nullable_to_non_nullable - as List, )); } } @@ -279,18 +223,14 @@ class __$AbstractMemeModelCopyWithImpl<$Res> } /// @nodoc -@JsonSerializable() -class _$_AbstractMemeModel extends _AbstractMemeModel { + +class _$_AbstractMemeModel implements _AbstractMemeModel { _$_AbstractMemeModel( {required this.sourceLink, required this.imageLink, required this.title, required this.author, - required this.imagePreviews}) - : super._(); - - factory _$_AbstractMemeModel.fromJson(Map json) => - _$$_AbstractMemeModelFromJson(json); + required this.imagePreviews}); @override final String sourceLink; @@ -347,16 +287,8 @@ class _$_AbstractMemeModel extends _AbstractMemeModel { TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews) $default, { - required TResult Function( - String title, - String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, - String subreddit, - int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, - bool nsfw) + required TResult Function(String title, String author, String imageLink, + String sourceLink, String subreddit, int ups, bool nsfw) reddit, }) { return $default(sourceLink, imageLink, title, author, imagePreviews); @@ -368,16 +300,8 @@ class _$_AbstractMemeModel extends _AbstractMemeModel { TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews)? $default, { - TResult Function( - String title, - String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, - String subreddit, - int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, - bool nsfw)? + TResult Function(String title, String author, String imageLink, + String sourceLink, String subreddit, int ups, bool nsfw)? reddit, }) { return $default?.call(sourceLink, imageLink, title, author, imagePreviews); @@ -389,16 +313,8 @@ class _$_AbstractMemeModel extends _AbstractMemeModel { TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews)? $default, { - TResult Function( - String title, - String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, - String subreddit, - int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, - bool nsfw)? + TResult Function(String title, String author, String imageLink, + String sourceLink, String subreddit, int ups, bool nsfw)? reddit, required TResult orElse(), }) { @@ -438,24 +354,15 @@ class _$_AbstractMemeModel extends _AbstractMemeModel { } return orElse(); } - - @override - Map toJson() { - return _$$_AbstractMemeModelToJson(this)..['runtimeType'] = 'default'; - } } -abstract class _AbstractMemeModel extends AbstractMemeModel { +abstract class _AbstractMemeModel implements AbstractMemeModel { factory _AbstractMemeModel( {required String sourceLink, required String imageLink, required String title, required String author, required List imagePreviews}) = _$_AbstractMemeModel; - _AbstractMemeModel._() : super._(); - - factory _AbstractMemeModel.fromJson(Map json) = - _$_AbstractMemeModel.fromJson; @override String get sourceLink => throw _privateConstructorUsedError; @@ -465,7 +372,6 @@ abstract class _AbstractMemeModel extends AbstractMemeModel { String get title => throw _privateConstructorUsedError; @override String get author => throw _privateConstructorUsedError; - @override List get imagePreviews => throw _privateConstructorUsedError; @override @JsonKey(ignore: true) @@ -483,12 +389,10 @@ abstract class $RedditMemeModelCopyWith<$Res> $Res call( {String title, String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, + String imageLink, + String sourceLink, String subreddit, int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, bool nsfw}); } @@ -507,12 +411,10 @@ class _$RedditMemeModelCopyWithImpl<$Res> $Res call({ Object? title = freezed, Object? author = freezed, - Object? imagePreviews = freezed, Object? imageLink = freezed, Object? sourceLink = freezed, Object? subreddit = freezed, Object? ups = freezed, - Object? spoilersEnabled = freezed, Object? nsfw = freezed, }) { return _then(RedditMemeModel( @@ -524,10 +426,6 @@ class _$RedditMemeModelCopyWithImpl<$Res> ? _value.author : author // ignore: cast_nullable_to_non_nullable as String, - imagePreviews: imagePreviews == freezed - ? _value.imagePreviews - : imagePreviews // ignore: cast_nullable_to_non_nullable - as List, imageLink: imageLink == freezed ? _value.imageLink : imageLink // ignore: cast_nullable_to_non_nullable @@ -544,10 +442,6 @@ class _$RedditMemeModelCopyWithImpl<$Res> ? _value.ups : ups // ignore: cast_nullable_to_non_nullable as int, - spoilersEnabled: spoilersEnabled == freezed - ? _value.spoilersEnabled - : spoilersEnabled // ignore: cast_nullable_to_non_nullable - as bool, nsfw: nsfw == freezed ? _value.nsfw : nsfw // ignore: cast_nullable_to_non_nullable @@ -557,49 +451,35 @@ class _$RedditMemeModelCopyWithImpl<$Res> } /// @nodoc -@JsonSerializable() -class _$RedditMemeModel extends RedditMemeModel { + +class _$RedditMemeModel implements RedditMemeModel { _$RedditMemeModel( {required this.title, required this.author, - @JsonKey(name: 'image_reviews') required this.imagePreviews, - @JsonKey(name: 'url') required this.imageLink, - @JsonKey(name: 'post_link') required this.sourceLink, + required this.imageLink, + required this.sourceLink, required this.subreddit, required this.ups, - @JsonKey(name: 'spoilers_enabled') required this.spoilersEnabled, - required this.nsfw}) - : super._(); - - factory _$RedditMemeModel.fromJson(Map json) => - _$$RedditMemeModelFromJson(json); + required this.nsfw}); @override final String title; @override final String author; @override - @JsonKey(name: 'image_reviews') - final List imagePreviews; - @override - @JsonKey(name: 'url') final String imageLink; @override - @JsonKey(name: 'post_link') final String sourceLink; @override final String subreddit; @override final int ups; @override - @JsonKey(name: 'spoilers_enabled') - final bool spoilersEnabled; - @override final bool nsfw; @override String toString() { - return 'AbstractMemeModel.reddit(title: $title, author: $author, imagePreviews: $imagePreviews, imageLink: $imageLink, sourceLink: $sourceLink, subreddit: $subreddit, ups: $ups, spoilersEnabled: $spoilersEnabled, nsfw: $nsfw)'; + return 'AbstractMemeModel.reddit(title: $title, author: $author, imageLink: $imageLink, sourceLink: $sourceLink, subreddit: $subreddit, ups: $ups, nsfw: $nsfw)'; } @override @@ -610,9 +490,6 @@ class _$RedditMemeModel extends RedditMemeModel { const DeepCollectionEquality().equals(other.title, title)) && (identical(other.author, author) || const DeepCollectionEquality().equals(other.author, author)) && - (identical(other.imagePreviews, imagePreviews) || - const DeepCollectionEquality() - .equals(other.imagePreviews, imagePreviews)) && (identical(other.imageLink, imageLink) || const DeepCollectionEquality() .equals(other.imageLink, imageLink)) && @@ -624,9 +501,6 @@ class _$RedditMemeModel extends RedditMemeModel { .equals(other.subreddit, subreddit)) && (identical(other.ups, ups) || const DeepCollectionEquality().equals(other.ups, ups)) && - (identical(other.spoilersEnabled, spoilersEnabled) || - const DeepCollectionEquality() - .equals(other.spoilersEnabled, spoilersEnabled)) && (identical(other.nsfw, nsfw) || const DeepCollectionEquality().equals(other.nsfw, nsfw))); } @@ -636,12 +510,10 @@ class _$RedditMemeModel extends RedditMemeModel { runtimeType.hashCode ^ const DeepCollectionEquality().hash(title) ^ const DeepCollectionEquality().hash(author) ^ - const DeepCollectionEquality().hash(imagePreviews) ^ const DeepCollectionEquality().hash(imageLink) ^ const DeepCollectionEquality().hash(sourceLink) ^ const DeepCollectionEquality().hash(subreddit) ^ const DeepCollectionEquality().hash(ups) ^ - const DeepCollectionEquality().hash(spoilersEnabled) ^ const DeepCollectionEquality().hash(nsfw); @JsonKey(ignore: true) @@ -655,20 +527,11 @@ class _$RedditMemeModel extends RedditMemeModel { TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews) $default, { - required TResult Function( - String title, - String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, - String subreddit, - int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, - bool nsfw) + required TResult Function(String title, String author, String imageLink, + String sourceLink, String subreddit, int ups, bool nsfw) reddit, }) { - return reddit(title, author, imagePreviews, imageLink, sourceLink, - subreddit, ups, spoilersEnabled, nsfw); + return reddit(title, author, imageLink, sourceLink, subreddit, ups, nsfw); } @override @@ -677,20 +540,12 @@ class _$RedditMemeModel extends RedditMemeModel { TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews)? $default, { - TResult Function( - String title, - String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, - String subreddit, - int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, - bool nsfw)? + TResult Function(String title, String author, String imageLink, + String sourceLink, String subreddit, int ups, bool nsfw)? reddit, }) { - return reddit?.call(title, author, imagePreviews, imageLink, sourceLink, - subreddit, ups, spoilersEnabled, nsfw); + return reddit?.call( + title, author, imageLink, sourceLink, subreddit, ups, nsfw); } @override @@ -699,22 +554,13 @@ class _$RedditMemeModel extends RedditMemeModel { TResult Function(String sourceLink, String imageLink, String title, String author, List imagePreviews)? $default, { - TResult Function( - String title, - String author, - @JsonKey(name: 'image_reviews') List imagePreviews, - @JsonKey(name: 'url') String imageLink, - @JsonKey(name: 'post_link') String sourceLink, - String subreddit, - int ups, - @JsonKey(name: 'spoilers_enabled') bool spoilersEnabled, - bool nsfw)? + TResult Function(String title, String author, String imageLink, + String sourceLink, String subreddit, int ups, bool nsfw)? reddit, required TResult orElse(), }) { if (reddit != null) { - return reddit(title, author, imagePreviews, imageLink, sourceLink, - subreddit, ups, spoilersEnabled, nsfw); + return reddit(title, author, imageLink, sourceLink, subreddit, ups, nsfw); } return orElse(); } @@ -749,46 +595,28 @@ class _$RedditMemeModel extends RedditMemeModel { } return orElse(); } - - @override - Map toJson() { - return _$$RedditMemeModelToJson(this)..['runtimeType'] = 'reddit'; - } } -abstract class RedditMemeModel extends AbstractMemeModel { +abstract class RedditMemeModel implements AbstractMemeModel { factory RedditMemeModel( {required String title, required String author, - @JsonKey(name: 'image_reviews') required List imagePreviews, - @JsonKey(name: 'url') required String imageLink, - @JsonKey(name: 'post_link') required String sourceLink, + required String imageLink, + required String sourceLink, required String subreddit, required int ups, - @JsonKey(name: 'spoilers_enabled') required bool spoilersEnabled, required bool nsfw}) = _$RedditMemeModel; - RedditMemeModel._() : super._(); - - factory RedditMemeModel.fromJson(Map json) = - _$RedditMemeModel.fromJson; @override String get title => throw _privateConstructorUsedError; @override String get author => throw _privateConstructorUsedError; @override - @JsonKey(name: 'image_reviews') - List get imagePreviews => throw _privateConstructorUsedError; - @override - @JsonKey(name: 'url') String get imageLink => throw _privateConstructorUsedError; @override - @JsonKey(name: 'post_link') String get sourceLink => throw _privateConstructorUsedError; String get subreddit => throw _privateConstructorUsedError; int get ups => throw _privateConstructorUsedError; - @JsonKey(name: 'spoilers_enabled') - bool get spoilersEnabled => throw _privateConstructorUsedError; bool get nsfw => throw _privateConstructorUsedError; @override @JsonKey(ignore: true) diff --git a/lib/domain/meme/abstract_meme_model.g.dart b/lib/domain/meme/abstract_meme_model.g.dart deleted file mode 100644 index 95c4671..0000000 --- a/lib/domain/meme/abstract_meme_model.g.dart +++ /dev/null @@ -1,56 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'abstract_meme_model.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$_AbstractMemeModel _$$_AbstractMemeModelFromJson(Map json) => - _$_AbstractMemeModel( - sourceLink: json['sourceLink'] as String, - imageLink: json['imageLink'] as String, - title: json['title'] as String, - author: json['author'] as String, - imagePreviews: (json['imagePreviews'] as List) - .map((e) => e as String) - .toList(), - ); - -Map _$$_AbstractMemeModelToJson( - _$_AbstractMemeModel instance) => - { - 'sourceLink': instance.sourceLink, - 'imageLink': instance.imageLink, - 'title': instance.title, - 'author': instance.author, - 'imagePreviews': instance.imagePreviews, - }; - -_$RedditMemeModel _$$RedditMemeModelFromJson(Map json) => - _$RedditMemeModel( - title: json['title'] as String, - author: json['author'] as String, - imagePreviews: (json['image_reviews'] as List) - .map((e) => e as String) - .toList(), - imageLink: json['url'] as String, - sourceLink: json['post_link'] as String, - subreddit: json['subreddit'] as String, - ups: json['ups'] as int, - spoilersEnabled: json['spoilers_enabled'] as bool, - nsfw: json['nsfw'] as bool, - ); - -Map _$$RedditMemeModelToJson(_$RedditMemeModel instance) => - { - 'title': instance.title, - 'author': instance.author, - 'image_reviews': instance.imagePreviews, - 'url': instance.imageLink, - 'post_link': instance.sourceLink, - 'subreddit': instance.subreddit, - 'ups': instance.ups, - 'spoilers_enabled': instance.spoilersEnabled, - 'nsfw': instance.nsfw, - }; diff --git a/lib/infrastructure/api/reddit/reddit_api.dart b/lib/infrastructure/api/reddit/reddit_api.dart index 28864bd..bbb4e8d 100644 --- a/lib/infrastructure/api/reddit/reddit_api.dart +++ b/lib/infrastructure/api/reddit/reddit_api.dart @@ -16,13 +16,41 @@ abstract class RedditAPI { @factoryMethod factory RedditAPI(@Named(kRedditDioName) Dio dio) = _RedditAPI; - @GET('/r/memes') - Future getMemes(); + // /r/subbreddit/random + // /r/subbreddit/sort (top, controversial) + + /// Grabs posts from /r/[subreddit] (memes) by default. [after] and [before] are + /// used for navigation, [limit] for number of posts. + @GET('/r/{subreddit}') + Future _getMemes({ + @Query('after') String? after, + @Query('before') String? before, + @Query('count') int? count, + @Query('limit') int? limit, + @Path('subreddit') String subreddit = 'memes', + }); static Interceptor getAuthenticationTokenInterceptor() => AuthenticationTokenInterceptor(); } +extension RedditAPIWrapper on RedditAPI { + Future getMemes({ + String? after, + String? before, + int? count, + int? limit, + String subreddit = 'memes', + }) => + _getMemes( + after: after, + before: before, + count: count, + limit: limit, + subreddit: subreddit, + ).then((it) => it.data as RedditListingResponse); +} + class AuthenticationTokenInterceptor extends Interceptor { AuthenticationTokenInterceptor(); diff --git a/lib/infrastructure/api/reddit/reddit_api.g.dart b/lib/infrastructure/api/reddit/reddit_api.g.dart index e5ac83f..485b829 100644 --- a/lib/infrastructure/api/reddit/reddit_api.g.dart +++ b/lib/infrastructure/api/reddit/reddit_api.g.dart @@ -16,14 +16,21 @@ class _RedditAPI implements RedditAPI { String? baseUrl; @override - Future> getMemes() async { + Future> _getMemes( + {after, before, count, limit, subreddit = 'memes'}) async { const _extra = {}; - final queryParameters = {}; + final queryParameters = { + r'after': after, + r'before': before, + r'count': count, + r'limit': limit + }; + queryParameters.removeWhere((k, v) => v == null); final _data = {}; final _result = await _dio.fetch>( _setStreamType>( Options(method: 'GET', headers: {}, extra: _extra) - .compose(_dio.options, '/r/memes', + .compose(_dio.options, '/r/$subreddit', queryParameters: queryParameters, data: _data) .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); final value = RedditResponse.fromJson(_result.data!); diff --git a/lib/infrastructure/api/reddit/reddit_auth_api.dart b/lib/infrastructure/api/reddit/reddit_auth_api.dart index 8d75471..24a55fc 100644 --- a/lib/infrastructure/api/reddit/reddit_auth_api.dart +++ b/lib/infrastructure/api/reddit/reddit_auth_api.dart @@ -57,12 +57,16 @@ class RefreshTokenInterceptor extends Interceptor { .getAccount() .toNullable()!; final newAccount = RedditAccount.fromResponse( - await serviceLocator().refreshToken(account)); + await serviceLocator().refreshToken(account), + ); serviceLocator().setAccount(newAccount); options.headers!['Authorization'] = 'bearer ${newAccount.accessToken}'; - final cloneRequest = await dio.request(requestOptions.path, - options: options, queryParameters: requestOptions.queryParameters); + final cloneRequest = await dio.request( + requestOptions.path, + options: options, + queryParameters: requestOptions.queryParameters, + ); handler.resolve(cloneRequest); } else { handler.next(err); diff --git a/lib/infrastructure/meme_scrapper/reddit_meme_mapper.dart b/lib/infrastructure/meme_scrapper/reddit_meme_mapper.dart new file mode 100644 index 0000000..7493701 --- /dev/null +++ b/lib/infrastructure/meme_scrapper/reddit_meme_mapper.dart @@ -0,0 +1,16 @@ +import 'package:devour/domain/meme/abstract_meme_model.dart'; +import 'package:devour/infrastructure/api/reddit/response/reddit_responses.dart'; + +class RedditMemeMapper { + static RedditMemeModel map(RedditPostResponse response) { + return RedditMemeModel( + title: response.title, + author: response.author, + imageLink: response.url, + sourceLink: '', + subreddit: response.subreddit, + ups: response.ups, + nsfw: response.over18, + ); + } +} diff --git a/lib/infrastructure/meme_scrapper/reddit_scrapper.dart b/lib/infrastructure/meme_scrapper/reddit_scrapper.dart new file mode 100644 index 0000000..51607f6 --- /dev/null +++ b/lib/infrastructure/meme_scrapper/reddit_scrapper.dart @@ -0,0 +1,29 @@ +import 'package:devour/domain/meme/abstract_meme_model.dart'; +import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart'; +import 'package:devour/infrastructure/api/reddit/reddit_api.dart'; +import 'package:devour/infrastructure/api/reddit/response/reddit_responses.dart'; +import 'package:devour/infrastructure/meme_scrapper/reddit_meme_mapper.dart'; +import 'package:injectable/injectable.dart'; + +@singleton +class RedditScrapperFacade { + @factoryMethod + RedditScrapperFacade(this.redditAPI); + + final RedditAPI redditAPI; + + @override + Future getOneMeme() { + throw UnimplementedError(); + } + + @override + Future> getMemes(int count) async { + final listing = await redditAPI.getMemes(limit: count); + final memes = listing.children + .map((post) => post as RedditPostResponse) + .where((post) => !post.stickied) + .map(RedditMemeMapper.map); + return memes.toList(); + } +} diff --git a/lib/infrastructure/meme_scrapper/reddit_scrapper_facade.dart b/lib/infrastructure/meme_scrapper/reddit_scrapper_facade.dart deleted file mode 100644 index 7939e44..0000000 --- a/lib/infrastructure/meme_scrapper/reddit_scrapper_facade.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:devour/domain/meme/abstract_meme_model.dart'; -import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart'; -import 'package:devour/infrastructure/register_module.dart'; -import 'package:dio/dio.dart'; -import 'package:injectable/injectable.dart'; -import 'package:retrofit/retrofit.dart'; - -part 'reddit_scrapper_facade.g.dart'; - -abstract class IRedditScrapperFacade - extends IMemeScrapperFacade {} - -@Singleton(as: IMemeScrapperFacade) -@RestApi(baseUrl: 'https://reddit-meme-api.herokuapp.com/') -abstract class RedditScrapperFacade - implements IMemeScrapperFacade { - @factoryMethod - factory RedditScrapperFacade(@Named(kRedditDioName) Dio dio) = _RedditScrapperFacade; - - @override - @GET('/1') - Future getOneMeme(); - - @override - @GET('/{count}') - Future> getMemes(@Path() int count); -} diff --git a/lib/infrastructure/meme_scrapper/reddit_scrapper_facade.g.dart b/lib/infrastructure/meme_scrapper/reddit_scrapper_facade.g.dart deleted file mode 100644 index 847753e..0000000 --- a/lib/infrastructure/meme_scrapper/reddit_scrapper_facade.g.dart +++ /dev/null @@ -1,62 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'reddit_scrapper_facade.dart'; - -// ************************************************************************** -// RetrofitGenerator -// ************************************************************************** - -class _RedditScrapperFacade implements RedditScrapperFacade { - _RedditScrapperFacade(this._dio, {this.baseUrl}) { - baseUrl ??= 'https://reddit-meme-api.herokuapp.com/'; - } - - final Dio _dio; - - String? baseUrl; - - @override - Future getOneMeme() async { - const _extra = {}; - final queryParameters = {}; - final _data = {}; - final _result = await _dio.fetch>( - _setStreamType( - Options(method: 'GET', headers: {}, extra: _extra) - .compose(_dio.options, '/1', - queryParameters: queryParameters, data: _data) - .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); - final value = RedditMemeModel.fromJson(_result.data!); - return value; - } - - @override - Future> getMemes(count) async { - const _extra = {}; - final queryParameters = {}; - final _data = {}; - final _result = await _dio.fetch>( - _setStreamType>( - Options(method: 'GET', headers: {}, extra: _extra) - .compose(_dio.options, '/$count', - queryParameters: queryParameters, data: _data) - .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl))); - var value = _result.data! - .map((dynamic i) => RedditMemeModel.fromJson(i as Map)) - .toList(); - return value; - } - - RequestOptions _setStreamType(RequestOptions requestOptions) { - if (T != dynamic && - !(requestOptions.responseType == ResponseType.bytes || - requestOptions.responseType == ResponseType.stream)) { - if (T == String) { - requestOptions.responseType = ResponseType.plain; - } else { - requestOptions.responseType = ResponseType.json; - } - } - return requestOptions; - } -} diff --git a/lib/injection.config.dart b/lib/injection.config.dart index 6351279..82b2624 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -4,25 +4,23 @@ // InjectableConfigGenerator // ************************************************************************** -import 'package:devour/application/accounts/bloc/accounts_bloc.dart' as _i18; -import 'package:devour/application/auth/login/login_bloc.dart' as _i12; -import 'package:devour/application/feed/bloc/feed_bloc.dart' as _i17; +import 'package:devour/application/accounts/bloc/accounts_bloc.dart' as _i16; +import 'package:devour/application/auth/login/login_bloc.dart' as _i9; +import 'package:devour/application/feed/bloc/feed_bloc.dart' as _i15; import 'package:devour/application/navigator/app_navigator.dart' as _i3; import 'package:devour/domain/auth/i_auth_facade.dart' as _i5; -import 'package:devour/domain/managers/accounts_manager.dart' as _i19; -import 'package:devour/domain/meme/abstract_meme_model.dart' as _i10; -import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart' as _i9; -import 'package:devour/domain/repositories/account_repository.dart' as _i15; -import 'package:devour/infrastructure/api/reddit/reddit_api.dart' as _i13; -import 'package:devour/infrastructure/api/reddit/reddit_auth_api.dart' as _i14; +import 'package:devour/domain/managers/accounts_manager.dart' as _i17; +import 'package:devour/domain/repositories/account_repository.dart' as _i13; +import 'package:devour/infrastructure/api/reddit/reddit_api.dart' as _i10; +import 'package:devour/infrastructure/api/reddit/reddit_auth_api.dart' as _i11; import 'package:devour/infrastructure/auth/telegram_auth_facade.dart' as _i6; import 'package:devour/infrastructure/data/local/data_adapter.dart' as _i7; import 'package:devour/infrastructure/data/local/hive_adapter.dart' as _i8; -import 'package:devour/infrastructure/meme_scrapper/reddit_scrapper_facade.dart' - as _i11; -import 'package:devour/infrastructure/register_module.dart' as _i20; +import 'package:devour/infrastructure/meme_scrapper/reddit_scrapper.dart' + as _i12; +import 'package:devour/infrastructure/register_module.dart' as _i18; import 'package:devour/infrastructure/repositories/accounts_repository.dart' - as _i16; + as _i14; import 'package:dio/dio.dart' as _i4; import 'package:get_it/get_it.dart' as _i1; import 'package:injectable/injectable.dart' @@ -40,22 +38,23 @@ Future<_i1.GetIt> $initGetIt(_i1.GetIt get, gh.factory<_i5.IAuthFacade>(() => _i6.TelegramAuthFacade()); await gh.singletonAsync<_i7.IDataAdapter>(() => _i8.HiveAdapter.create(), preResolve: true); - gh.singleton<_i9.IMemeScrapperFacade<_i10.RedditMemeModel>>( - _i11.RedditScrapperFacade(get<_i4.Dio>(instanceName: 'redditDio'))); - gh.factory<_i12.LoginBloc>(() => _i12.LoginBloc(get<_i5.IAuthFacade>())); - gh.singleton<_i13.RedditAPI>( - _i13.RedditAPI(get<_i4.Dio>(instanceName: 'redditDio'))); - gh.singleton<_i14.RedditAuthAPI>( - _i14.RedditAuthAPI(get<_i4.Dio>(instanceName: 'redditDio'))); - await gh.singletonAsync<_i15.AccountsRepository>( - () => _i16.AccountsRepositoryImpl.create(get<_i7.IDataAdapter>()), + gh.factory<_i9.LoginBloc>(() => _i9.LoginBloc(get<_i5.IAuthFacade>())); + gh.singleton<_i10.RedditAPI>( + _i10.RedditAPI(get<_i4.Dio>(instanceName: 'redditDio'))); + gh.singleton<_i11.RedditAuthAPI>( + _i11.RedditAuthAPI(get<_i4.Dio>(instanceName: 'redditDio'))); + gh.singleton<_i12.RedditScrapperFacade>( + _i12.RedditScrapperFacade(get<_i10.RedditAPI>())); + await gh.singletonAsync<_i13.AccountsRepository>( + () => _i14.AccountsRepositoryImpl.create(get<_i7.IDataAdapter>()), preResolve: true); - gh.factory<_i17.FeedBloc>(() => _i17.FeedBloc(get<_i13.RedditAPI>())); - gh.factory<_i18.AccountsBloc>(() => _i18.AccountsBloc( - get<_i14.RedditAuthAPI>(), get<_i15.AccountsRepository>())); - gh.singletonAsync<_i19.AccountsManager>( - () => _i19.AccountsManager.init(get<_i15.AccountsRepository>())); + gh.factory<_i15.FeedBloc>( + () => _i15.FeedBloc(get<_i12.RedditScrapperFacade>())); + gh.factory<_i16.AccountsBloc>(() => _i16.AccountsBloc( + get<_i11.RedditAuthAPI>(), get<_i13.AccountsRepository>())); + gh.singletonAsync<_i17.AccountsManager>( + () => _i17.AccountsManager.init(get<_i13.AccountsRepository>())); return get; } -class _$RegisterModule extends _i20.RegisterModule {} +class _$RegisterModule extends _i18.RegisterModule {} diff --git a/lib/presentation/screens/feed/feed_screen.dart b/lib/presentation/screens/feed/feed_screen.dart index 9eb3525..22f37d5 100644 --- a/lib/presentation/screens/feed/feed_screen.dart +++ b/lib/presentation/screens/feed/feed_screen.dart @@ -1,6 +1,5 @@ import 'package:devour/application/feed/bloc/feed_bloc.dart'; -import 'package:devour/domain/meme/abstract_meme_model.dart'; -import 'package:devour/domain/meme_scrapper/i_meme_scrapper_facade.dart'; +import 'package:devour/infrastructure/meme_scrapper/reddit_scrapper.dart'; import 'package:devour/injection.dart'; import 'package:devour/presentation/widgets/platform/platform_scaffold.dart'; import 'package:flutter/widgets.dart'; @@ -14,13 +13,12 @@ class FeedScreen extends StatelessWidget { @override Widget build(BuildContext context) { return PlatformScaffold( - body: BlocProvider( - create: (context) => serviceLocator.get( - // maybe its not the best soltion, but i don't know, how to do injectable - // with generics like - param1: serviceLocator.get>()) - ..add(FeedEvent.init()), - child: Feed(), - )); + body: BlocProvider( + create: (context) => serviceLocator.get( + param1: serviceLocator.get(), + )..add(FeedEvent.init()), + child: Feed(), + ), + ); } }