Skip to content

Commit 4dada26

Browse files
committed
Create dark mode support
1 parent c614091 commit 4dada26

File tree

9 files changed

+232
-96
lines changed

9 files changed

+232
-96
lines changed

lib/app.dart

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_news_app/feature/presentation/page/home/home_page.dart';
3+
import 'package:hive/hive.dart';
4+
import 'package:hive_flutter/hive_flutter.dart';
35

46
class App extends StatelessWidget {
57
@override
68
Widget build(BuildContext context) {
7-
return MaterialApp(
8-
debugShowCheckedModeBanner: false,
9-
title: 'News App',
10-
home: HomePage(),
9+
return ValueListenableBuilder(
10+
valueListenable: Hive.box('settings').listenable(),
11+
builder: (context, box, widget) {
12+
var isDarkMode = box.get('darkMode') ?? false;
13+
return MaterialApp(
14+
debugShowCheckedModeBanner: false,
15+
title: 'News App',
16+
theme: ThemeData(
17+
brightness: isDarkMode ? Brightness.dark : Brightness.light,
18+
),
19+
home: HomePage(),
20+
);
21+
},
1122
);
1223
}
1324
}

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

+89-58
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ import 'package:flutter_news_app/feature/data/model/categorynews/category_news_m
88
import 'package:flutter_news_app/feature/data/model/topheadlinesnews/top_headlines_news_response_model.dart';
99
import 'package:flutter_news_app/feature/presentation/bloc/topheadlinesnews/bloc.dart';
1010
import 'package:flutter_news_app/feature/presentation/page/search/search_page.dart';
11+
import 'package:flutter_news_app/feature/presentation/page/settings/settings_page.dart';
1112
import 'package:flutter_news_app/feature/presentation/widget/widget_failure_message.dart';
1213
import 'package:flutter_news_app/feature/presentation/widget/widget_item_news.dart';
1314
import 'package:flutter_news_app/injection_container.dart';
1415
import 'package:flutter_screenutil/flutter_screenutil.dart';
16+
import 'package:hive/hive.dart';
17+
import 'package:hive_flutter/hive_flutter.dart';
1518
import 'package:intl/intl.dart';
1619
import 'package:url_launcher/url_launcher.dart';
1720

@@ -76,62 +79,87 @@ class _HomePageState extends State<HomePage> {
7679
}
7780
}
7881
},
79-
child: Stack(
80-
children: [
81-
Container(
82-
width: double.infinity,
83-
height: double.infinity,
84-
color: Color(0xFFEFF5F5),
85-
),
86-
SafeArea(
87-
child: Container(
88-
width: double.infinity,
89-
color: Color(0xFFEFF5F5),
90-
padding: EdgeInsets.symmetric(
91-
vertical: 24.h,
82+
child: ValueListenableBuilder(
83+
valueListenable: Hive.box('settings').listenable(),
84+
builder: (context, box, widget) {
85+
var isDarkMode = box.get('darkMode') ?? false;
86+
return Stack(
87+
children: [
88+
Container(
89+
width: double.infinity,
90+
height: double.infinity,
91+
color: isDarkMode ? null : Color(0xFFEFF5F5),
9292
),
93-
child: Column(
94-
crossAxisAlignment: CrossAxisAlignment.start,
95-
children: <Widget>[
96-
Padding(
97-
padding: EdgeInsets.symmetric(horizontal: 48.w),
98-
child: Row(
99-
children: <Widget>[
100-
Expanded(
101-
child: Text(
102-
'Daily News',
103-
style: TextStyle(
104-
fontSize: 48.sp,
93+
SafeArea(
94+
child: Container(
95+
width: double.infinity,
96+
color: isDarkMode ? null : Color(0xFFEFF5F5),
97+
padding: EdgeInsets.symmetric(
98+
vertical: 24.h,
99+
),
100+
child: Column(
101+
crossAxisAlignment: CrossAxisAlignment.start,
102+
children: <Widget>[
103+
Padding(
104+
padding: EdgeInsets.symmetric(horizontal: 48.w),
105+
child: Row(
106+
children: <Widget>[
107+
Expanded(
108+
child: Text(
109+
'Daily News',
110+
style: TextStyle(
111+
fontSize: 48.sp,
112+
),
113+
),
105114
),
106-
),
107-
),
108-
GestureDetector(
109-
onTap: () {
110-
Navigator.push(
111-
context,
112-
MaterialPageRoute(builder: (context) => SearchPage()),
113-
);
114-
},
115-
child: Hero(
116-
tag: 'iconSearch',
117-
child: Icon(Icons.search),
118-
),
115+
GestureDetector(
116+
onTap: () {
117+
Navigator.push(
118+
context,
119+
MaterialPageRoute(builder: (context) => SearchPage()),
120+
);
121+
},
122+
child: Hero(
123+
tag: 'iconSearch',
124+
child: Icon(
125+
Icons.search,
126+
size: 64.w,
127+
),
128+
),
129+
),
130+
SizedBox(width: 48.w),
131+
GestureDetector(
132+
onTap: () {
133+
Navigator.push(
134+
context,
135+
MaterialPageRoute(
136+
builder: (context) => SettingsPage(),
137+
),
138+
);
139+
},
140+
child: Icon(
141+
Icons.settings,
142+
size: 64.w,
143+
),
144+
),
145+
],
119146
),
120-
],
121-
),
122-
),
123-
WidgetDateToday(),
124-
SizedBox(height: 24.h),
125-
WidgetCategoryNews(listCategories: listCategories),
126-
SizedBox(height: 24.h),
127-
Expanded(
128-
child: Platform.isIOS ? _buildWidgetContentNewsIOS() : _buildWidgetContentNewsAndroid(),
147+
),
148+
WidgetDateToday(),
149+
SizedBox(height: 24.h),
150+
WidgetCategoryNews(
151+
listCategories: listCategories, indexDefaultSelected: indexCategorySelected),
152+
SizedBox(height: 24.h),
153+
Expanded(
154+
child: Platform.isIOS ? _buildWidgetContentNewsIOS() : _buildWidgetContentNewsAndroid(),
155+
),
156+
],
129157
),
130-
],
158+
),
131159
),
132-
),
133-
),
134-
],
160+
],
161+
);
162+
},
135163
),
136164
),
137165
),
@@ -404,8 +432,12 @@ class _HomePageState extends State<HomePage> {
404432

405433
class WidgetCategoryNews extends StatefulWidget {
406434
final List<CategoryNewsModel> listCategories;
435+
final int indexDefaultSelected;
407436

408-
WidgetCategoryNews({@required this.listCategories});
437+
WidgetCategoryNews({
438+
@required this.listCategories,
439+
@required this.indexDefaultSelected,
440+
});
409441

410442
@override
411443
_WidgetCategoryNewsState createState() => _WidgetCategoryNewsState();
@@ -416,7 +448,7 @@ class _WidgetCategoryNewsState extends State<WidgetCategoryNews> {
416448

417449
@override
418450
void initState() {
419-
indexCategorySelected = 0;
451+
indexCategorySelected = widget.indexDefaultSelected;
420452
super.initState();
421453
}
422454

@@ -439,12 +471,11 @@ class _WidgetCategoryNewsState extends State<WidgetCategoryNews> {
439471
if (indexCategorySelected == index) {
440472
return;
441473
}
442-
setState(() {
443-
indexCategorySelected = index;
444-
});
474+
setState(() => indexCategorySelected = index);
445475
var topHeadlinesNewsBloc = BlocProvider.of<TopHeadlinesNewsBloc>(context);
446-
topHeadlinesNewsBloc
447-
.add(ChangeCategoryTopHeadlinesNewsEvent(indexCategorySelected: indexCategorySelected));
476+
topHeadlinesNewsBloc.add(
477+
ChangeCategoryTopHeadlinesNewsEvent(indexCategorySelected: index),
478+
);
448479
},
449480
child: Container(
450481
child: AnimatedContainer(

lib/feature/presentation/page/search/search_page.dart

+4-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class _SearchPageState extends State<SearchPage> {
4242
@override
4343
Widget build(BuildContext context) {
4444
ScreenUtil.init(context);
45+
var theme = Theme.of(context);
46+
var isDarkTheme = theme.brightness == Brightness.dark;
4547
return Scaffold(
4648
body: BlocProvider<TopHeadlinesNewsBloc>(
4749
create: (context) => topHeadlinesNewsBloc,
@@ -50,11 +52,11 @@ class _SearchPageState extends State<SearchPage> {
5052
Container(
5153
width: double.infinity,
5254
height: double.infinity,
53-
color: Color(0xFFEFF5F5),
55+
color: isDarkTheme ? null : Color(0xFFEFF5F5),
5456
),
5557
SafeArea(
5658
child: Container(
57-
color: Color(0xFFEFF5F5),
59+
color: isDarkTheme ? null : Color(0xFFEFF5F5),
5860
width: double.infinity,
5961
padding: EdgeInsets.symmetric(
6062
vertical: 24.h,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_screenutil/flutter_screenutil.dart';
3+
import 'package:hive/hive.dart';
4+
import 'package:hive_flutter/hive_flutter.dart';
5+
6+
class SettingsPage extends StatefulWidget {
7+
@override
8+
_SettingsPageState createState() => _SettingsPageState();
9+
}
10+
11+
class _SettingsPageState extends State<SettingsPage> {
12+
@override
13+
Widget build(BuildContext context) {
14+
ScreenUtil.init(context);
15+
return Scaffold(
16+
appBar: WidgetAppBar(),
17+
body: Container(
18+
width: double.infinity,
19+
padding: EdgeInsets.all(48.w),
20+
child: Column(
21+
crossAxisAlignment: CrossAxisAlignment.start,
22+
children: <Widget>[
23+
Text(
24+
'Interface',
25+
style: TextStyle(
26+
fontSize: 48.sp,
27+
fontWeight: FontWeight.bold,
28+
),
29+
),
30+
Row(
31+
children: <Widget>[
32+
Expanded(
33+
child: Column(
34+
crossAxisAlignment: CrossAxisAlignment.start,
35+
children: <Widget>[
36+
Text(
37+
'Use dark mode',
38+
style: TextStyle(
39+
fontSize: 42.sp,
40+
),
41+
),
42+
Text(
43+
'Get that whiteness out',
44+
style: TextStyle(
45+
fontSize: 36.sp,
46+
color: Colors.grey,
47+
),
48+
),
49+
],
50+
),
51+
),
52+
ValueListenableBuilder(
53+
valueListenable: Hive.box('settings').listenable(),
54+
builder: (context, box, widget) {
55+
var isDarkMode = box.get('darkMode') ?? false;
56+
return Switch(
57+
value: isDarkMode,
58+
onChanged: (value) async {
59+
isDarkMode = value;
60+
await box.put('darkMode', isDarkMode);
61+
},
62+
);
63+
},
64+
),
65+
],
66+
),
67+
],
68+
),
69+
),
70+
);
71+
}
72+
}
73+
74+
class WidgetAppBar extends PreferredSize {
75+
@override
76+
Widget build(BuildContext context) {
77+
return ValueListenableBuilder(
78+
valueListenable: Hive.box('settings').listenable(),
79+
builder: (context, box, widget) {
80+
var isDarkMode = box.get('darkMode') ?? false;
81+
return isDarkMode
82+
? AppBar(
83+
title: Text('Settings'),
84+
)
85+
: AppBar(
86+
title: Text('Settings'),
87+
);
88+
},
89+
);
90+
}
91+
92+
@override
93+
Size get preferredSize {
94+
return Size.fromHeight(kToolbarHeight);
95+
}
96+
}

lib/injection_container.dart

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ import 'package:flutter_news_app/feature/data/repository/news/news_repository_im
99
import 'package:flutter_news_app/feature/domain/repository/news/news_repository.dart';
1010
import 'package:flutter_news_app/feature/domain/usecase/gettopheadlinesnews/get_top_headlines_news.dart';
1111
import 'package:flutter_news_app/feature/domain/usecase/searchtopheadlinesnews/search_top_headlines_news.dart';
12+
import 'package:flutter_news_app/feature/presentation/bloc/topheadlinesnews/bloc.dart';
1213
import 'package:get_it/get_it.dart';
1314

14-
import 'feature/presentation/bloc/topheadlinesnews/bloc.dart';
15-
1615
final sl = GetIt.instance;
1716

1817
Future<void> init() async {

lib/main_development.dart

+4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import 'package:flutter_news_app/app.dart';
33
import 'package:flutter_news_app/config/base_url_config.dart';
44
import 'package:flutter_news_app/config/flavor_config.dart';
55
import 'package:flutter_news_app/injection_container.dart' as di;
6+
import 'package:hive/hive.dart';
7+
import 'package:hive_flutter/hive_flutter.dart';
68

79
void main() async {
810
WidgetsFlutterBinding.ensureInitialized();
11+
await Hive.initFlutter();
12+
await Hive.openBox('settings');
913
FlavorConfig(
1014
flavor: Flavor.DEVELOPMENT,
1115
values: FlavorValues(baseUrl: BaseUrlConfig().baseUrlDevelopment),

lib/main_production.dart

+4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import 'package:flutter_news_app/app.dart';
33
import 'package:flutter_news_app/config/base_url_config.dart';
44
import 'package:flutter_news_app/config/flavor_config.dart';
55
import 'package:flutter_news_app/injection_container.dart' as di;
6+
import 'package:hive/hive.dart';
7+
import 'package:hive_flutter/hive_flutter.dart';
68

79
void main() async {
810
WidgetsFlutterBinding.ensureInitialized();
11+
await Hive.initFlutter();
12+
await Hive.openBox('settings');
913
FlavorConfig(
1014
flavor: Flavor.PRODUCTION,
1115
values: FlavorValues(baseUrl: BaseUrlConfig().baseUrlProduction),

0 commit comments

Comments
 (0)