Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4e84b42

Browse files
Merge pull request #25 from CoderJava/feature/select-category-news
Create feature Change Category Top Headlines News
2 parents 89418a8 + 2e5c87f commit 4e84b42

File tree

7 files changed

+156
-17
lines changed

7 files changed

+156
-17
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsS
2121
) async* {
2222
if (event is LoadTopHeadlinesNewsEvent) {
2323
yield* _mapLoadTopHeadlinesNewsEventToState(event);
24+
} else if (event is ChangeCategoryTopHeadlinesNewsEvent) {
25+
yield* _mapChangeCategoryTopHeadlinesNewsEventToState(event);
2426
}
2527
}
2628

@@ -39,4 +41,10 @@ class TopHeadlinesNewsBloc extends Bloc<TopHeadlinesNewsEvent, TopHeadlinesNewsS
3941
(data) => LoadedTopHeadlinesNewsState(listArticles: data.articles),
4042
);
4143
}
44+
45+
Stream<TopHeadlinesNewsState> _mapChangeCategoryTopHeadlinesNewsEventToState(
46+
ChangeCategoryTopHeadlinesNewsEvent event,
47+
) async* {
48+
yield ChangedCategoryTopHeadlinesNewsState(indexCategorySelected: event.indexCategorySelected);
49+
}
4250
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,18 @@ class LoadTopHeadlinesNewsEvent extends TopHeadlinesNewsEvent {
1717
String toString() {
1818
return 'LoadTopHeadlinesNewsEvent{category: $category}';
1919
}
20+
}
21+
22+
class ChangeCategoryTopHeadlinesNewsEvent extends TopHeadlinesNewsEvent {
23+
final int indexCategorySelected;
24+
25+
ChangeCategoryTopHeadlinesNewsEvent({@required this.indexCategorySelected});
26+
27+
@override
28+
List<Object> get props => [indexCategorySelected];
29+
30+
@override
31+
String toString() {
32+
return 'ChangeCategoryTopHeadlinesNewsEvent{indexCategorySelected: $indexCategorySelected}';
33+
}
2034
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,18 @@ class FailureTopHeadlinesNewsState extends TopHeadlinesNewsState {
3838
String toString() {
3939
return 'FailureTopHeadlinesNewsState{errorMessage: $errorMessage}';
4040
}
41+
}
42+
43+
class ChangedCategoryTopHeadlinesNewsState extends TopHeadlinesNewsState {
44+
final int indexCategorySelected;
45+
46+
ChangedCategoryTopHeadlinesNewsState({this.indexCategorySelected});
47+
48+
@override
49+
List<Object> get props => [indexCategorySelected];
50+
51+
@override
52+
String toString() {
53+
return 'ChangedCategoryTopHeadlinesNewsState{indexCategorySelected: $indexCategorySelected}';
54+
}
4155
}

‎lib/feature/presentation/page/home/home_page.dart‎

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class _HomePageState extends State<HomePage> {
2626
CategoryNewsModel(image: 'assets/images/img_entertainment.png', title: 'Entertainment'),
2727
CategoryNewsModel(image: 'assets/images/img_health.png', title: 'Health'),
2828
CategoryNewsModel(image: 'assets/images/img_science.png', title: 'Science'),
29-
CategoryNewsModel(image: 'assets/images/img_sport.png', title: 'Sport'),
29+
CategoryNewsModel(image: 'assets/images/img_sport.png', title: 'Sports'),
3030
CategoryNewsModel(image: 'assets/images/img_technology.png', title: 'Technology'),
3131
];
3232
final refreshIndicatorState = GlobalKey<RefreshIndicatorState>();
@@ -66,6 +66,15 @@ class _HomePageState extends State<HomePage> {
6666
_resetRefreshIndicator();
6767
} else if (state is LoadedTopHeadlinesNewsState) {
6868
_resetRefreshIndicator();
69+
} else if (state is ChangedCategoryTopHeadlinesNewsState) {
70+
indexCategorySelected = state.indexCategorySelected;
71+
if (Platform.isIOS) {
72+
isLoadingCenterIOS = true;
73+
var category = listCategories[indexCategorySelected].title.toLowerCase();
74+
topHeadlinesNewsBloc.add(LoadTopHeadlinesNewsEvent(category: category));
75+
} else {
76+
refreshIndicatorState.currentState.show();
77+
}
6978
}
7079
},
7180
child: Container(
@@ -101,7 +110,7 @@ class _HomePageState extends State<HomePage> {
101110
),
102111
WidgetDateToday(),
103112
SizedBox(height: 24.h),
104-
_buildWidgetListCategory(),
113+
WidgetCategoryNews(listCategories: listCategories),
105114
SizedBox(height: 24.h),
106115
Expanded(
107116
child: Platform.isIOS ? _buildWidgetContentNewsIOS() : _buildWidgetContentNewsAndroid(),
@@ -181,6 +190,7 @@ class _HomePageState extends State<HomePage> {
181190
Widget _buildWidgetContentNewsAndroid() {
182191
return BlocBuilder<TopHeadlinesNewsBloc, TopHeadlinesNewsState>(
183192
builder: (context, state) {
193+
debugPrint('state: $state');
184194
var listArticles = <ItemArticleTopHeadlinesNewsResponseModel>[];
185195
if (state is LoadedTopHeadlinesNewsState) {
186196
listArticles.addAll(state.listArticles);
@@ -210,7 +220,7 @@ class _HomePageState extends State<HomePage> {
210220
itemCount: listArticles.length,
211221
),
212222
),
213-
listArticles.isEmpty && state is!LoadingTopHeadlinesNewsState
223+
listArticles.isEmpty && state isFailureTopHeadlinesNewsState
214224
? _buildWidgetFailureLoadData()
215225
: Container(),
216226
],
@@ -474,26 +484,50 @@ class _HomePageState extends State<HomePage> {
474484
),
475485
);
476486
}
487+
}
488+
489+
class WidgetCategoryNews extends StatefulWidget {
490+
final List<CategoryNewsModel> listCategories;
491+
492+
WidgetCategoryNews({@required this.listCategories});
493+
494+
@override
495+
_WidgetCategoryNewsState createState() => _WidgetCategoryNewsState();
496+
}
497+
498+
class _WidgetCategoryNewsState extends State<WidgetCategoryNews> {
499+
int indexCategorySelected;
500+
501+
@override
502+
void initState() {
503+
indexCategorySelected = 0;
504+
super.initState();
505+
}
477506

478-
Widget _buildWidgetListCategory() {
507+
@override
508+
Widget build(BuildContext context) {
479509
return SizedBox(
480510
height: 100.h,
481511
child: ListView.builder(
482512
padding: EdgeInsets.symmetric(horizontal: 48.w),
483513
scrollDirection: Axis.horizontal,
484514
itemBuilder: (context, index) {
485-
var itemCategory = listCategories[index];
515+
var itemCategory = widget.listCategories[index];
486516
return Padding(
487517
padding: EdgeInsets.only(
488518
left: index == 0 ? 0 : 12.w,
489-
right: index == listCategories.length - 1 ? 0 : 12.w,
519+
right: index == widget.listCategories.length - 1 ? 0 : 12.w,
490520
),
491521
child: GestureDetector(
492522
onTap: () {
493-
// TODO: buat fitur pilih category
523+
if (indexCategorySelected == index) {
524+
return;
525+
}
494526
setState(() {
495527
indexCategorySelected = index;
496528
});
529+
var topHeadlinesNewsBloc = BlocProvider.of<TopHeadlinesNewsBloc>(context);
530+
topHeadlinesNewsBloc.add(ChangeCategoryTopHeadlinesNewsEvent(indexCategorySelected: indexCategorySelected));
497531
},
498532
child: Container(
499533
child: AnimatedContainer(
@@ -508,9 +542,9 @@ class _HomePageState extends State<HomePage> {
508542
),
509543
border: indexCategorySelected == index
510544
? Border.all(
511-
color: Colors.white,
512-
width: 2.0,
513-
)
545+
color: Colors.white,
546+
width: 2.0,
547+
)
514548
: null,
515549
),
516550
child: Center(
@@ -528,22 +562,23 @@ class _HomePageState extends State<HomePage> {
528562
image: itemCategory.title.toLowerCase() == 'all'
529563
? null
530564
: DecorationImage(
531-
image: AssetImage(
532-
itemCategory.image,
533-
),
534-
fit: BoxFit.cover,
535-
),
565+
image: AssetImage(
566+
itemCategory.image,
567+
),
568+
fit: BoxFit.cover,
569+
),
536570
),
537571
),
538572
),
539573
);
540574
},
541-
itemCount: listCategories.length,
575+
itemCount: widget.listCategories.length,
542576
),
543577
);
544578
}
545579
}
546580

581+
547582
class WidgetDateToday extends StatefulWidget {
548583
@override
549584
_WidgetDateTodayState createState() => _WidgetDateTodayState();

‎test/feature/presentation/bloc/topheadlinesnews/top_headlines_news_bloc_test.dart‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,20 @@ void main() {
140140
verify(mockGetTopHeadlinesNews(ParamsGetTopHeadlinesNews(category: tCategory))).called(1);
141141
});
142142
});
143+
144+
group('ChangeCategoryTopHeadlinesNews', () {
145+
blocTest(
146+
'make sure to emit [ChangedCategoryTopHeadlinesNewsState] when receive ChangeCategoryTopHeadlinesNewsEvent with '
147+
'a successful process',
148+
build: () async {
149+
return topHeadlinesNewsBloc;
150+
},
151+
act: (bloc) {
152+
return bloc.add(ChangeCategoryTopHeadlinesNewsEvent(indexCategorySelected: 1));
153+
},
154+
expect: [
155+
ChangedCategoryTopHeadlinesNewsState(indexCategorySelected: 1),
156+
],
157+
);
158+
});
143159
}

‎test/feature/presentation/bloc/topheadlinesnews/top_headlines_news_event_test.dart‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ void main() {
66
final tCategory = 'technology';
77

88
test(
9-
'make sure the props value is []',
9+
'make sure the props value is [category]',
1010
() async {
1111
// assert
1212
expect(LoadTopHeadlinesNewsEvent(category: tCategory).props, [tCategory]);
@@ -24,4 +24,30 @@ void main() {
2424
},
2525
);
2626
});
27+
28+
group('ChangeCategoryTopHeadlinesNews', () {
29+
final tChangeCategoryTopHeadlinesNewsEvent = ChangeCategoryTopHeadlinesNewsEvent(indexCategorySelected: 0);
30+
31+
test(
32+
'make sure the props value is [indexCategorySelected]',
33+
() async {
34+
// assert
35+
expect(
36+
tChangeCategoryTopHeadlinesNewsEvent.props,
37+
[tChangeCategoryTopHeadlinesNewsEvent.indexCategorySelected],
38+
);
39+
},
40+
);
41+
42+
test(
43+
'make sure the output of the toString function',
44+
() async {
45+
// assert
46+
expect(
47+
tChangeCategoryTopHeadlinesNewsEvent.toString(),
48+
'ChangeCategoryTopHeadlinesNewsEvent{indexCategorySelected: ${tChangeCategoryTopHeadlinesNewsEvent.indexCategorySelected}}',
49+
);
50+
},
51+
);
52+
});
2753
}

‎test/feature/presentation/bloc/topheadlinesnews/top_headlines_news_state_test.dart‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,30 @@ void main() {
8989
},
9090
);
9191
});
92+
93+
group('ChangedCategoryTopHeadlinesNewsState', () {
94+
final tChangedCategoryTopHeadlinesNewsState = ChangedCategoryTopHeadlinesNewsState(indexCategorySelected: 1);
95+
96+
test(
97+
'make sure the props value is [indexCategorySelected]',
98+
() async {
99+
// assert
100+
expect(
101+
tChangedCategoryTopHeadlinesNewsState.props,
102+
[tChangedCategoryTopHeadlinesNewsState.indexCategorySelected],
103+
);
104+
},
105+
);
106+
107+
test(
108+
'make sure the output of the toString function',
109+
() async {
110+
// assert
111+
expect(
112+
tChangedCategoryTopHeadlinesNewsState.toString(),
113+
'ChangedCategoryTopHeadlinesNewsState{indexCategorySelected: ${tChangedCategoryTopHeadlinesNewsState.indexCategorySelected}}',
114+
);
115+
},
116+
);
117+
});
92118
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /