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 b85ce98

Browse files
Create UI failure top headlines news
Create UI failure and refresh top headlines news
1 parent 6c27cd8 commit b85ce98

File tree

4 files changed

+202
-35
lines changed

4 files changed

+202
-35
lines changed

‎assets/svg/undraw_newspaper.svg‎

Lines changed: 1 addition & 0 deletions
Loading[フレーム]

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

Lines changed: 175 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import 'dart:async';
2+
import 'dart:io';
3+
14
import 'package:cached_network_image/cached_network_image.dart';
25
import 'package:flutter/cupertino.dart';
36
import 'package:flutter/material.dart';
@@ -7,6 +10,7 @@ import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlin
710
import 'package:flutter_news_app/feature/presentation/bloc/topheadlinesnews/bloc.dart';
811
import 'package:flutter_news_app/injection_container.dart';
912
import 'package:flutter_screenutil/flutter_screenutil.dart';
13+
import 'package:flutter_svg/flutter_svg.dart';
1014
import 'package:intl/intl.dart';
1115

1216
class HomePage extends StatefulWidget {
@@ -25,13 +29,25 @@ class _HomePageState extends State<HomePage> {
2529
CategoryNewsModel(image: 'assets/images/img_sport.png', title: 'Sport'),
2630
CategoryNewsModel(image: 'assets/images/img_technology.png', title: 'Technology'),
2731
];
32+
final refreshIndicatorState = GlobalKey<RefreshIndicatorState>();
33+
34+
bool isLoadingCenterIOS = false;
35+
Completer completerRefresh;
2836
var indexCategorySelected = 0;
2937

3038
@override
3139
void initState() {
32-
topHeadlinesNewsBloc.add(
33-
LoadTopHeadlinesNewsEvent(category: listCategories[indexCategorySelected].title.toLowerCase()),
34-
);
40+
WidgetsBinding.instance.addPostFrameCallback((_) {
41+
if (Platform.isIOS) {
42+
isLoadingCenterIOS = true;
43+
topHeadlinesNewsBloc.add(
44+
LoadTopHeadlinesNewsEvent(category: listCategories[indexCategorySelected].title.toLowerCase()),
45+
);
46+
} else {
47+
completerRefresh = Completer();
48+
refreshIndicatorState.currentState.show();
49+
}
50+
});
3551
super.initState();
3652
}
3753

@@ -46,7 +62,11 @@ class _HomePageState extends State<HomePage> {
4662
create: (context) => topHeadlinesNewsBloc,
4763
child: BlocListener<TopHeadlinesNewsBloc, TopHeadlinesNewsState>(
4864
listener: (context, state) {
49-
// TODO: handle listener state yang diperlukan
65+
if (state is FailureTopHeadlinesNewsState) {
66+
_resetRefreshIndicator();
67+
} else if (state is LoadedTopHeadlinesNewsState) {
68+
_resetRefreshIndicator();
69+
}
5070
},
5171
child: Container(
5272
width: double.infinity,
@@ -84,7 +104,7 @@ class _HomePageState extends State<HomePage> {
84104
_buildWidgetListCategory(),
85105
SizedBox(height: 24.h),
86106
Expanded(
87-
child: _buildWidgetContentNews(),
107+
child: Platform.isIOS ?_buildWidgetContentNewsIOS() :_buildWidgetContentNewsAndroid(),
88108
),
89109
SizedBox(height: paddingBottom),
90110
],
@@ -95,43 +115,163 @@ class _HomePageState extends State<HomePage> {
95115
);
96116
}
97117

98-
Widget _buildWidgetContentNews() {
118+
void _resetRefreshIndicator() {
119+
if (isLoadingCenterIOS) {
120+
isLoadingCenterIOS = false;
121+
}
122+
completerRefresh?.complete();
123+
completerRefresh = Completer();
124+
}
125+
126+
Widget _buildWidgetContentNewsIOS() {
99127
return BlocBuilder<TopHeadlinesNewsBloc, TopHeadlinesNewsState>(
100128
builder: (context, state) {
101-
if (state is LoadingTopHeadlinesNewsState) {
102-
return Center(
103-
child: CircularProgressIndicator(),
104-
);
105-
} else if (state is FailureTopHeadlinesNewsState) {
129+
var listArticles = <ItemArticleTopHeadlinesNewsResponseModel>[];
130+
if (state is LoadedTopHeadlinesNewsState) {
131+
listArticles.addAll(state.listArticles);
132+
} else if (isLoadingCenterIOS) {
106133
return Center(
107-
child: Text(state.errorMessage),
134+
child: CupertinoActivityIndicator(),
108135
);
109-
} else if (state is LoadedTopHeadlinesNewsState) {
110-
var listArticles = state.listArticles;
111-
return ListView.builder(
112-
padding: EdgeInsets.symmetric(horizontal: 48.w),
113-
itemBuilder: (context, index) {
114-
var itemArticle = listArticles[index];
115-
var dateTimePublishedAt = DateFormat('yyyy-MM-ddTHH:mm:ssZ').parse(itemArticle.publishedAt, true);
116-
var strPublishedAt = DateFormat('MMM dd, yyyy HH:mm').format(dateTimePublishedAt);
117-
if (index == 0) {
118-
return _buildWidgetItemLatestNews(itemArticle, strPublishedAt);
136+
}
137+
return Stack(
138+
children: <Widget>[
139+
Padding(
140+
padding: EdgeInsets.symmetric(horizontal: 48.w),
141+
child: CustomScrollView(
142+
physics: BouncingScrollPhysics(
143+
parent: AlwaysScrollableScrollPhysics(),
144+
),
145+
slivers: <Widget>[
146+
CupertinoSliverRefreshControl(
147+
onRefresh: () {
148+
topHeadlinesNewsBloc.add(
149+
LoadTopHeadlinesNewsEvent(category: listCategories[indexCategorySelected].title.toLowerCase()),
150+
);
151+
return completerRefresh.future;
152+
},
153+
),
154+
SliverList(
155+
delegate: SliverChildBuilderDelegate(
156+
(context, index) {
157+
var itemArticle = listArticles[index];
158+
var dateTimePublishedAt = DateFormat('yyyy-MM-ddTHH:mm:ssZ').parse(itemArticle.publishedAt, true);
159+
var strPublishedAt = DateFormat('MMM dd, yyyy HH:mm').format(dateTimePublishedAt);
160+
if (index == 0) {
161+
return _buildWidgetItemLatestNews(itemArticle, strPublishedAt);
162+
} else {
163+
return _buildWidgetItemNews(index, itemArticle, strPublishedAt);
164+
}
165+
},
166+
childCount: listArticles.length,
167+
),
168+
),
169+
],
170+
),
171+
),
172+
listArticles.isEmpty && state is! LoadingTopHeadlinesNewsState
173+
? _buildWidgetFailureLoadData()
174+
: Container(),
175+
],
176+
);
177+
},
178+
);
179+
}
180+
181+
Widget _buildWidgetContentNewsAndroid() {
182+
return BlocBuilder<TopHeadlinesNewsBloc, TopHeadlinesNewsState>(
183+
builder: (context, state) {
184+
var listArticles = <ItemArticleTopHeadlinesNewsResponseModel>[];
185+
if (state is LoadedTopHeadlinesNewsState) {
186+
listArticles.addAll(state.listArticles);
187+
}
188+
return Stack(
189+
children: <Widget>[
190+
RefreshIndicator(
191+
key: refreshIndicatorState,
192+
onRefresh: () {
193+
topHeadlinesNewsBloc.add(
194+
LoadTopHeadlinesNewsEvent(category: listCategories[indexCategorySelected].title.toLowerCase()),
195+
);
196+
return completerRefresh.future;
197+
},
198+
child: ListView.builder(
199+
padding: EdgeInsets.symmetric(horizontal: 48.w),
200+
itemBuilder: (context, index) {
201+
var itemArticle = listArticles[index];
202+
var dateTimePublishedAt = DateFormat('yyyy-MM-ddTHH:mm:ssZ').parse(itemArticle.publishedAt, true);
203+
var strPublishedAt = DateFormat('MMM dd, yyyy HH:mm').format(dateTimePublishedAt);
204+
if (index == 0) {
205+
return _buildWidgetItemLatestNews(itemArticle, strPublishedAt);
206+
} else {
207+
return _buildWidgetItemNews(index, itemArticle, strPublishedAt);
208+
}
209+
},
210+
itemCount: listArticles.length,
211+
),
212+
),
213+
listArticles.isEmpty && state is! LoadingTopHeadlinesNewsState
214+
? _buildWidgetFailureLoadData()
215+
: Container(),
216+
],
217+
);
218+
},
219+
);
220+
}
221+
222+
Widget _buildWidgetFailureLoadData() {
223+
return Center(
224+
child: Column(
225+
mainAxisAlignment: MainAxisAlignment.center,
226+
children: <Widget>[
227+
SvgPicture.asset(
228+
'assets/svg/undraw_newspaper.svg',
229+
width: ScreenUtil.screenWidthDp / 3,
230+
height: ScreenUtil.screenWidthDp / 3,
231+
),
232+
SizedBox(height: 24.h),
233+
Text(
234+
'You seem to be offline',
235+
style: TextStyle(
236+
fontSize: 48.sp,
237+
fontWeight: FontWeight.w500,
238+
),
239+
),
240+
Text(
241+
'Check your wi-fi connection or cellular data \nand try again.',
242+
style: TextStyle(
243+
fontSize: 36.sp,
244+
),
245+
textAlign: TextAlign.center,
246+
),
247+
RaisedButton(
248+
onPressed: () {
249+
if (Platform.isIOS) {
250+
isLoadingCenterIOS = true;
251+
topHeadlinesNewsBloc.add(
252+
LoadTopHeadlinesNewsEvent(category: listCategories[indexCategorySelected].title.toLowerCase()),
253+
);
119254
} else {
120-
return_buildWidgetItemNews(index, itemArticle, strPublishedAt);
255+
refreshIndicatorState.currentState.show();
121256
}
122257
},
123-
itemCount: listArticles.length,
124-
);
125-
} else {
126-
return Container();
127-
}
128-
},
258+
child: Text(
259+
'Try Again'.toUpperCase(),
260+
style: TextStyle(
261+
color: Colors.white,
262+
fontSize: 36.sp,
263+
),
264+
),
265+
color: Colors.grey[700],
266+
),
267+
],
268+
),
129269
);
130270
}
131271

132272
Widget _buildWidgetItemNews(
133273
int index,
134-
ItemArticleTopHeadlinesNewsResponseModel itemArticleTopHeadlinesNewsResponseModel,
274+
ItemArticleTopHeadlinesNewsResponseModel itemArticle,
135275
String strPublishedAt,
136276
) {
137277
return Padding(
@@ -147,7 +287,7 @@ class _HomePageState extends State<HomePage> {
147287
ClipRRect(
148288
borderRadius: BorderRadius.circular(8.0),
149289
child: CachedNetworkImage(
150-
imageUrl: itemArticleTopHeadlinesNewsResponseModel.urlToImage,
290+
imageUrl: itemArticle.urlToImage,
151291
fit: BoxFit.cover,
152292
width: 200.w,
153293
height: 200.w,
@@ -182,18 +322,18 @@ class _HomePageState extends State<HomePage> {
182322
children: <Widget>[
183323
Expanded(
184324
child: Text(
185-
itemArticleTopHeadlinesNewsResponseModel.title,
325+
itemArticle.title,
186326
maxLines: 2,
187327
overflow: TextOverflow.ellipsis,
188328
style: TextStyle(
189329
fontSize: 36.sp,
190330
),
191331
),
192332
),
193-
itemArticleTopHeadlinesNewsResponseModel.author == null
333+
itemArticle.author == null
194334
? Container()
195335
: Text(
196-
itemArticleTopHeadlinesNewsResponseModel.author,
336+
itemArticle.author,
197337
style: TextStyle(
198338
color: Colors.grey,
199339
fontSize: 28.sp,
@@ -217,7 +357,7 @@ class _HomePageState extends State<HomePage> {
217357
),
218358
),
219359
Text(
220-
itemArticleTopHeadlinesNewsResponseModel.source.name,
360+
itemArticle.source.name,
221361
style: TextStyle(
222362
color: Colors.grey,
223363
fontSize: 24.sp,

‎pubspec.lock‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,13 @@ packages:
279279
url: "https://pub.dartlang.org"
280280
source: hosted
281281
version: "0.5.2"
282+
flutter_svg:
283+
dependency: "direct main"
284+
description:
285+
name: flutter_svg
286+
url: "https://pub.dartlang.org"
287+
source: hosted
288+
version: "0.17.4"
282289
flutter_test:
283290
dependency: "direct dev"
284291
description: flutter
@@ -464,6 +471,20 @@ packages:
464471
url: "https://pub.dartlang.org"
465472
source: hosted
466473
version: "1.6.4"
474+
path_drawing:
475+
dependency: transitive
476+
description:
477+
name: path_drawing
478+
url: "https://pub.dartlang.org"
479+
source: hosted
480+
version: "0.4.1"
481+
path_parsing:
482+
dependency: transitive
483+
description:
484+
name: path_parsing
485+
url: "https://pub.dartlang.org"
486+
source: hosted
487+
version: "0.1.4"
467488
path_provider:
468489
dependency: transitive
469490
description:

0 commit comments

Comments
(0)

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