From f1ad11dcc6275714e19fce0bbb2933dc6a53ca95 Mon Sep 17 00:00:00 2001 From: Yudi Setiawan Date: Fri, 29 May 2020 13:20:28 +0700 Subject: [PATCH] Create detail news feature --- .../presentation/page/home/home_page.dart | 107 +++++---- .../presentation/page/search/search_page.dart | 213 +++++++++--------- .../presentation/widget/widget_item_news.dart | 11 +- pubspec.yaml | 7 - 4 files changed, 179 insertions(+), 159 deletions(-) diff --git a/lib/feature/presentation/page/home/home_page.dart b/lib/feature/presentation/page/home/home_page.dart index d05cc1b..eea2dca 100644 --- a/lib/feature/presentation/page/home/home_page.dart +++ b/lib/feature/presentation/page/home/home_page.dart @@ -13,6 +13,7 @@ import 'package:flutter_news_app/feature/presentation/widget/widget_item_news.da import 'package:flutter_news_app/injection_container.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:intl/intl.dart'; +import 'package:url_launcher/url_launcher.dart'; class HomePage extends StatefulWidget { @override @@ -55,9 +56,6 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { ScreenUtil.init(context); - var mediaQueryData = MediaQuery.of(context); - var paddingTop = mediaQueryData.padding.top; - var paddingBottom = mediaQueryData.padding.bottom; return Scaffold( body: BlocProvider( create: (context) => topHeadlinesNewsBloc, @@ -78,53 +76,62 @@ class _HomePageState extends State { } } }, - child: Container( - width: double.infinity, - color: Color(0xFFEFF5F5), - padding: EdgeInsets.symmetric( - vertical: 24.h, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: paddingTop), - Padding( - padding: EdgeInsets.symmetric(horizontal: 48.w), - child: Row( + child: Stack( + children: [ + Container( + width: double.infinity, + height: double.infinity, + color: Color(0xFFEFF5F5), + ), + SafeArea( + child: Container( + width: double.infinity, + color: Color(0xFFEFF5F5), + padding: EdgeInsets.symmetric( + vertical: 24.h, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - child: Text( - 'Daily News', - style: TextStyle( - fontSize: 48.sp, - ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 48.w), + child: Row( + children: [ + Expanded( + child: Text( + 'Daily News', + style: TextStyle( + fontSize: 48.sp, + ), + ), + ), + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => SearchPage()), + ); + }, + child: Hero( + tag: 'iconSearch', + child: Icon(Icons.search), + ), + ), + ], ), ), - GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => SearchPage()), - ); - }, - child: Hero( - tag: 'iconSearch', - child: Icon(Icons.search), - ), + WidgetDateToday(), + SizedBox(height: 24.h), + WidgetCategoryNews(listCategories: listCategories), + SizedBox(height: 24.h), + Expanded( + child: Platform.isIOS ? _buildWidgetContentNewsIOS() : _buildWidgetContentNewsAndroid(), ), ], ), ), - WidgetDateToday(), - SizedBox(height: 24.h), - WidgetCategoryNews(listCategories: listCategories), - SizedBox(height: 24.h), - Expanded( - child: Platform.isIOS ? _buildWidgetContentNewsIOS() : _buildWidgetContentNewsAndroid(), - ), - SizedBox(height: paddingBottom), - ], - ), + ), + ], ), ), ), @@ -287,12 +294,18 @@ class _HomePageState extends State { String strPublishedAt, ) { return GestureDetector( - onTap: () { - // TODO: buat fitur arahkan ke website detail berita + onTap: () async { + if (await canLaunch(itemArticle.url)) { + await launch(itemArticle.url); + } else { + Scaffold.of(context).showSnackBar(SnackBar( + content: Text('Couldn\'t open detail news'), + )); + } }, child: Container( width: double.infinity, - height: ScreenUtil.screenHeightDp / 3, + height: ScreenUtil.screenWidthDp / 1.7, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.0), image: DecorationImage( @@ -306,7 +319,7 @@ class _HomePageState extends State { children: [ Container( width: double.infinity, - height: ScreenUtil.screenHeightDp / 3, + height: ScreenUtil.screenWidthDp / 1.7, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.0), gradient: LinearGradient( diff --git a/lib/feature/presentation/page/search/search_page.dart b/lib/feature/presentation/page/search/search_page.dart index ef7221a..7c7a2ff 100644 --- a/lib/feature/presentation/page/search/search_page.dart +++ b/lib/feature/presentation/page/search/search_page.dart @@ -42,119 +42,126 @@ class _SearchPageState extends State { @override Widget build(BuildContext context) { ScreenUtil.init(context); - var mediaQueryData = MediaQuery.of(context); - var paddingTop = mediaQueryData.padding.top; - var paddingBottom = mediaQueryData.padding.bottom; return Scaffold( body: BlocProvider( create: (context) => topHeadlinesNewsBloc, - child: Container( - color: Color(0xFFEFF5F5), - width: double.infinity, - padding: EdgeInsets.symmetric( - horizontal: 48.w, - vertical: 24.h, - ), - child: Column( - children: [ - SizedBox(height: paddingTop), - Row( - children: [ - GestureDetector( - onTap: () { - Navigator.pop(context); - }, - child: Icon( - Platform.isIOS ? Icons.arrow_back_ios : Icons.arrow_back, - ), - ), - SizedBox(width: 24.w), - Expanded( - child: Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.grey), - borderRadius: BorderRadius.circular(99.0), - ), - padding: EdgeInsets.symmetric(horizontal: 36.w), - child: Row( - children: [ - Expanded( - child: TextField( - controller: controllerKeyword, - decoration: InputDecoration( - isDense: true, - hintText: 'Searching something?', - hintStyle: TextStyle( - fontSize: 36.sp, - color: Colors.grey, - ), - enabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - ), - style: TextStyle( - fontSize: 36.sp, - ), - ), + child: Stack( + children: [ + Container( + width: double.infinity, + height: double.infinity, + color: Color(0xFFEFF5F5), + ), + SafeArea( + child: Container( + color: Color(0xFFEFF5F5), + width: double.infinity, + padding: EdgeInsets.symmetric( + vertical: 24.h, + horizontal: 48.w, + ), + child: Column( + children: [ + Row( + children: [ + GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon( + Platform.isIOS ? Icons.arrow_back_ios : Icons.arrow_back, ), - Hero( - tag: 'iconSearch', - child: Focus( - focusNode: focusNodeIconSearch, - child: Icon( - Icons.search, - size: 48.w, - ), + ), + SizedBox(width: 24.w), + Expanded( + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(99.0), + ), + padding: EdgeInsets.symmetric(horizontal: 36.w), + child: Row( + children: [ + Expanded( + child: TextField( + controller: controllerKeyword, + decoration: InputDecoration( + isDense: true, + hintText: 'Searching something?', + hintStyle: TextStyle( + fontSize: 36.sp, + color: Colors.grey, + ), + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + ), + style: TextStyle( + fontSize: 36.sp, + ), + ), + ), + Hero( + tag: 'iconSearch', + child: Focus( + focusNode: focusNodeIconSearch, + child: Icon( + Icons.search, + size: 48.w, + ), + ), + ), + ], ), ), - ], - ), + ), + ], ), - ), - ], - ), - SizedBox(height: 16.h), - Expanded( - child: BlocBuilder( - builder: (context, state) { - if (state is LoadingTopHeadlinesNewsState) { - return Center( - child: Platform.isIOS ? CupertinoActivityIndicator() : CircularProgressIndicator(), - ); - } else if (state is FailureTopHeadlinesNewsState) { - return WidgetFailureMessage(); - } else if (state is SearchSuccessTopHeadlinesNewsState) { - var listArticles = state.listArticles; - if (listArticles.isEmpty) { - return WidgetFailureMessage( - errorTitle: 'Data not found', - errorSubtitle: 'Hm, we couldn\'t find what you were looking for.', - ); - } else { - return ListView.builder( - padding: EdgeInsets.only(bottom: paddingBottom), - itemBuilder: (context, index) { - var itemArticle = listArticles[index]; - var dateTimePublishedAt = - DateFormat('yyy-MM-ddTHH:mm:ssZ').parse(itemArticle.publishedAt, true); - var strPublishedAt = DateFormat('MMM dd, yyyy HH:mm').format(dateTimePublishedAt); - return Padding( - padding: EdgeInsets.symmetric(vertical: 16.h), - child: WidgetItemNews( - itemArticle: itemArticle, - strPublishedAt: strPublishedAt, - ), + SizedBox(height: 16.h), + Expanded( + child: BlocBuilder( + builder: (context, state) { + if (state is LoadingTopHeadlinesNewsState) { + return Center( + child: Platform.isIOS ? CupertinoActivityIndicator() : CircularProgressIndicator(), ); - }, - itemCount: listArticles.length, - ); - } - } - return Container(); - }, + } else if (state is FailureTopHeadlinesNewsState) { + return WidgetFailureMessage(); + } else if (state is SearchSuccessTopHeadlinesNewsState) { + var listArticles = state.listArticles; + if (listArticles.isEmpty) { + return WidgetFailureMessage( + errorTitle: 'Data not found', + errorSubtitle: 'Hm, we couldn\'t find what you were looking for.', + ); + } else { + return ListView.builder( + padding: EdgeInsets.zero, + itemBuilder: (context, index) { + var itemArticle = listArticles[index]; + var dateTimePublishedAt = + DateFormat('yyy-MM-ddTHH:mm:ssZ').parse(itemArticle.publishedAt, true); + var strPublishedAt = DateFormat('MMM dd, yyyy HH:mm').format(dateTimePublishedAt); + return Padding( + padding: EdgeInsets.symmetric(vertical: 16.h), + child: WidgetItemNews( + itemArticle: itemArticle, + strPublishedAt: strPublishedAt, + ), + ); + }, + itemCount: listArticles.length, + ); + } + } + return Container(); + }, + ), + ), + ], ), ), - ], - ), + ), + ], ), ), ); diff --git a/lib/feature/presentation/widget/widget_item_news.dart b/lib/feature/presentation/widget/widget_item_news.dart index 5280b8d..111e26c 100644 --- a/lib/feature/presentation/widget/widget_item_news.dart +++ b/lib/feature/presentation/widget/widget_item_news.dart @@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlines_news_response_model.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:url_launcher/url_launcher.dart'; class WidgetItemNews extends StatelessWidget { final ItemArticleTopHeadlinesNewsResponseModel itemArticle; @@ -16,8 +17,14 @@ class WidgetItemNews extends StatelessWidget { Widget build(BuildContext context) { ScreenUtil.init(context); return GestureDetector( - onTap: () { - // TODO: buat fitur arahkan ke website detail berita + onTap: () async { + if (await canLaunch(itemArticle.url)) { + await launch(itemArticle.url); + } else { + Scaffold.of(context).showSnackBar(SnackBar( + content: Text('Couldn\'t open detail news'), + )); + } }, child: SizedBox( height: 200.w, diff --git a/pubspec.yaml b/pubspec.yaml index 0003840..0db22d9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -82,15 +82,8 @@ dev_dependencies: flutter: - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg assets: - assets/images/ - assets/svg/