Skip to content

Commit 65657a9

Browse files
authored
Merge pull request #27 from CoderJava/feature/searching-news
Feature Searching News
2 parents 4e84b42 + 68d39d4 commit 65657a9

File tree

18 files changed

+945
-212
lines changed

18 files changed

+945
-212
lines changed

lib/feature/data/datasource/news/news_remote_data_source.dart

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlin
44
import 'package:meta/meta.dart';
55

66
abstract class NewsRemoteDataSource {
7-
/// Calls the baseUrl:/v2/top-headlines?category=:category&country=:country&apiKey=:apiKey endpoint
7+
/// Calls the [baseUrl]/v2/top-headlines?category=:category&country=:country&apiKey=:apiKey endpoint
88
///
99
/// Throws a [DioError] for all error codes.
1010
Future<TopHeadlinesNewsResponseModel> getTopHeadlinesNews(String category);
11+
12+
/// Calls the [baseUrl]/v2/top-headlines?country=:country&apiKey=:apiKey&q=:q
13+
///
14+
/// Throws a [DioError] for all error codes.
15+
Future<TopHeadlinesNewsResponseModel> searchTopHeadlinesNews(String keyword);
1116
}
1217

1318
class NewsRemoteDataSourceImpl implements NewsRemoteDataSource {
@@ -46,4 +51,21 @@ class NewsRemoteDataSourceImpl implements NewsRemoteDataSource {
4651
throw DioError();
4752
}
4853
}
54+
55+
@override
56+
Future<TopHeadlinesNewsResponseModel> searchTopHeadlinesNews(String keyword) async {
57+
var response = await dio.get(
58+
'/v2/top-headlines',
59+
queryParameters: {
60+
'country': 'id',
61+
'apiKey': constantConfig.apiKeyNewsApi,
62+
'q': keyword,
63+
},
64+
);
65+
if (response.statusCode == 200) {
66+
return TopHeadlinesNewsResponseModel.fromJson(response.data);
67+
} else {
68+
throw DioError();
69+
}
70+
}
4971
}

lib/feature/data/repository/news/news_repository_impl.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,19 @@ class NewsRepositoryImpl implements NewsRepository {
3030
return Left(ConnectionFailure());
3131
}
3232
}
33+
34+
@override
35+
Future<Either<Failure, TopHeadlinesNewsResponseModel>> searchTopHeadlinesNews(String keyword) async {
36+
var isConnected = await networkInfo.isConnected;
37+
if (isConnected) {
38+
try {
39+
var response = await newsRemoteDataSource.searchTopHeadlinesNews(keyword);
40+
return Right(response);
41+
} on DioError catch (error) {
42+
return Left(ServerFailure(error.message));
43+
}
44+
} else {
45+
return Left(ConnectionFailure());
46+
}
47+
}
3348
}

lib/feature/domain/repository/news/news_repository.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ abstract class NewsRepository {
66

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

9+
Future<Either<Failure, TopHeadlinesNewsResponseModel>> searchTopHeadlinesNews(String keyword);
910
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'package:dartz/dartz.dart';
2+
import 'package:equatable/equatable.dart';
3+
import 'package:flutter_news_app/core/error/failure.dart';
4+
import 'package:flutter_news_app/feature/domain/repository/news/news_repository.dart';
5+
import 'package:meta/meta.dart';
6+
import 'package:flutter_news_app/core/usecase/usecase.dart';
7+
import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlines_news_response_model.dart';
8+
9+
class SearchTopHeadlinesNews implements UseCase<TopHeadlinesNewsResponseModel, ParamsSearchTopHeadlinesNews> {
10+
final NewsRepository newsRepository;
11+
12+
SearchTopHeadlinesNews({@required this.newsRepository});
13+
14+
@override
15+
Future<Either<Failure, TopHeadlinesNewsResponseModel>> call(ParamsSearchTopHeadlinesNews params) async {
16+
return await newsRepository.searchTopHeadlinesNews(params.keyword);
17+
}
18+
}
19+
20+
class ParamsSearchTopHeadlinesNews extends Equatable {
21+
final String keyword;
22+
23+
ParamsSearchTopHeadlinesNews({@required this.keyword});
24+
25+
@override
26+
List<Object> get props => [keyword];
27+
28+
@override
29+
String toString() {
30+
return 'ParamsSearchTopHeadlinesNews{keyword: $keyword}';
31+
}
32+
}

lib/feature/presentation/bloc/topheadlinesnews/top_headlines_news_bloc.dart

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@ import 'dart:async';
33
import 'package:bloc/bloc.dart';
44
import 'package:flutter_news_app/core/error/failure.dart';
55
import 'package:flutter_news_app/feature/domain/usecase/gettopheadlinesnews/get_top_headlines_news.dart';
6+
import 'package:flutter_news_app/feature/domain/usecase/searchtopheadlinesnews/search_top_headlines_news.dart';
67
import 'package:meta/meta.dart';
78

89
import './bloc.dart';
910

1011
class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsState> {
1112
final GetTopHeadlinesNews getTopHeadlinesNews;
13+
final SearchTopHeadlinesNews searchTopHeadlinesNews;
1214

13-
TopHeadlinesNewsBloc({@required this.getTopHeadlinesNews}) : assert(getTopHeadlinesNews != null);
15+
TopHeadlinesNewsBloc({
16+
@required this.getTopHeadlinesNews,
17+
@required this.searchTopHeadlinesNews,
18+
}) : assert(getTopHeadlinesNews != null),
19+
assert(searchTopHeadlinesNews != null);
1420

1521
@override
1622
TopHeadlinesNewsState get initialState => InitialTopHeadlinesNewsState();
@@ -23,6 +29,8 @@ class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsS
2329
yield* _mapLoadTopHeadlinesNewsEventToState(event);
2430
} else if (event is ChangeCategoryTopHeadlinesNewsEvent) {
2531
yield* _mapChangeCategoryTopHeadlinesNewsEventToState(event);
32+
} else if (event is SearchTopHeadlinesNewsEvent) {
33+
yield* _mapSearchTopHeadlinesNewsEventToState(event);
2634
}
2735
}
2836

@@ -47,4 +55,20 @@ class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsS
4755
) async* {
4856
yield ChangedCategoryTopHeadlinesNewsState(indexCategorySelected: event.indexCategorySelected);
4957
}
58+
59+
Stream<TopHeadlinesNewsState> _mapSearchTopHeadlinesNewsEventToState(SearchTopHeadlinesNewsEvent event) async* {
60+
yield LoadingTopHeadlinesNewsState();
61+
var result = await searchTopHeadlinesNews(ParamsSearchTopHeadlinesNews(keyword: event.keyword));
62+
yield result.fold(
63+
// ignore: missing_return
64+
(failure) {
65+
if (failure is ServerFailure) {
66+
return FailureTopHeadlinesNewsState(errorMessage: failure.errorMessage);
67+
} else if (failure is ConnectionFailure) {
68+
return FailureTopHeadlinesNewsState(errorMessage: failure.errorMessage);
69+
}
70+
},
71+
(response) => SearchSuccessTopHeadlinesNewsState(listArticles: response.articles),
72+
);
73+
}
5074
}

lib/feature/presentation/bloc/topheadlinesnews/top_headlines_news_event.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,18 @@ class ChangeCategoryTopHeadlinesNewsEvent extends TopHeadlinesNewsEvent {
3131
String toString() {
3232
return 'ChangeCategoryTopHeadlinesNewsEvent{indexCategorySelected: $indexCategorySelected}';
3333
}
34+
}
35+
36+
class SearchTopHeadlinesNewsEvent extends TopHeadlinesNewsEvent {
37+
final String keyword;
38+
39+
SearchTopHeadlinesNewsEvent({@required this.keyword});
40+
41+
@override
42+
List<Object> get props => [keyword];
43+
44+
@override
45+
String toString() {
46+
return 'SearchTopHeadlinesNewsEvent{keyword: $keyword}';
47+
}
3448
}

lib/feature/presentation/bloc/topheadlinesnews/top_headlines_news_state.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,18 @@ class ChangedCategoryTopHeadlinesNewsState extends TopHeadlinesNewsState {
5252
String toString() {
5353
return 'ChangedCategoryTopHeadlinesNewsState{indexCategorySelected: $indexCategorySelected}';
5454
}
55+
}
56+
57+
class SearchSuccessTopHeadlinesNewsState extends TopHeadlinesNewsState {
58+
final List<ItemArticleTopHeadlinesNewsResponseModel> listArticles;
59+
60+
SearchSuccessTopHeadlinesNewsState({this.listArticles});
61+
62+
@override
63+
List<Object> get props => [listArticles];
64+
65+
@override
66+
String toString() {
67+
return 'SearchSuccessTopHeadlinesNewsState{listArticles: $listArticles}';
68+
}
5569
}

0 commit comments

Comments
 (0)