Skip to content

Instantly share code, notes, and snippets.

@h4040
Created May 24, 2018 02:19
Show Gist options
  • Save h4040/385a113b9d94cfaa5273a99a910df3d3 to your computer and use it in GitHub Desktop.
Save h4040/385a113b9d94cfaa5273a99a910df3d3 to your computer and use it in GitHub Desktop.
NewsReader
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:intl/intl.dart';
import 'dart:async';
import 'dart:collection';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:share/share.dart' as sharing;
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
enum LastUserAction { search, categories, customNews, news, topNews, myFeed }
enum TextSize { small, medium, big, huge }
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
static const String FAVORITE_NEWS_SOURCES = "FAVORITE_NEWS_SOURCES";
static const String FAVORITE_NEWS_SOURCES_ID = "FAVORITE_NEWS_SOURCES_ID";
static const String CUSTOM_NEWS_SOURCES = "CUSTOM_NEWS_SOURCES";
static const String BREAKING_NEWS = "Breaking News";
static const String MY_FEED = "My Feed";
static const String WHATS_NEW = "WHATS_NEW_V6"; // TODO: Change me on new release!
String selectedNewsSourceId = "";
String appBarTitle = "";
static MyThemes currentSelectedTheme = MyThemes.defaultDark;
static Country currentSelectedCountry = Country.USA;
DateTime timeOfAppPaused;
bool shouldShowHelpText = false;
bool noServerConnForNewsStories = false;
bool noServerConnForNewsSources = false;
bool isValidCustomNewsSource = true;
bool noFavoriteNewsSourcesSelected = false;
List newsSourcesArray = [];
List newsStoriesArray = [];
List<String> favoriteNewsSources = new List<String>();
List<String> favoriteNewsSourcesId = new List<String>();
List<String> customNewsSources = new List<String>();
HashSet<String> newsSourcesIdSet = new HashSet();
LastUserAction lastUserAction = LastUserAction.topNews;
// used to highlight currently selected news source listTile
String _selectedNewsSource = "${getCurrentCountry().toUpperCase()} $BREAKING_NEWS";
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey();
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
new GlobalKey<RefreshIndicatorState>();
ScrollController _scrollController = new ScrollController();
TextEditingController _seachTextFieldController = new TextEditingController();
SharedPreferences prefs;
String userAgent =
"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Mobile Safari/537.36";
final FlutterWebviewPlugin flutterWebviewPlugin = new FlutterWebviewPlugin();
bool isWebViewOpen = false;
double appbarHeight = 0.0;
static Map<TextSize, double> textSizes = Map<TextSize, double>();
static double adjustedFontSize = 0.0;
@override
void initState() {
super.initState();
textSizes.putIfAbsent(TextSize.small, () => 14.0);
textSizes.putIfAbsent(TextSize.medium, () => 16.0);
textSizes.putIfAbsent(TextSize.big, () => 20.0);
textSizes.putIfAbsent(TextSize.huge, () => 26.0);
WidgetsBinding.instance.addObserver(this); // used for detecting app lifecycle
initSharedPreferences()
.then((_) => getFontSizeSelectionFromDisk())
.then((_) => getWhatsNewBoolFromDisk())
.then((_) => getCountrySelectionFromDisk())
.then((_) => initSelectedNewsSourceVar())
.then((_) => setAppBarTitle())
.then((_) => loadTopHeadlines())
.then((_) => getFavoriteNewsSourcesFromDisk())
.then((_) => getFavoriteNewsSourcesIdFromDisk())
.then((_) => loadNewsSources())
.then((_) => getCustomNewsSourcesFromDisk())
.then((_) => addCustomNewsSourcesToNewsSourcesArray())
.then((_) => addFavoriteNewsSourcesToNewsSourcesArray())
.then((_) => sortNewsSourcesArray())
.then((_) => getThemeSelectionFromDisk());
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
flutterWebviewPlugin.dispose();
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (AppLifecycleState.resumed == state) {
// only refresh news stories if 10mins have passed since app was paused
DateTime now = new DateTime.now();
Duration timeSinceAppWasPaused = now.difference(timeOfAppPaused);
if (timeSinceAppWasPaused.inMinutes >= 10) _refreshIndicatorKey.currentState.show();
} else if (AppLifecycleState.paused == state)
// save current time to memory
timeOfAppPaused = new DateTime.now();
}
/*
* HTTP METHODS BEGIN
*/
loadNewsStoriesFromCustomSource() async {
noFavoriteNewsSourcesSelected = false;
if (newsStoriesArray != null) setState(() => newsStoriesArray.clear());
String dataUrl = "https://newsapi.org/v2/everything?domains=" +
selectedNewsSourceId.toLowerCase() +
"&apiKey=a30edf50cbbb48049945142f004c36c3";
http.Response response = await http.get(dataUrl);
if (response.statusCode == 200) {
Map<String, dynamic> newsStories = json.decode(response.body);
if (newsStories['totalResults'] == 0) {
setState(() {
isValidCustomNewsSource = false;
});
} else {
setState(() {
isValidCustomNewsSource = true;
newsStoriesArray = newsStories['articles'];
});
}
} else {
setState(() {
noServerConnForNewsStories = true;
});
}
}
loadTopHeadlines() async {
isValidCustomNewsSource = true;
noFavoriteNewsSourcesSelected = false;
if (newsStoriesArray != null) setState(() => newsStoriesArray.clear());
String dataUrl =
"https://newsapi.org/v2/top-headlines?country=${getCurrentCountry()}&apiKey=a30edf50cbbb48049945142f004c36c3";
http.Response response = await http.get(dataUrl);
if (response.statusCode == 200) {
Map<String, dynamic> newsStories = json.decode(response.body);
setState(() {
noServerConnForNewsStories = false;
newsStoriesArray = newsStories['articles'];
});
} else {
setState(() {
noServerConnForNewsStories = true;
});
}
}
loadNewsSources() async {
isValidCustomNewsSource = true;
newsSourcesArray ?? newsSourcesArray.clear;
newsSourcesIdSet.clear();
String dataUrl =
"https://newsapi.org/v2/sources?&country=${getCurrentCountry()}&apiKey=a30edf50cbbb48049945142f004c36c3";
http.Response response = await http.get(dataUrl);
if (response.statusCode == 200) {
Map<String, dynamic> newsSources = json.decode(response.body);
setState(() {
newsSourcesArray = newsSources['sources'];
noServerConnForNewsSources = false;
});
for (LinkedHashMap source in newsSourcesArray) {
newsSourcesIdSet.add(source['id']);
}
} else {
setState(() {
noServerConnForNewsSources = true;
});
}
}
loadNewsStories() async {
isValidCustomNewsSource = true;
noFavoriteNewsSourcesSelected = false;
if (newsStoriesArray != null) setState(() => newsStoriesArray.clear());
String dataUrl = "https://newsapi.org/v2/top-headlines?sources=" +
selectedNewsSourceId +
"&apiKey=a30edf50cbbb48049945142f004c36c3";
http.Response response = await http.get(dataUrl);
if (response.statusCode == 200) {
Map<String, dynamic> newsStories = json.decode(response.body);
setState(() {
noServerConnForNewsStories = false;
newsStoriesArray = newsStories['articles'];
});
} else {
setState(() {
noServerConnForNewsStories = true;
});
}
}
loadMyFeed() async {
isValidCustomNewsSource = true;
noFavoriteNewsSourcesSelected = false;
if (newsStoriesArray != null) setState(() => newsStoriesArray.clear());
if (favoriteNewsSourcesId.length == 0) {
setState(() {
noFavoriteNewsSourcesSelected = true;
});
return;
}
StringBuffer sourcesBuffer = StringBuffer(); // pre-defined sources from newsapi.org
StringBuffer domainsBuffer = StringBuffer(); // custom news sources
for (int i = 0; i < favoriteNewsSourcesId.length; i++) {
String newsSource = favoriteNewsSourcesId[i];
if (customNewsSources.contains(newsSource)) {
domainsBuffer.write("$newsSource,");
} else {
sourcesBuffer.write("$newsSource,");
}
}
String sources = sourcesBuffer.toString();
String domains = domainsBuffer.toString().toLowerCase();
if (sources.length > 0)
sources = sources.substring(0, sources.length - 1); // remove trailing comma
if (domains.length > 0) domains = domains.substring(0, domains.length - 1);
String dataUrl =
"https://newsapi.org/v2/everything?sources=$sources&domains=$domains&apiKey=a30edf50cbbb48049945142f004c36c3";
http.Response response = await http.get(dataUrl);
if (response.statusCode == 200) {
Map<String, dynamic> newsStories = json.decode(response.body);
setState(() {
noServerConnForNewsStories = false;
newsStoriesArray = newsStories['articles'];
});
} else {
setState(() {
noServerConnForNewsStories = true;
});
}
}
loadNewsStoriesFromSearch(String keyWord) async {
isValidCustomNewsSource = true;
noFavoriteNewsSourcesSelected = false;
if (newsStoriesArray != null) setState(() => newsStoriesArray.clear());
String searchUrl = "https://newsapi.org/v2/everything?q=" +
keyWord +
"&language=en&sortBy=publishedAt&apiKey=a30edf50cbbb48049945142f004c36c3";
http.Response response = await http.get(searchUrl);
if (response.statusCode == 200) {
Map<String, dynamic> newsStories = json.decode(response.body);
setState(() {
noServerConnForNewsStories = false;
newsStoriesArray = newsStories['articles'];
});
} else {
setState(() {
noServerConnForNewsStories = true;
});
}
}
loadNewsStoriesFromCategory() async {
isValidCustomNewsSource = true;
noFavoriteNewsSourcesSelected = false;
if (newsStoriesArray != null) setState(() => newsStoriesArray.clear());
String dataUrl =
"https://newsapi.org/v2/top-headlines?country=${getCurrentCountry()}&category=" +
_selectedNewsSource +
"&apiKey=a30edf50cbbb48049945142f004c36c3";
http.Response response = await http.get(dataUrl);
if (response.statusCode == 200) {
Map<String, dynamic> newsStories = json.decode(response.body);
setState(() {
noServerConnForNewsStories = false;
newsStoriesArray = newsStories['articles'];
});
} else {
setState(() {
noServerConnForNewsStories = true;
});
}
}
/*
* UI METHODS BEGIN
*/
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onBackKeyPressed,
child: Theme(
data: getCurrentTheme(),
child: Scaffold(
key: _scaffoldKey,
appBar: buildAppBar(),
drawer: buildListOfNewsSources(),
body: buildListOfNewsStories())));
}
buildNewsCategories() {
double iconSize = 60.0;
double textSize = 20.0;
Color iconColor = Colors.black;
Color textColor = Colors.black;
return GridView.count(
shrinkWrap: true,
crossAxisCount: 3,
childAspectRatio: 1.0,
children: <Widget>[
InkWell(
onTap: () {
Navigator.pop(context);
selectedNewsSourceId = "business";
_selectedNewsSource = "business";
appBarTitle = "${getCurrentCountry().toUpperCase()} Business";
lastUserAction = LastUserAction.categories;
_refreshIndicatorKey.currentState.show();
},
child: Container(
decoration: BoxDecoration(color: Color(0xFF69F0AE)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(),
Center(child: Icon(Icons.attach_money, size: iconSize, color: iconColor)),
Text(
"BUSINESS",
style: TextStyle(fontSize: textSize, color: textColor),
)
],
)),
),
InkWell(
onTap: () {
Navigator.pop(context);
selectedNewsSourceId = "technology";
_selectedNewsSource = "technology";
appBarTitle = "${getCurrentCountry().toUpperCase()} Tech";
lastUserAction = LastUserAction.categories;
_refreshIndicatorKey.currentState.show();
},
child: Container(
decoration: BoxDecoration(color: Color(0xFFFFD740)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(),
Icon(Icons.smartphone, size: iconSize, color: iconColor),
Text(
"TECH",
style: TextStyle(fontSize: textSize, color: textColor),
)
],
)),
),
InkWell(
onTap: () {
Navigator.pop(context);
selectedNewsSourceId = "science";
_selectedNewsSource = "science";
appBarTitle = "${getCurrentCountry().toUpperCase()} Science";
lastUserAction = LastUserAction.categories;
_refreshIndicatorKey.currentState.show();
},
child: Container(
decoration: BoxDecoration(color: Color(0xFFE040FB)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(),
Icon(Icons.bubble_chart, size: iconSize, color: iconColor),
Text(
"SCIENCE",
style: TextStyle(fontSize: textSize, color: textColor),
)
],
)),
),
InkWell(
onTap: () {
Navigator.pop(context);
selectedNewsSourceId = "sports";
_selectedNewsSource = "sports";
appBarTitle = "${getCurrentCountry().toUpperCase()} Sports";
lastUserAction = LastUserAction.categories;
_refreshIndicatorKey.currentState.show();
},
child: Container(
decoration: BoxDecoration(color: Color(0xFF40C4FF)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(),
Icon(Icons.golf_course, size: iconSize, color: iconColor),
Text(
"SPORTS",
style: TextStyle(fontSize: textSize, color: textColor),
)
],
)),
),
InkWell(
onTap: () {
Navigator.pop(context);
selectedNewsSourceId = "health";
_selectedNewsSource = "health";
appBarTitle = "${getCurrentCountry().toUpperCase()} Health";
lastUserAction = LastUserAction.categories;
_refreshIndicatorKey.currentState.show();
},
child: Container(
decoration: BoxDecoration(color: Color(0xFF536DFE)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(),
Icon(Icons.favorite_border, size: iconSize, color: iconColor),
Text(
"HEALTH",
style: TextStyle(fontSize: textSize, color: textColor),
)
],
)),
),
InkWell(
onTap: () {
Navigator.pop(context);
selectedNewsSourceId = "entertainment";
_selectedNewsSource = "entertainment";
appBarTitle = "${getCurrentCountry().toUpperCase()} Showbiz";
lastUserAction = LastUserAction.categories;
_refreshIndicatorKey.currentState.show();
},
child: Container(
decoration: BoxDecoration(color: Color(0XFFFF5252)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(),
Icon(Icons.local_movies, size: iconSize, color: iconColor),
Text(
"SHOWBIZ",
style: TextStyle(fontSize: textSize, color: textColor),
)
],
)),
),
],
);
}
buildListOfNewsSources() {
if (noServerConnForNewsSources) {
Timer(Duration(seconds: 5), () => loadNewsSources());
return Drawer(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Padding(
padding: EdgeInsets.all(8.0),
child: Text("Retrying connection...",
style: TextStyle(fontSize: getFontSize(TextSize.small)),
textAlign: TextAlign.center)),
],
)));
} else {
return Drawer(
child: Scrollbar(
child: ListView(
children: List.generate(newsSourcesArray.length + 4, (int index) {
if (index == 0)
return buildNewsCategories();
else if (index == 1)
return getBreakingNewsListTile();
else if (index == 2)
return getMyFeedListTile();
else if (index == 3)
return Divider();
else {
index -= 4;
String newsSource = newsSourcesArray[index]['name'] ?? "Unknown Source";
String newsSourceId = newsSourcesArray[index]['id'] ?? "Unknown ID";
return Row(
children: <Widget>[
new IconButton(
icon: favoriteNewsSources.contains(newsSource)
? new Icon(Icons.star,
color: _selectedNewsSource == newsSource ? getAccentColor() : null)
: new Icon(Icons.star_border,
color: _selectedNewsSource == newsSource ? getAccentColor() : null),
onPressed: () {
if (favoriteNewsSources.contains(newsSource)) {
favoriteNewsSources.remove(newsSource);
favoriteNewsSourcesId.remove(newsSourceId);
} else {
favoriteNewsSources.add(newsSource);
favoriteNewsSourcesId.add(newsSourceId);
}
saveFavoriteNewsSourcesToDisk();
saveFavoriteNewsSourcesIdToDisk();
setState(() {
sortNewsSourcesArray();
});
},
padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
),
Expanded(
child: SizedBox(
height: 50.0,
child: InkWell(
child: Align(
alignment: Alignment.centerLeft,
child: Text(
newsSource,
softWrap: false,
style: TextStyle(
fontSize: getFontSize(TextSize.big),
color: _selectedNewsSource == newsSourcesArray[index]['name']
? getAccentColor()
: null),
overflow: TextOverflow.fade,
maxLines: 1,
)),
onTap: () {
Navigator.pop(context);
selectedNewsSourceId = newsSourcesArray[index]['id'];
appBarTitle = newsSourcesArray[index]['name'];
_selectedNewsSource = newsSourcesArray[index]['name'];
if (customNewsSources.contains(newsSource)) {
lastUserAction = LastUserAction.customNews;
_refreshIndicatorKey.currentState.show();
} else {
lastUserAction = LastUserAction.news;
if (_refreshIndicatorKey.currentState == null)
refreshNewsStories();
else
_refreshIndicatorKey.currentState.show();
}
},
)),
),
showRemoveCustomNewsSourceButton(newsSource, index)
],
);
}
}))));
}
}
getBreakingNewsListTile() {
return Row(
children: <Widget>[
new IconButton(
color: _selectedNewsSource == BREAKING_NEWS ? defaultDarkTheme.accentColor : null,
icon: Icon(Icons.home,
color: _selectedNewsSource == "${getCurrentCountry().toUpperCase()} $BREAKING_NEWS"
? getAccentColor()
: null),
onPressed: () => null,
padding: EdgeInsets.fromLTRB(16.0, 24.0, 8.0, 12.0),
),
Expanded(
child: InkWell(
child: Padding(
padding: EdgeInsets.fromLTRB(8.0, 24.0, 8.0, 12.0),
child: Text("${getCurrentCountry().toUpperCase()}" + " $BREAKING_NEWS",
style: TextStyle(
fontSize: getFontSize(TextSize.big),
color: _selectedNewsSource ==
"${getCurrentCountry().toUpperCase()} $BREAKING_NEWS"
? getAccentColor()
: null))),
onTap: () {
appBarTitle = "${getCurrentCountry().toUpperCase()} $BREAKING_NEWS";
lastUserAction = LastUserAction.topNews;
Navigator.pop(context);
_selectedNewsSource = "${getCurrentCountry().toUpperCase()} $BREAKING_NEWS";
if (_refreshIndicatorKey.currentState == null)
refreshNewsStories();
else
_refreshIndicatorKey.currentState.show();
},
))
],
);
}
getMyFeedListTile() {
return Row(
children: <Widget>[
new IconButton(
color: _selectedNewsSource == MY_FEED ? defaultDarkTheme.accentColor : null,
icon:
Icon(Icons.favorite, color: _selectedNewsSource == MY_FEED ? getAccentColor() : null),
onPressed: () => null,
padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
),
Expanded(
child: SizedBox(
height: 50.0,
child: InkWell(
child: Align(
alignment: Alignment.centerLeft,
child: Text(
MY_FEED,
softWrap: false,
style: TextStyle(
fontSize: getFontSize(TextSize.big),
color: _selectedNewsSource == MY_FEED ? getAccentColor() : null),
overflow: TextOverflow.fade,
maxLines: 1,
)),
onTap: () {
Navigator.pop(context);
appBarTitle = MY_FEED;
_selectedNewsSource = MY_FEED;
lastUserAction = LastUserAction.myFeed;
if (_refreshIndicatorKey.currentState == null)
refreshNewsStories();
else
_refreshIndicatorKey.currentState.show();
},
)),
),
],
);
}
showRemoveCustomNewsSourceButton(String newsSource, int index) {
if (customNewsSources.contains(newsSource)) {
return IconButton(
icon: Icon(Icons.remove_circle_outline,
color: _selectedNewsSource == newsSource ? getAccentColor() : null),
onPressed: () {
if (customNewsSources.contains(newsSource)) {
customNewsSources.remove(newsSource);
newsSourcesArray.removeAt(index);
prefs.setStringList(CUSTOM_NEWS_SOURCES, customNewsSources);
setState(() {
sortNewsSourcesArray();
});
}
},
);
} else {
return SizedBox(width: 10.0, height: 1.0);
}
}
buildListOfNewsStories() {
if (!isValidCustomNewsSource) {
return Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 30.0),
child: Text("The news provider '$_selectedNewsSource' was not recognized.",
style: TextStyle(fontSize: getFontSize(TextSize.huge)),
textAlign: TextAlign.center)));
} else if (noServerConnForNewsStories) {
Timer(Duration(seconds: 6), () => refreshNewsStories());
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Padding(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 30.0),
child: Text(
"No data received from server.\nPlease check your internet connection. Reconnecting...",
style: TextStyle(fontSize: getFontSize(TextSize.huge)),
textAlign: TextAlign.center),
)
],
));
} else if (noFavoriteNewsSourcesSelected) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 30.0),
child: Text(
"Your news feed is empty.\You can star one or more news sources from the drawer to build your feed.",
style: TextStyle(fontSize: getFontSize(TextSize.huge)),
textAlign: TextAlign.center),
)
],
));
} else {
return Scrollbar(
child: RefreshIndicator(
onRefresh: refreshNewsStories,
key: _refreshIndicatorKey,
displacement: 80.0,
child: ListView(
controller: _scrollController,
children: new List.generate(newsStoriesArray.length, (int index) {
String title = newsStoriesArray[index]['title'] ?? "";
String newsText = newsStoriesArray[index]['description'] ?? "";
String url = newsStoriesArray[index]['url'] ?? "";
String imageUrl = newsStoriesArray[index]['urlToImage'] ?? "";
String dateTime = newsStoriesArray[index]['publishedAt'] ?? "";
String newsSourceName =
newsStoriesArray[index]['source']['name'] ?? "Unknown source";
String formattedDate = formatDateForUi(dateTime);
return Padding(
padding: EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
child: InkWell(
onTap: () {
final mediaQuery = MediaQuery.of(context);
final topPadding = mediaQuery.padding.top; // status bar
double top = appbarHeight + topPadding; // appbar
double height = mediaQuery.size.height - top;
double width = mediaQuery.size.width;
flutterWebviewPlugin.launch(url,
rect: Rect.fromLTWH(0.0, top, width, height),
userAgent: userAgent,
clearCookies: true,
withZoom: true);
setState(() => isWebViewOpen = true);
},
child: Card(
elevation: 5.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
showImageIfAvailable(imageUrl),
Padding(
padding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 8.0),
child: Text(title,
textAlign: TextAlign.left,
style: TextStyle(
fontSize: getFontSize(TextSize.huge),
fontWeight: FontWeight.bold)),
),
showNewsSourceName(newsSourceName),
Padding(
padding: EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
child: Text(newsText,
style: TextStyle(fontSize: getFontSize(TextSize.medium))),
),
Padding(
padding: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0),
child: Row(
children: <Widget>[
Expanded(
child: Opacity(
opacity: 0.75,
child: Text(formattedDate,
style: TextStyle(
fontStyle: FontStyle.italic,
fontSize: getFontSize(TextSize.small)))),
),
IconButton(
icon: Icon(
Icons.share,
color: getAccentColor(),
),
padding: EdgeInsets.fromLTRB(0.0, 0.0, 16.0, 0.0),
iconSize: 32.0,
onPressed: () =>
sharing.share('"' + title + '"' + " " + url)),
Text("READ MORE",
style: TextStyle(
fontSize: getFontSize(TextSize.medium),
color: getAccentColor(),
fontWeight: FontWeight.bold))
],
))
]))));
}),
)),
);
}
}
buildAppBar() {
Color accentColor =
currentSelectedTheme == MyThemes.defaultLight ? Colors.white : getAccentColor();
Icon drawerMenu = Icon(Icons.menu, color: accentColor);
Icon backBtn = Icon(Icons.arrow_back, color: accentColor);
Icon settingsIcon = Icon(Icons.more_vert, color: accentColor);
AppBar myAppBar = AppBar(
leading: IconButton(
icon: isWebViewOpen ? backBtn : drawerMenu,
onPressed: () {
if (isWebViewOpen) {
flutterWebviewPlugin.close();
setState(() => isWebViewOpen = false);
} else
_scaffoldKey.currentState.openDrawer();
}),
title: Text(appBarTitle,
style: TextStyle(color: accentColor, fontSize: getFontSize(TextSize.big))),
actions: isWebViewOpen
? List<Widget>()
: <Widget>[
PopupMenuButton<ListTile>(
icon: settingsIcon,
elevation: 16.0,
itemBuilder: (BuildContext context) => <PopupMenuItem<ListTile>>[
PopupMenuItem<ListTile>(
child: ListTile(
leading: Icon(Icons.palette, color: getAccentColor()),
title: Text("Theme",
style: TextStyle(
color: getAccentColor(), fontSize: getFontSize(TextSize.medium))),
onTap: () {
Navigator.of(context).pop();
showThemeDialog();
},
)),
PopupMenuItem<ListTile>(
child: ListTile(
leading: Icon(Icons.search, color: getAccentColor()),
title: Text("Search",
style: TextStyle(
color: getAccentColor(), fontSize: getFontSize(TextSize.medium))),
onTap: () {
Navigator.of(context).pop();
showSearchDialog();
},
)),
PopupMenuItem<ListTile>(
child: ListTile(
leading: Icon(Icons.add, color: getAccentColor()),
title: Text("Provider",
style: TextStyle(
color: getAccentColor(), fontSize: getFontSize(TextSize.medium))),
onTap: () {
Navigator.of(context).pop();
showAddCustomNewsSourcesDialog();
},
)),
PopupMenuItem<ListTile>(
child: ListTile(
leading: Icon(Icons.language, color: getAccentColor()),
title: Text("Country",
style: TextStyle(
color: getAccentColor(), fontSize: getFontSize(TextSize.medium))),
onTap: () {
Navigator.of(context).pop();
showCountryDialog();
},
)),
PopupMenuItem<ListTile>(
child: ListTile(
leading: Icon(Icons.format_size, color: getAccentColor()),
title: Text("Font Size",
style: TextStyle(
color: getAccentColor(), fontSize: getFontSize(TextSize.medium))),
onTap: () {
Navigator.of(context).pop();
showFontSizeDialog();
},
)),
],
),
],
);
appbarHeight = myAppBar.preferredSize.height;
return myAppBar;
}
Future<Null> showFontSizeDialog() async {
return showDialog<Null>(
context: context,
barrierDismissible: true,
child: FontSizeSelection(onFontSizeChosen: setFontSize, currentFontSize: adjustedFontSize));
}
Future<Null> showCountryDialog() async {
return showDialog<Null>(
context: context,
barrierDismissible: true,
child:
CountrySelection(onCountryChosen: setCountry, currentCountry: currentSelectedCountry));
}
Future<Null> showThemeDialog() async {
return showDialog<Null>(
context: context,
barrierDismissible: true,
child: ThemeSelection(onThemeChosen: setTheme, currentTheme: currentSelectedTheme));
}
void setTheme(MyThemes chosenTheme) {
setState(() => currentSelectedTheme = chosenTheme);
prefs.setInt("theme", chosenTheme.index);
}
void setFontSize(double chosenSize) {
setState(() => adjustedFontSize = chosenSize);
prefs.setDouble("fontSize", chosenSize);
}
Future<Null> showSearchDialog() async {
double screenWidth = MediaQuery.of(context).size.width;
return showDialog<Null>(
context: context,
barrierDismissible: true,
child: Theme(
data: getCurrentTheme(),
child: AlertDialog(
title: Text('Search For News Articles...',
style: TextStyle(color: getAccentColor(), fontSize: getFontSize(TextSize.big))),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
SizedBox(
width: screenWidth * 0.8,
height: 50.0,
child: TextField(
controller: _seachTextFieldController,
autofocus: true,
maxLength: 50,
maxLengthEnforced: true,
decoration: InputDecoration(icon: Icon(Icons.search)),
onSubmitted: (_) => beginNewsSearch(_seachTextFieldController.text),
),
)
],
),
),
actions: <Widget>[
FlatButton(
child: Text('CLOSE', style: TextStyle(fontSize: getFontSize(TextSize.small))),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('SEARCH', style: TextStyle(fontSize: getFontSize(TextSize.small))),
onPressed: () {
beginNewsSearch(_seachTextFieldController.text);
},
),
],
)),
);
}
Future<Null> showWhatsNewDialog() async {
double screenWidth = MediaQuery.of(context).size.width;
return showDialog<Null>(
context: context,
barrierDismissible: false,
child: Theme(
data: getCurrentTheme(),
child: AlertDialog(
title: Text('Whats New In v6.0?',
style: TextStyle(color: getAccentColor(), fontSize: getFontSize(TextSize.big))),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
SizedBox(
width: screenWidth * 0.8,
child: Text(
"- Look for 'My Feed' under the 'Breaking News' tile. It aggregates news articles from news providers you have starred.\n" +
"- Starred news providers stay in the list even when the country is changed.",
style: TextStyle(fontSize: getFontSize(TextSize.medium))))
],
),
),
actions: <Widget>[
FlatButton(
child: Text("Cool!", style: TextStyle(fontSize: getFontSize(TextSize.small))),
onPressed: () {
prefs.setBool(WHATS_NEW, true);
Navigator.of(context).pop();
},
),
],
)),
);
}
beginNewsSearch(String keyword) {
if (keyword.length > 0) {
appBarTitle = "'" + keyword + "'";
_selectedNewsSource = appBarTitle;
selectedNewsSourceId = appBarTitle;
lastUserAction = LastUserAction.search;
_refreshIndicatorKey.currentState.show();
Navigator.of(context).pop();
}
}
Future<Null> showAddCustomNewsSourcesDialog() async {
final customNewsSourceFormField = GlobalKey<FormState>();
double screenWidth = MediaQuery.of(context).size.width;
return showDialog<Null>(
context: context,
barrierDismissible: true,
child: Theme(
data: getCurrentTheme(),
child: AlertDialog(
title: Text('Add News Provider',
style: TextStyle(color: getAccentColor(), fontSize: getFontSize(TextSize.big))),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
SizedBox(
width: screenWidth * 0.8,
height: 70.0,
child: Form(
key: customNewsSourceFormField,
child: TextFormField(
autofocus: true,
autocorrect: false,
decoration: InputDecoration(hintText: "mynews.com"),
onSaved: (val) => addCustomNewsSource(val),
onFieldSubmitted: ((val) {
if (val.isEmpty)
return "You must enter a url like mynews.com";
else if (customNewsSources.contains(val))
return "Custom news source already exists";
else
return null;
}),
validator: ((val) {
if (val.isEmpty)
return "You must enter a url like mynews.com";
else if (customNewsSources.contains(val))
return "Custom news source already exists";
else
return null;
}),
)))
],
),
),
actions: <Widget>[
FlatButton(
child: Text('CLOSE', style: TextStyle(fontSize: getFontSize(TextSize.small))),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('ADD', style: TextStyle(fontSize: getFontSize(TextSize.small))),
onPressed: () {
if (customNewsSourceFormField.currentState.validate()) {
customNewsSourceFormField.currentState.save();
Navigator.of(context).pop();
}
},
),
],
)),
);
}
/*
* HELPER METHODS BEGIN
*/
void addCustomNewsSourcesToNewsSourcesArray() {
for (String customNewsSource in customNewsSources) {
Map<String, String> customNewsSourceMap = {'name': customNewsSource, 'id': customNewsSource};
newsSourcesArray.add(customNewsSourceMap);
newsSourcesIdSet.add(customNewsSource);
}
}
void addFavoriteNewsSourcesToNewsSourcesArray() {
for (int i = 0; i < favoriteNewsSources.length; i++) {
Map<String, String> favoriteNewsMap = {
'name': favoriteNewsSources[i],
'id': favoriteNewsSourcesId[i]
};
if (!newsSourcesIdSet.contains(favoriteNewsSourcesId[i]))
newsSourcesArray.add(favoriteNewsMap);
}
}
void setCountry(Country chosenCountry) {
currentSelectedCountry = chosenCountry;
lastUserAction = LastUserAction.topNews;
_selectedNewsSource = "${getCurrentCountry().toUpperCase()} $BREAKING_NEWS";
_refreshIndicatorKey.currentState
.show()
.then((_) => setAppBarTitle())
.then((_) => loadNewsSources())
.then((_) => addCustomNewsSourcesToNewsSourcesArray())
.then((_) => addFavoriteNewsSourcesToNewsSourcesArray())
.then((_) => setState(() => sortNewsSourcesArray()));
prefs.setInt("country", chosenCountry.index);
}
Future<bool> _onBackKeyPressed() {
flutterWebviewPlugin.close();
setState(() {
isWebViewOpen = false;
});
Completer<bool> completer = new Completer<bool>();
completer.complete();
return completer.future;
}
static double getFontSize(TextSize textSize) {
return textSizes[textSize] + adjustedFontSize;
}
void initSelectedNewsSourceVar() {
_selectedNewsSource = "${getCurrentCountry().toUpperCase()} $BREAKING_NEWS";
}
void setAppBarTitle() {
appBarTitle = "${getCurrentCountry().toUpperCase()} $BREAKING_NEWS";
}
static String getCurrentCountry() {
switch (currentSelectedCountry) {
case Country.Argentina:
return "ar";
case Country.Australia:
return "au";
case Country.Austria:
return "at";
case Country.Belgium:
return "be";
case Country.Brazil:
return "br";
case Country.Bulgaria:
return "bg";
case Country.Canada:
return "ca";
case Country.China:
return "cn";
case Country.Colombia:
return "co";
case Country.Cuba:
return "cu";
case Country.Czechia:
return "cz";
case Country.Egypt:
return "eg";
case Country.France:
return "fr";
case Country.Germany:
return "de";
case Country.Greece:
return "gr";
case Country.HongKong:
return "hk";
case Country.Hungary:
return "hu";
case Country.India:
return "in";
case Country.Indonesia:
return "id";
case Country.Ireland:
return "ie";
case Country.Israel:
return "il";
case Country.Italy:
return "it";
case Country.Japan:
return "jp";
case Country.Korea:
return "kr";
case Country.Latvia:
return "lv";
case Country.Lithuania:
return "lt";
case Country.Malaysia:
return "my";
case Country.Mexico:
return "mx";
case Country.Morocco:
return "ma";
case Country.Netherlands:
return "nl";
case Country.NewZealand:
return "nz";
case Country.Nigeria:
return "ng";
case Country.Norway:
return "no";
case Country.Philippines:
return "ph";
case Country.Poland:
return "pl";
case Country.Portugal:
return "pt";
case Country.Romania:
return "ro";
case Country.Russia:
return "ru";
case Country.SaudiArabia:
return "sa";
case Country.Serbia:
return "rs";
case Country.Singapore:
return "sg";
case Country.Slovakia:
return "sk";
case Country.Slovenia:
return "si";
case Country.SouthAfrica:
return "za";
case Country.Sweden:
return "se";
case Country.Switzerland:
return "ch";
case Country.Taiwan:
return "tw";
case Country.Thailand:
return "th";
case Country.Turkey:
return "tr";
case Country.Ukraine:
return "ua";
case Country.UK_NI:
return "gb";
case Country.UAE:
return "ae";
case Country.USA:
return "us";
case Country.Venezuela:
return "ve";
default:
return "us";
}
}
static ThemeData getCurrentTheme() {
switch (currentSelectedTheme) {
case MyThemes.defaultLight:
return defaultLightTheme;
break;
case MyThemes.defaultDark:
return defaultDarkTheme;
break;
case MyThemes.darkYellow:
return darkYellow;
break;
case MyThemes.darkCyan:
return darkCyan;
break;
case MyThemes.darkGreen:
return darkGreen;
break;
case MyThemes.darkPurple:
return darkPurple;
break;
case MyThemes.darkPink:
return darkPink;
break;
case MyThemes.darkTeal:
return darkTeal;
break;
}
return defaultLightTheme;
}
void addCustomNewsSource(String customNewsSource) {
customNewsSources.add(customNewsSource);
// save list to disk
prefs.setStringList(CUSTOM_NEWS_SOURCES, customNewsSources);
// Build map to add to newsSourcesArray
Map<String, String> customNewsSourceMap = {'name': customNewsSource, 'id': customNewsSource};
newsSourcesArray.add(customNewsSourceMap);
selectedNewsSourceId = customNewsSourceMap['id'];
appBarTitle = customNewsSourceMap['name'];
_selectedNewsSource = customNewsSourceMap['name'];
sortNewsSourcesArray();
lastUserAction = LastUserAction.customNews;
if (_refreshIndicatorKey.currentState == null)
refreshNewsStories();
else
_refreshIndicatorKey.currentState.show();
}
Widget showNewsSourceName(String newsSource) {
if (lastUserAction == LastUserAction.search ||
lastUserAction == LastUserAction.topNews ||
lastUserAction == LastUserAction.categories ||
lastUserAction == LastUserAction.myFeed) {
return Padding(
padding: EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
child: Opacity(
opacity: 0.75,
child: Text(newsSource,
style: TextStyle(
fontSize: getFontSize(TextSize.small),
fontStyle: FontStyle.italic,
)),
));
} else {
return Padding(
padding: EdgeInsets.all(0.0),
);
}
}
String formatDateForUi(String dateTime) {
if (dateTime != "") {
String newDateTime = dateTime.substring(0, 19) + "Z";
DateTime dtObj = DateTime.parse(newDateTime);
DateTime localDtObj = dtObj.toLocal();
DateTime now = DateTime.now();
Duration difference = localDtObj.difference(now);
int days = difference.inDays.abs();
if (days > 0) return "$days day${pluralizeTime(days)} ago";
int hours = difference.inHours.abs();
if (hours > 0) return "$hours hour${pluralizeTime(hours)} ago";
int minutes = difference.inMinutes.abs();
if (minutes > 0) return "$minutes minute${pluralizeTime(minutes)} ago";
int seconds = difference.inSeconds.abs();
if (seconds > 0) return "$seconds second${pluralizeTime(seconds)} ago";
}
return "";
}
String pluralizeTime(int timeUnit) {
return timeUnit > 1 ? "s" : "";
}
String formatDateForSearchQuery(DateTime dateTimeObj) {
DateFormat formatter = new DateFormat('yyyy-MM-dd');
return formatter.format(dateTimeObj);
}
sortNewsSourcesArray() {
newsSourcesArray.sort((a, b) {
// both - sort alphabetically
if (favoriteNewsSources.contains(a['name']) && favoriteNewsSources.contains(b['name']))
return a['name'].compareTo(b['name']);
// a and NOT b (a comes before b)
else if (favoriteNewsSources.contains(a['name']) && !favoriteNewsSources.contains(b['name']))
return -1;
// NOT a, but b (a comes after b)
else if (!favoriteNewsSources.contains(a['name']) && favoriteNewsSources.contains(b['name']))
return 1;
// none - sort alphabetically
else
return a['name'].compareTo(b['name']);
});
}
Future<Null> refreshNewsStories() {
Completer<Null> completer = new Completer<Null>();
switch (lastUserAction) {
case LastUserAction.myFeed:
loadMyFeed().then((_) => completer.complete());
break;
case LastUserAction.categories:
loadNewsStoriesFromCategory().then((_) => completer.complete());
break;
case LastUserAction.topNews:
loadTopHeadlines().then((_) => completer.complete());
break;
case LastUserAction.search:
loadNewsStoriesFromSearch(_seachTextFieldController.text).then((_) => completer.complete());
break;
case LastUserAction.customNews:
loadNewsStoriesFromCustomSource().then((_) => completer.complete());
break;
case LastUserAction.news:
loadNewsStories().then((_) => completer.complete());
break;
}
return completer.future;
}
getThemeSelectionFromDisk() {
setState(() {
currentSelectedTheme = MyThemes.values[prefs.getInt("theme") ?? 0];
});
}
getCountrySelectionFromDisk() {
currentSelectedCountry = Country.values[prefs.getInt("country") ?? Country.USA.index];
}
getWhatsNewBoolFromDisk() {
bool userHasReadWhatsNew = prefs.getBool(WHATS_NEW) ?? false;
if (!userHasReadWhatsNew) showWhatsNewDialog();
}
getFontSizeSelectionFromDisk() {
adjustedFontSize = prefs.getDouble("fontSize") ?? 0.0;
}
saveFavoriteNewsSourcesToDisk() async {
prefs.setStringList(FAVORITE_NEWS_SOURCES, favoriteNewsSources);
}
saveFavoriteNewsSourcesIdToDisk() async {
prefs.setStringList(FAVORITE_NEWS_SOURCES_ID, favoriteNewsSourcesId);
}
getFavoriteNewsSourcesFromDisk() async {
if (prefs.getStringList(FAVORITE_NEWS_SOURCES) == null)
favoriteNewsSources = new List();
else
favoriteNewsSources = new List<String>.from(prefs.getStringList(FAVORITE_NEWS_SOURCES));
}
getFavoriteNewsSourcesIdFromDisk() async {
if (prefs.getStringList(FAVORITE_NEWS_SOURCES_ID) == null)
favoriteNewsSourcesId = new List();
else
favoriteNewsSourcesId = new List<String>.from(prefs.getStringList(FAVORITE_NEWS_SOURCES_ID));
}
getCustomNewsSourcesFromDisk() async {
if (prefs.getStringList(CUSTOM_NEWS_SOURCES) == null)
customNewsSources = new List();
else
customNewsSources = new List<String>.from(prefs.getStringList(CUSTOM_NEWS_SOURCES));
}
Widget showImageIfAvailable(String imageUrl) {
double screenWidth = MediaQuery.of(context).size.width;
double pictureWidth = screenWidth - 32;
double pictureHeight = pictureWidth * 0.65;
if (imageUrl != null && imageUrl != "") {
return FadeInImage.assetNetwork(
fit: BoxFit.cover,
placeholder: "images/loading.gif",
image: imageUrl,
height: pictureHeight,
width: pictureWidth);
} else
return SizedBox(width: 0.0, height: 0.0);
}
initSharedPreferences() async {
prefs = await SharedPreferences.getInstance();
}
Color getAccentColor() {
ThemeData theme = getCurrentTheme();
return theme.accentColor;
}
}
/*
Classes related to theming
*/
enum MyThemes {
defaultDark,
defaultLight,
darkTeal,
darkCyan,
darkPurple,
darkGreen,
darkYellow,
darkPink
}
final ThemeData defaultLightTheme = new ThemeData(
brightness: Brightness.light, primarySwatch: Colors.blue, accentColor: Colors.blueAccent);
final ThemeData defaultDarkTheme = new ThemeData(
brightness: Brightness.dark,
primarySwatch: Colors.lightBlue,
accentColor: Colors.lightBlueAccent);
final ThemeData darkTeal = new ThemeData(
brightness: Brightness.dark, primarySwatch: Colors.teal, accentColor: Colors.tealAccent);
final ThemeData darkCyan = new ThemeData(
brightness: Brightness.dark, primarySwatch: Colors.cyan, accentColor: Colors.cyanAccent);
final ThemeData darkPurple = new ThemeData(
brightness: Brightness.dark, primarySwatch: Colors.purple, accentColor: Colors.purpleAccent);
final ThemeData darkGreen = new ThemeData(
brightness: Brightness.dark, primarySwatch: Colors.green, accentColor: Colors.greenAccent);
final ThemeData darkYellow = new ThemeData(
brightness: Brightness.dark, primarySwatch: Colors.yellow, accentColor: Colors.yellowAccent);
final ThemeData darkPink = new ThemeData(
brightness: Brightness.dark, primarySwatch: Colors.pink, accentColor: Colors.pinkAccent);
typedef void ThemeSelectionCallback(MyThemes chosenTheme);
class ThemeSelection extends StatefulWidget {
final ThemeSelectionCallback onThemeChosen;
final MyThemes currentTheme;
ThemeSelection({this.onThemeChosen, this.currentTheme});
@override
_ThemeSelectionState createState() => new _ThemeSelectionState(currentTheme: this.currentTheme);
}
class _ThemeSelectionState extends State<ThemeSelection> {
MyThemes currentTheme;
MyThemes themeGroupValue = MyThemes.defaultLight;
_ThemeSelectionState({this.currentTheme});
@override
void initState() {
super.initState();
themeGroupValue = currentTheme;
}
@override
Widget build(BuildContext context) {
return Theme(
data: _HomePageState.getCurrentTheme(),
child: AlertDialog(
actions: <Widget>[
FlatButton(
child: Text('CLOSE',
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('SELECT',
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
onPressed: () {
widget.onThemeChosen(themeGroupValue);
Navigator.of(context).pop();
},
),
],
title: Text("Select Theme",
style: TextStyle(
fontSize: _HomePageState.getFontSize(TextSize.big),
)),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
RadioListTile(
value: MyThemes.defaultLight,
title: Text("Default Light",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
groupValue: themeGroupValue,
onChanged: (value) => setState(() => this.themeGroupValue = value),
),
RadioListTile(
value: MyThemes.defaultDark,
title: Text("Default Dark",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
groupValue: themeGroupValue,
onChanged: (value) => setState(() => this.themeGroupValue = value),
),
RadioListTile(
value: MyThemes.darkTeal,
title: Text("Dark / Teal",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
groupValue: themeGroupValue,
onChanged: (value) => setState(() => this.themeGroupValue = value),
),
RadioListTile(
value: MyThemes.darkCyan,
title: Text("Dark / Cyan",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
groupValue: themeGroupValue,
onChanged: (value) => setState(() => this.themeGroupValue = value),
),
RadioListTile(
value: MyThemes.darkPurple,
title: Text("Dark / Purple",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
groupValue: themeGroupValue,
onChanged: (value) => setState(() => this.themeGroupValue = value),
),
RadioListTile(
value: MyThemes.darkGreen,
title: Text("Dark / Green",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
groupValue: themeGroupValue,
onChanged: (value) => setState(() => this.themeGroupValue = value),
),
RadioListTile(
value: MyThemes.darkYellow,
title: Text("Dark / Yellow",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
groupValue: themeGroupValue,
onChanged: (value) => setState(() => this.themeGroupValue = value),
),
RadioListTile(
value: MyThemes.darkPink,
title: Text("Dark / Pink",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
groupValue: themeGroupValue,
onChanged: (value) => setState(() => this.themeGroupValue = value),
),
],
)),
));
}
}
/*
Classes related to setting country
*/
typedef void CountrySelectionCallback(Country country);
class CountrySelection extends StatefulWidget {
final CountrySelectionCallback onCountryChosen;
final Country currentCountry;
CountrySelection({this.onCountryChosen, this.currentCountry});
@override
_CountrySelectionState createState() =>
new _CountrySelectionState(currentCountry: this.currentCountry);
}
class _CountrySelectionState extends State<CountrySelection> {
Country currentCountry;
Country countryGoupValue = Country.USA;
_CountrySelectionState({this.currentCountry});
@override
void initState() {
super.initState();
countryGoupValue = currentCountry;
}
@override
Widget build(BuildContext context) {
return Theme(
data: _HomePageState.getCurrentTheme(),
child: AlertDialog(
actions: <Widget>[
FlatButton(
child: Text('CLOSE',
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('SELECT',
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
onPressed: () {
widget.onCountryChosen(countryGoupValue);
Navigator.of(context).pop();
},
),
],
title: Text("Get news providers from:",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.big))),
content: SingleChildScrollView(child: ListBody(children: getCountryListTiles())),
));
}
List<Widget> getCountryListTiles() {
List<RadioListTile> countryList = new List<RadioListTile>();
for (Country theCountry in Country.values) {
countryList.add(
RadioListTile(
value: theCountry,
title: Text("${getCountryName(theCountry.toString().substring(8))}",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
groupValue: countryGoupValue,
onChanged: (value) => setState(() => this.countryGoupValue = value),
),
);
}
return countryList;
}
String getCountryName(String name) {
switch (name) {
case "HongKong":
return "Hong Kong";
case "NewZealand":
return "New Zealand";
case "SaudiArabia":
return "Saudi Arabia";
case "SouthAfrica":
return "South Africa";
case "UK_NI":
return "UK / NI";
default:
return name;
}
}
}
enum Country {
Argentina,
Australia,
Austria,
Belgium,
Brazil,
Bulgaria,
Canada,
China,
Colombia,
Cuba,
Czechia,
Egypt,
France,
Germany,
Greece,
HongKong,
Hungary,
India,
Indonesia,
Ireland,
Israel,
Italy,
Japan,
Korea,
Latvia,
Lithuania,
Malaysia,
Mexico,
Morocco,
Netherlands,
NewZealand,
Nigeria,
Norway,
Philippines,
Poland,
Portugal,
Romania,
Russia,
SaudiArabia,
Serbia,
Singapore,
Slovakia,
Slovenia,
SouthAfrica,
Sweden,
Switzerland,
Taiwan,
Thailand,
Turkey,
Ukraine,
UK_NI,
UAE,
USA,
Venezuela
}
typedef void FontSizeSelectionCallBack(double newSize);
class FontSizeSelection extends StatefulWidget {
final FontSizeSelectionCallBack onFontSizeChosen;
final double currentFontSize;
FontSizeSelection({this.onFontSizeChosen, this.currentFontSize});
@override
_FontSizeSelectionState createState() =>
new _FontSizeSelectionState(currentFontSize: this.currentFontSize);
}
class _FontSizeSelectionState extends State<FontSizeSelection> {
double currentFontSize;
double fontSizeGroupValue = 0.0;
_FontSizeSelectionState({this.currentFontSize});
@override
void initState() {
super.initState();
fontSizeGroupValue = currentFontSize;
}
@override
Widget build(BuildContext context) {
return Theme(
data: _HomePageState.getCurrentTheme(),
child: AlertDialog(
actions: <Widget>[
FlatButton(
child: Text('CLOSE',
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('SELECT',
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.small))),
onPressed: () {
widget.onFontSizeChosen(fontSizeGroupValue);
Navigator.of(context).pop();
},
),
],
title: Text("Select Font Size:",
style: TextStyle(fontSize: _HomePageState.getFontSize(TextSize.big))),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
RadioListTile(
value: -3.0,
title: Text("Small", style: TextStyle(fontSize: 14.0)),
groupValue: fontSizeGroupValue,
onChanged: (value) => setState(() => this.fontSizeGroupValue = value),
),
RadioListTile(
value: 0.0,
title: Text("Medium", style: TextStyle(fontSize: 20.0)),
groupValue: fontSizeGroupValue,
onChanged: (value) => setState(() => this.fontSizeGroupValue = value),
),
RadioListTile(
value: 6.0,
title: Text("Large", style: TextStyle(fontSize: 26.0)),
groupValue: fontSizeGroupValue,
onChanged: (value) => setState(() => this.fontSizeGroupValue = value),
),
],
)),
));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment