Skip to content

Commit b40bc00

Browse files
committed
Add a Scaffold in article page to allow launching url from its body.
This has required to switch to master channel because rotating the article Scaffolds didn't work in the Transform widgets.
1 parent c08e94f commit b40bc00

File tree

6 files changed

+209
-155
lines changed

6 files changed

+209
-155
lines changed

ios/Podfile.lock

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
PODS:
2+
- Flutter (1.0.0)
3+
- shared_preferences (0.0.1):
4+
- Flutter
5+
- url_launcher (0.0.1):
6+
- Flutter
7+
8+
DEPENDENCIES:
9+
- Flutter (from `.symlinks/flutter/ios`)
10+
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
11+
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
12+
13+
EXTERNAL SOURCES:
14+
Flutter:
15+
:path: ".symlinks/flutter/ios"
16+
shared_preferences:
17+
:path: ".symlinks/plugins/shared_preferences/ios"
18+
url_launcher:
19+
:path: ".symlinks/plugins/url_launcher/ios"
20+
21+
SPEC CHECKSUMS:
22+
Flutter: 9d0fac939486c9aba2809b7982dfdbb47a7b0296
23+
shared_preferences: 5a1d487c427ee18fcd3ea1f2a131569481834b53
24+
url_launcher: 92b89c1029a0373879933c21642958c874539095
25+
26+
PODFILE CHECKSUM: 1e5af4103afd21ca5ead147d7b81d06f494f51a2
27+
28+
COCOAPODS: 1.5.3

lib/main.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class HomePage extends StatelessWidget {
4343
MediaQuery.of(context).padding.bottom;
4444

4545
return SafeArea(
46+
// This Scaffold is used to display the FlipPane SnackBar. Later,
47+
// each article page will have its own Scaffold
4648
child: Scaffold(
4749
body: FlipPanel(
4850
itemStream: ArticleBlocProvider.of(context).articles,

lib/ui/article_page.dart

Lines changed: 142 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import 'package:flutter/material.dart';
44
import 'package:flutter_board/model/article.dart';
55
import 'package:flutter_board/service/article_bloc_provider.dart';
66
import 'package:flutter_board/ui/sources_page.dart';
7+
import 'package:url_launcher/url_launcher.dart';
78

89
typedef void FlipBack({bool backToTop});
910

10-
class ArticlePage extends StatelessWidget {
11+
class ArticlePage extends StatefulWidget {
1112
final Article article;
1213

1314
final FlipBack flipBack;
@@ -16,6 +17,13 @@ class ArticlePage extends StatelessWidget {
1617

1718
ArticlePage(this.article, this.flipBack, this.height);
1819

20+
@override
21+
ArticlePageState createState() {
22+
return new ArticlePageState();
23+
}
24+
}
25+
26+
class ArticlePageState extends State<ArticlePage> {
1927
Future<Null> _selectSources(BuildContext context) async {
2028
String result = await Navigator.push(
2129
context,
@@ -27,6 +35,16 @@ class ArticlePage extends StatelessWidget {
2735
}
2836
}
2937

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+
3048
@override
3149
Widget build(BuildContext context) {
3250
var screenWidth = MediaQuery.of(context).size.width;
@@ -57,138 +75,141 @@ class ArticlePage extends StatelessWidget {
5775

5876
return Container(
5977
color: Colors.white,
60-
height: height,
78+
height: widget.height,
6179
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',
7692
),
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),
12297
),
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),
134107
)
135108
: 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+
},
170135
),
171-
),
172-
Row(
173-
mainAxisSize: MainAxisSize.max,
174-
crossAxisAlignment: CrossAxisAlignment.end,
136+
],
137+
),
138+
body: GestureDetector(
139+
onTap: _launchURL,
140+
child: Column(
175141
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(),
180155
),
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+
),
184162
),
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+
],
188209
),
189210
],
190211
),
191-
],
212+
),
192213
),
193214
);
194215
}

0 commit comments

Comments
 (0)