@@ -4,10 +4,11 @@ import 'package:flutter/material.dart';
4
4
import 'package:flutter_board/model/article.dart' ;
5
5
import 'package:flutter_board/service/article_bloc_provider.dart' ;
6
6
import 'package:flutter_board/ui/sources_page.dart' ;
7
+ import 'package:url_launcher/url_launcher.dart' ;
7
8
8
9
typedef void FlipBack ({bool backToTop});
9
10
10
- class ArticlePage extends StatelessWidget {
11
+ class ArticlePage extends StatefulWidget {
11
12
final Article article;
12
13
13
14
final FlipBack flipBack;
@@ -16,6 +17,13 @@ class ArticlePage extends StatelessWidget {
16
17
17
18
ArticlePage (this .article, this .flipBack, this .height);
18
19
20
+ @override
21
+ ArticlePageState createState () {
22
+ return new ArticlePageState ();
23
+ }
24
+ }
25
+
26
+ class ArticlePageState extends State <ArticlePage > {
19
27
Future <Null > _selectSources (BuildContext context) async {
20
28
String result = await Navigator .push (
21
29
context,
@@ -27,6 +35,16 @@ class ArticlePage extends StatelessWidget {
27
35
}
28
36
}
29
37
38
+ _launchURL () async {
39
+ String url = widget.article.url;
40
+ if (await canLaunch (url)) {
41
+ await launch (url);
42
+ } else {
43
+ Scaffold .of (context)
44
+ .showSnackBar (SnackBar (content: Text ("Could not launch $url " )));
45
+ }
46
+ }
47
+
30
48
@override
31
49
Widget build (BuildContext context) {
32
50
var screenWidth = MediaQuery .of (context).size.width;
@@ -57,138 +75,141 @@ class ArticlePage extends StatelessWidget {
57
75
58
76
return Container (
59
77
color: Colors .white,
60
- height: height,
78
+ height: widget. height,
61
79
width: MediaQuery .of (context).size.width,
62
- child: Column (
63
- children: [
64
- AppBar (
65
- leading: flipBack != null
66
- ? new IconButton (
67
- icon: _getBackIcon (Theme .of (context).platform),
68
- color: Colors .black87,
69
- onPressed: flipBack,
70
- )
71
- : Padding (
72
- padding: const EdgeInsets .all (10.0 ),
73
- child: Image .asset (
74
- 'assets/images/flutboard_logo.png' ,
75
- ),
80
+ child: Scaffold (
81
+ appBar: AppBar (
82
+ leading: widget.flipBack != null
83
+ ? new IconButton (
84
+ icon: _getBackIcon (Theme .of (context).platform),
85
+ color: Colors .black87,
86
+ onPressed: widget.flipBack,
87
+ )
88
+ : Padding (
89
+ padding: const EdgeInsets .all (10.0 ),
90
+ child: Image .asset (
91
+ 'assets/images/flutboard_logo.png' ,
76
92
),
77
- title: Text (
78
- article.source,
79
- style: TextStyle (color: Colors .black87),
80
- ),
81
- elevation: 0.0 ,
82
- centerTitle: true ,
83
- backgroundColor: Colors .white,
84
- actions: < Widget > [
85
- flipBack == null
86
- ? IconButton (
87
- icon: new Icon (Icons .refresh),
88
- //color: Colors.black87,
89
- onPressed: () => ArticleBlocProvider
90
- .of (context)
91
- .getArticles (refresh: true ),
92
- )
93
- : Container (),
94
- PopupMenuButton <String >(
95
- itemBuilder: (BuildContext context) {
96
- return < PopupMenuEntry <String >> [
97
- flipBack == null
98
- ? PopupMenuItem <String >(
99
- value: 'sources' ,
100
- child: Text ('Select Sources' ),
101
- )
102
- : PopupMenuItem <String >(
103
- value: 'back' ,
104
- child: Text ('Back to Top' ),
105
- ),
106
- PopupMenuItem <String >(
107
- value: 'about' ,
108
- child: Text ('About' ),
109
- ),
110
- ];
111
- },
112
- onSelected: (String value) {
113
- if (value == 'back' ) {
114
- flipBack (backToTop: true );
115
- }
116
- if (value == 'sources' ) {
117
- _selectSources (context);
118
- }
119
- },
120
- ),
121
- ],
93
+ ),
94
+ title: Text (
95
+ widget.article.source,
96
+ style: TextStyle (color: Colors .black87),
122
97
),
123
- SizedBox (
124
- width: screenWidth,
125
- //height: screenWidth / 2,
126
- child: article.urlToImage != null
127
- ? FadeInImage .assetNetwork (
128
- placeholder: 'assets/images/1x1_transparent.png' ,
129
- image: article.urlToImage,
130
- width: screenWidth,
131
- height: screenWidth / 2 ,
132
- fadeInDuration: const Duration (milliseconds: 300 ),
133
- fit: BoxFit .cover,
98
+ elevation: 0.0 ,
99
+ centerTitle: true ,
100
+ actions: < Widget > [
101
+ widget.flipBack == null
102
+ ? IconButton (
103
+ icon: new Icon (Icons .refresh),
104
+ //color: Colors.black87,
105
+ onPressed: () => ArticleBlocProvider .of (context)
106
+ .getArticles (refresh: true ),
134
107
)
135
108
: Container (),
136
- ),
137
- Padding (
138
- padding: EdgeInsets .all (10.0 ),
139
- child: Text (
140
- article.title,
141
- style: TextStyle (fontWeight: FontWeight .bold, fontSize: 28.0 ),
142
- ),
143
- ),
144
- Padding (
145
- padding: EdgeInsets .all (10.0 ),
146
- child: Row (
147
- children: < Widget > [
148
- Text (
149
- article.author ?? article.source,
150
- style: TextStyle (
151
- fontSize: 15.0 ,
152
- fontWeight: FontWeight .bold,
153
- color: Colors .grey),
154
- ),
155
- ],
156
- ),
157
- ),
158
- Expanded (
159
- child: Padding (
160
- padding: EdgeInsets .all (10.0 ),
161
- child: new LayoutBuilder (
162
- builder: (BuildContext context, BoxConstraints constraints) {
163
- return new Text (
164
- article.description,
165
- overflow: TextOverflow .ellipsis,
166
- style: TextStyle (fontSize: 18.0 , color: Colors .black54),
167
- maxLines: (constraints.maxHeight / 18.0 ).floor () - 1 ,
168
- );
169
- }),
109
+ PopupMenuButton <String >(
110
+ itemBuilder: (BuildContext context) {
111
+ return < PopupMenuEntry <String >> [
112
+ widget.flipBack == null
113
+ ? PopupMenuItem <String >(
114
+ value: 'sources' ,
115
+ child: Text ('Select Sources' ),
116
+ )
117
+ : PopupMenuItem <String >(
118
+ value: 'back' ,
119
+ child: Text ('Back to Top' ),
120
+ ),
121
+ PopupMenuItem <String >(
122
+ value: 'about' ,
123
+ child: Text ('About' ),
124
+ ),
125
+ ];
126
+ },
127
+ onSelected: (String value) {
128
+ if (value == 'back' ) {
129
+ widget.flipBack (backToTop: true );
130
+ }
131
+ if (value == 'sources' ) {
132
+ _selectSources (context);
133
+ }
134
+ },
170
135
),
171
- ),
172
- Row (
173
- mainAxisSize: MainAxisSize .max,
174
- crossAxisAlignment: CrossAxisAlignment .end,
136
+ ],
137
+ ),
138
+ body: GestureDetector (
139
+ onTap: _launchURL,
140
+ child: Column (
175
141
children: < Widget > [
176
- Expanded (child: Container ()),
177
- IconButton (
178
- icon: Icon (Icons .favorite_border),
179
- onPressed: null ,
142
+ SizedBox (
143
+ width: screenWidth,
144
+ //height: screenWidth / 2,
145
+ child: widget.article.urlToImage != null
146
+ ? FadeInImage .assetNetwork (
147
+ placeholder: 'assets/images/1x1_transparent.png' ,
148
+ image: widget.article.urlToImage,
149
+ width: screenWidth,
150
+ height: screenWidth / 2 ,
151
+ fadeInDuration: const Duration (milliseconds: 300 ),
152
+ fit: BoxFit .cover,
153
+ )
154
+ : Container (),
180
155
),
181
- IconButton (
182
- icon: Icon (Icons .add),
183
- onPressed: null ,
156
+ Padding (
157
+ padding: EdgeInsets .all (10.0 ),
158
+ child: Text (
159
+ widget.article.title,
160
+ style: TextStyle (fontWeight: FontWeight .bold, fontSize: 28.0 ),
161
+ ),
184
162
),
185
- IconButton (
186
- icon: _getMenuIcon (Theme .of (context).platform),
187
- onPressed: null ,
163
+ Padding (
164
+ padding: EdgeInsets .all (10.0 ),
165
+ child: Row (
166
+ children: < Widget > [
167
+ Text (
168
+ widget.article.author ?? widget.article.source,
169
+ style: TextStyle (
170
+ fontSize: 15.0 ,
171
+ fontWeight: FontWeight .bold,
172
+ color: Colors .grey),
173
+ ),
174
+ ],
175
+ ),
176
+ ),
177
+ Expanded (
178
+ child: Padding (
179
+ padding: EdgeInsets .all (10.0 ),
180
+ child: new LayoutBuilder (builder:
181
+ (BuildContext context, BoxConstraints constraints) {
182
+ return new Text (
183
+ widget.article.description,
184
+ overflow: TextOverflow .ellipsis,
185
+ style: TextStyle (fontSize: 18.0 , color: Colors .black54),
186
+ maxLines: (constraints.maxHeight / 18.0 ).floor () - 1 ,
187
+ );
188
+ }),
189
+ ),
190
+ ),
191
+ Row (
192
+ mainAxisSize: MainAxisSize .max,
193
+ crossAxisAlignment: CrossAxisAlignment .end,
194
+ children: < Widget > [
195
+ Expanded (child: Container ()),
196
+ IconButton (
197
+ icon: Icon (Icons .favorite_border),
198
+ onPressed: null ,
199
+ ),
200
+ IconButton (
201
+ icon: Icon (Icons .add),
202
+ onPressed: null ,
203
+ ),
204
+ IconButton (
205
+ icon: _getMenuIcon (Theme .of (context).platform),
206
+ onPressed: null ,
207
+ ),
208
+ ],
188
209
),
189
210
],
190
211
),
191
- ] ,
212
+ ) ,
192
213
),
193
214
);
194
215
}
0 commit comments