Skip to content
24 changes: 23 additions & 1 deletion lib/feature/data/datasource/news/news_remote_data_source.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlin
import 'package:meta/meta.dart';

abstract class NewsRemoteDataSource {
/// Calls the baseUrl:/v2/top-headlines?category=:category&country=:country&apiKey=:apiKey endpoint
/// Calls the [baseUrl]/v2/top-headlines?category=:category&country=:country&apiKey=:apiKey endpoint
///
/// Throws a [DioError] for all error codes.
Future<TopHeadlinesNewsResponseModel> getTopHeadlinesNews(String category);

/// Calls the [baseUrl]/v2/top-headlines?country=:country&apiKey=:apiKey&q=:q
///
/// Throws a [DioError] for all error codes.
Future<TopHeadlinesNewsResponseModel> searchTopHeadlinesNews(String keyword);
}

class NewsRemoteDataSourceImpl implements NewsRemoteDataSource {
Expand Down Expand Up @@ -46,4 +51,21 @@ class NewsRemoteDataSourceImpl implements NewsRemoteDataSource {
throw DioError();
}
}

@override
Future<TopHeadlinesNewsResponseModel> searchTopHeadlinesNews(String keyword) async {
var response = await dio.get(
'/v2/top-headlines',
queryParameters: {
'country': 'id',
'apiKey': constantConfig.apiKeyNewsApi,
'q': keyword,
},
);
if (response.statusCode == 200) {
return TopHeadlinesNewsResponseModel.fromJson(response.data);
} else {
throw DioError();
}
}
}
15 changes: 15 additions & 0 deletions lib/feature/data/repository/news/news_repository_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,19 @@ class NewsRepositoryImpl implements NewsRepository {
return Left(ConnectionFailure());
}
}

@override
Future<Either<Failure, TopHeadlinesNewsResponseModel>> searchTopHeadlinesNews(String keyword) async {
var isConnected = await networkInfo.isConnected;
if (isConnected) {
try {
var response = await newsRemoteDataSource.searchTopHeadlinesNews(keyword);
return Right(response);
} on DioError catch (error) {
return Left(ServerFailure(error.message));
}
} else {
return Left(ConnectionFailure());
}
}
}
1 change: 1 addition & 0 deletions lib/feature/domain/repository/news/news_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ abstract class NewsRepository {

Future<Either<Failure, TopHeadlinesNewsResponseModel>> getTopHeadlinesNews(String category);

Future<Either<Failure, TopHeadlinesNewsResponseModel>> searchTopHeadlinesNews(String keyword);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_news_app/core/error/failure.dart';
import 'package:flutter_news_app/feature/domain/repository/news/news_repository.dart';
import 'package:meta/meta.dart';
import 'package:flutter_news_app/core/usecase/usecase.dart';
import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlines_news_response_model.dart';

class SearchTopHeadlinesNews implements UseCase<TopHeadlinesNewsResponseModel, ParamsSearchTopHeadlinesNews> {
final NewsRepository newsRepository;

SearchTopHeadlinesNews({@required this.newsRepository});

@override
Future<Either<Failure, TopHeadlinesNewsResponseModel>> call(ParamsSearchTopHeadlinesNews params) async {
return await newsRepository.searchTopHeadlinesNews(params.keyword);
}
}

class ParamsSearchTopHeadlinesNews extends Equatable {
final String keyword;

ParamsSearchTopHeadlinesNews({@required this.keyword});

@override
List<Object> get props => [keyword];

@override
String toString() {
return 'ParamsSearchTopHeadlinesNews{keyword: $keyword}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:flutter_news_app/core/error/failure.dart';
import 'package:flutter_news_app/feature/domain/usecase/gettopheadlinesnews/get_top_headlines_news.dart';
import 'package:flutter_news_app/feature/domain/usecase/searchtopheadlinesnews/search_top_headlines_news.dart';
import 'package:meta/meta.dart';

import './bloc.dart';

class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsState> {
final GetTopHeadlinesNews getTopHeadlinesNews;
final SearchTopHeadlinesNews searchTopHeadlinesNews;

TopHeadlinesNewsBloc({@required this.getTopHeadlinesNews}) : assert(getTopHeadlinesNews != null);
TopHeadlinesNewsBloc({
@required this.getTopHeadlinesNews,
@required this.searchTopHeadlinesNews,
}) : assert(getTopHeadlinesNews != null),
assert(searchTopHeadlinesNews != null);

@override
TopHeadlinesNewsState get initialState => InitialTopHeadlinesNewsState();
Expand All @@ -23,6 +29,8 @@ class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsS
yield* _mapLoadTopHeadlinesNewsEventToState(event);
} else if (event is ChangeCategoryTopHeadlinesNewsEvent) {
yield* _mapChangeCategoryTopHeadlinesNewsEventToState(event);
} else if (event is SearchTopHeadlinesNewsEvent) {
yield* _mapSearchTopHeadlinesNewsEventToState(event);
}
}

Expand All @@ -47,4 +55,20 @@ class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsS
) async* {
yield ChangedCategoryTopHeadlinesNewsState(indexCategorySelected: event.indexCategorySelected);
}

Stream<TopHeadlinesNewsState> _mapSearchTopHeadlinesNewsEventToState(SearchTopHeadlinesNewsEvent event) async* {
yield LoadingTopHeadlinesNewsState();
var result = await searchTopHeadlinesNews(ParamsSearchTopHeadlinesNews(keyword: event.keyword));
yield result.fold(
// ignore: missing_return
(failure) {
if (failure is ServerFailure) {
return FailureTopHeadlinesNewsState(errorMessage: failure.errorMessage);
} else if (failure is ConnectionFailure) {
return FailureTopHeadlinesNewsState(errorMessage: failure.errorMessage);
}
},
(response) => SearchSuccessTopHeadlinesNewsState(listArticles: response.articles),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,18 @@ class ChangeCategoryTopHeadlinesNewsEvent extends TopHeadlinesNewsEvent {
String toString() {
return 'ChangeCategoryTopHeadlinesNewsEvent{indexCategorySelected: $indexCategorySelected}';
}
}

class SearchTopHeadlinesNewsEvent extends TopHeadlinesNewsEvent {
final String keyword;

SearchTopHeadlinesNewsEvent({@required this.keyword});

@override
List<Object> get props => [keyword];

@override
String toString() {
return 'SearchTopHeadlinesNewsEvent{keyword: $keyword}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,18 @@ class ChangedCategoryTopHeadlinesNewsState extends TopHeadlinesNewsState {
String toString() {
return 'ChangedCategoryTopHeadlinesNewsState{indexCategorySelected: $indexCategorySelected}';
}
}

class SearchSuccessTopHeadlinesNewsState extends TopHeadlinesNewsState {
final List<ItemArticleTopHeadlinesNewsResponseModel> listArticles;

SearchSuccessTopHeadlinesNewsState({this.listArticles});

@override
List<Object> get props => [listArticles];

@override
String toString() {
return 'SearchSuccessTopHeadlinesNewsState{listArticles: $listArticles}';
}
}
Loading